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