| /* | |
| * 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 |