blob: 3fa6d81079bec2e8b376fc5ab2d49d746f9d92ac [file] [log] [blame]
/*
* 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.
*/
#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 &regs) const;
void setDebugRegisters(const struct kvm_debugregs &regs);
void getXCRs(struct kvm_xcrs &regs) const;
void setXCRs(const struct kvm_xcrs &regs);
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 &regs,
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