Since the last round of fixes a few new issues have snuck in. We should consider switching the regression runs to clang.
256 lines
7.9 KiB
C++
256 lines
7.9 KiB
C++
/*
|
|
* Copyright (c) 2013 Andreas Sandberg
|
|
* All rights reserved
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Authors: Andreas Sandberg
|
|
*/
|
|
|
|
#ifndef __CPU_KVM_X86_CPU_HH__
|
|
#define __CPU_KVM_X86_CPU_HH__
|
|
|
|
#include "cpu/kvm/base.hh"
|
|
#include "cpu/kvm/vm.hh"
|
|
#include "params/X86KvmCPU.hh"
|
|
|
|
/**
|
|
* x86 implementation of a KVM-based hardware virtualized CPU.
|
|
*/
|
|
class X86KvmCPU : public BaseKvmCPU
|
|
{
|
|
public:
|
|
X86KvmCPU(X86KvmCPUParams *params);
|
|
virtual ~X86KvmCPU();
|
|
|
|
void startup() override;
|
|
|
|
/** @{ */
|
|
void dump() const override;
|
|
void dumpFpuRegs() const;
|
|
void dumpIntRegs() const;
|
|
void dumpSpecRegs() const;
|
|
void dumpDebugRegs() const;
|
|
void dumpXCRs() const;
|
|
void dumpXSave() const;
|
|
void dumpVCpuEvents() const;
|
|
void dumpMSRs() const;
|
|
/** @} */
|
|
|
|
protected:
|
|
typedef std::vector<struct kvm_msr_entry> KvmMSRVector;
|
|
|
|
Tick kvmRun(Tick ticks) override;
|
|
|
|
/**
|
|
* Run the virtual CPU until draining completes.
|
|
*
|
|
* In addition to the base functionality provided by
|
|
* BaseKvmCPU::kvmRunDrain(), this method handles x86-specific
|
|
* cases where there are pending interrupt events in the virtual
|
|
* CPU. These are handled by requesting an interrupt window if
|
|
* interrupts are pending (causing the vCPU to execute until
|
|
* interrupts can be delivered again).
|
|
*
|
|
* @see BaseKvmCPU::kvmRunDrain()
|
|
* @see archIsDrained()
|
|
*
|
|
* @return Number of ticks executed
|
|
*/
|
|
Tick kvmRunDrain() override;
|
|
|
|
/** Wrapper that synchronizes state in kvm_run */
|
|
Tick kvmRunWrapper(Tick ticks);
|
|
|
|
uint64_t getHostCycles() const override;
|
|
|
|
/**
|
|
* Methods to access CPUID information using the extended
|
|
* API. Only available if Kvm::capExtendedCPUID() is true.
|
|
*
|
|
* @{
|
|
*/
|
|
void setCPUID(const struct kvm_cpuid2 &cpuid);
|
|
void setCPUID(const Kvm::CPUIDVector &cpuid);
|
|
/** @} */
|
|
|
|
/**
|
|
* Methods to access MSRs in the guest.
|
|
*
|
|
* @{
|
|
*/
|
|
void setMSRs(const struct kvm_msrs &msrs);
|
|
void setMSRs(const KvmMSRVector &msrs);
|
|
void getMSRs(struct kvm_msrs &msrs) const;
|
|
void setMSR(uint32_t index, uint64_t value);
|
|
uint64_t getMSR(uint32_t index) const;
|
|
/** @} */
|
|
|
|
/**
|
|
* Get a list of MSRs supported by both gem5 and KVM.
|
|
*
|
|
* @note This method uses an internal cache and only generates the
|
|
* MSR list once.
|
|
*
|
|
* @return reference to a list of msr indices
|
|
*/
|
|
const Kvm::MSRIndexVector &getMsrIntersection() const;
|
|
|
|
/**
|
|
* Wrappers around KVM's state transfer methods.
|
|
*
|
|
* @{
|
|
*/
|
|
void getDebugRegisters(struct kvm_debugregs ®s) const;
|
|
void setDebugRegisters(const struct kvm_debugregs ®s);
|
|
void getXCRs(struct kvm_xcrs ®s) const;
|
|
void setXCRs(const struct kvm_xcrs ®s);
|
|
void getXSave(struct kvm_xsave &xsave) const;
|
|
void setXSave(const struct kvm_xsave &xsave);
|
|
void getVCpuEvents(struct kvm_vcpu_events &events) const;
|
|
void setVCpuEvents(const struct kvm_vcpu_events &events);
|
|
/** @} */
|
|
|
|
void updateKvmState() override;
|
|
void updateThreadContext() override;
|
|
|
|
/**
|
|
* Inject pending interrupts from gem5 into the virtual CPU.
|
|
*/
|
|
void deliverInterrupts();
|
|
|
|
/**
|
|
* Handle x86 legacy IO (in/out)
|
|
*/
|
|
Tick handleKvmExitIO() override;
|
|
|
|
Tick handleKvmExitIRQWindowOpen() override;
|
|
|
|
/**
|
|
* Check if there are pending events in the vCPU that prevents it
|
|
* from being drained.
|
|
*
|
|
* There are cases after interrupt injection where the interrupt
|
|
* is still pending in the guest. This method detects such cases
|
|
* and requests additional draining.
|
|
*
|
|
* @return False if there are pending events in the guest, True
|
|
* otherwise.
|
|
*/
|
|
bool archIsDrained() const override;
|
|
|
|
private:
|
|
/**
|
|
* Support routines to update the state of the KVM CPU from gem5's
|
|
* state representation.
|
|
*
|
|
* @{
|
|
*/
|
|
/** Update integer registers */
|
|
void updateKvmStateRegs();
|
|
/** Update control registers (CRx, segments, etc.) */
|
|
void updateKvmStateSRegs();
|
|
/**
|
|
* Update FPU and SIMD registers
|
|
*
|
|
* This method uses the appropriate (depending on availability and
|
|
* user configuration) kernel API by calling
|
|
* updateKvmStateFPULegacy() or updateKvmStateFPUXSave().
|
|
*
|
|
* @see updateKvmStateFPULegacy()
|
|
* @see updateKvmStateFPUXSave()
|
|
*/
|
|
void updateKvmStateFPU();
|
|
/**
|
|
* Update FPU and SIMD registers using the legacy API
|
|
*
|
|
* @note This method should normally only be called by
|
|
* updateKvmStateFPU() which automatically chooses between
|
|
* available APIs.
|
|
*/
|
|
void updateKvmStateFPULegacy();
|
|
/**
|
|
* Update FPU and SIMD registers using the XSave API
|
|
*
|
|
* @note This method should normally only be called by
|
|
* updateKvmStateFPU() which automatically chooses between
|
|
* available APIs.
|
|
*/
|
|
void updateKvmStateFPUXSave();
|
|
/** Update MSR registers */
|
|
void updateKvmStateMSRs();
|
|
/** @} */
|
|
|
|
/**
|
|
* Support routines to update the state of gem5's thread context from
|
|
* KVM's state representation.
|
|
*
|
|
* @{
|
|
*/
|
|
/** Update integer registers */
|
|
void updateThreadContextRegs(const struct kvm_regs ®s,
|
|
const struct kvm_sregs &sregs);
|
|
/** Update control registers (CRx, segments, etc.) */
|
|
void updateThreadContextSRegs(const struct kvm_sregs &sregs);
|
|
/** Update FPU and SIMD registers using the legacy API */
|
|
void updateThreadContextFPU(const struct kvm_fpu &fpu);
|
|
/** Update FPU and SIMD registers using the XSave API */
|
|
void updateThreadContextXSave(const struct kvm_xsave &kxsave);
|
|
/** Update MSR registers */
|
|
void updateThreadContextMSRs();
|
|
/** @} */
|
|
|
|
/** Transfer gem5's CPUID values into the virtual CPU. */
|
|
void updateCPUID();
|
|
|
|
/**
|
|
* Handle a 32-bit IO access that should be mapped to a MiscReg.
|
|
*
|
|
* @note This method can only be called on when handling IO after
|
|
* a KVM_EXIT_IO.
|
|
*
|
|
* @param miscreg Register to map the current IO access to.
|
|
*/
|
|
void handleIOMiscReg32(int miscreg);
|
|
|
|
/** Cached intersection of supported MSRs */
|
|
mutable Kvm::MSRIndexVector cachedMsrIntersection;
|
|
|
|
/** @{ */
|
|
/** Kvm::capDebugRegs() available? */
|
|
bool haveDebugRegs;
|
|
/** Kvm::capXSave() available? */
|
|
bool haveXSave;
|
|
/**
|
|
* Should the XSave interface be used to sync the FPU and SIMD
|
|
* registers?
|
|
*/
|
|
bool useXSave;
|
|
/** Kvm::capXCRs() available? */
|
|
bool haveXCRs;
|
|
/** @} */
|
|
};
|
|
|
|
#endif
|