1/* 2 * Copyright (c) 2013 Andreas Sandberg 3 * All rights reserved 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Andreas Sandberg 29 */ 30 31#ifndef __CPU_KVM_X86_CPU_HH__ 32#define __CPU_KVM_X86_CPU_HH__ 33 34#include "cpu/kvm/base.hh" 35#include "cpu/kvm/vm.hh" 36#include "params/X86KvmCPU.hh" 37 38/** 39 * x86 implementation of a KVM-based hardware virtualized CPU. 40 */ 41class X86KvmCPU : public BaseKvmCPU 42{ 43 public: 44 X86KvmCPU(X86KvmCPUParams *params); 45 virtual ~X86KvmCPU(); 46 47 void startup() override; 48 49 /** @{ */ 50 void dump() const override; 51 void dumpFpuRegs() const; 52 void dumpIntRegs() const; 53 void dumpSpecRegs() const; 54 void dumpDebugRegs() const; 55 void dumpXCRs() const; 56 void dumpXSave() const; 57 void dumpVCpuEvents() const; 58 void dumpMSRs() const; 59 /** @} */ 60 61 protected: 62 typedef std::vector<struct kvm_msr_entry> KvmMSRVector; 63 64 Tick kvmRun(Tick ticks) override; 65 66 /** 67 * Run the virtual CPU until draining completes. 68 * 69 * In addition to the base functionality provided by 70 * BaseKvmCPU::kvmRunDrain(), this method handles x86-specific 71 * cases where there are pending interrupt events in the virtual 72 * CPU. These are handled by requesting an interrupt window if 73 * interrupts are pending (causing the vCPU to execute until 74 * interrupts can be delivered again). 75 * 76 * @see BaseKvmCPU::kvmRunDrain() 77 * @see archIsDrained() 78 * 79 * @return Number of ticks executed 80 */ 81 Tick kvmRunDrain() override; 82 83 /** Wrapper that synchronizes state in kvm_run */ 84 Tick kvmRunWrapper(Tick ticks); 85 86 uint64_t getHostCycles() const override; 87 88 /** 89 * Methods to access CPUID information using the extended 90 * API. Only available if Kvm::capExtendedCPUID() is true. 91 * 92 * @{ 93 */ 94 void setCPUID(const struct kvm_cpuid2 &cpuid); 95 void setCPUID(const Kvm::CPUIDVector &cpuid); 96 /** @} */ 97 98 /** 99 * Methods to access MSRs in the guest. 100 * 101 * @{ 102 */ 103 void setMSRs(const struct kvm_msrs &msrs); 104 void setMSRs(const KvmMSRVector &msrs); 105 void getMSRs(struct kvm_msrs &msrs) const; 106 void setMSR(uint32_t index, uint64_t value); 107 uint64_t getMSR(uint32_t index) const; 108 /** @} */ 109 110 /** 111 * Get a list of MSRs supported by both gem5 and KVM. 112 * 113 * @note This method uses an internal cache and only generates the 114 * MSR list once. 115 * 116 * @return reference to a list of msr indices 117 */ 118 const Kvm::MSRIndexVector &getMsrIntersection() const; 119 120 /** 121 * Wrappers around KVM's state transfer methods. 122 * 123 * @{ 124 */ 125 void getDebugRegisters(struct kvm_debugregs ®s) const; 126 void setDebugRegisters(const struct kvm_debugregs ®s); 127 void getXCRs(struct kvm_xcrs ®s) const; 128 void setXCRs(const struct kvm_xcrs ®s); 129 void getXSave(struct kvm_xsave &xsave) const; 130 void setXSave(const struct kvm_xsave &xsave); 131 void getVCpuEvents(struct kvm_vcpu_events &events) const; 132 void setVCpuEvents(const struct kvm_vcpu_events &events); 133 /** @} */ 134 135 void updateKvmState() override; 136 void updateThreadContext() override; 137 138 /** 139 * Inject pending interrupts from gem5 into the virtual CPU. 140 */ 141 void deliverInterrupts(); 142 143 /** 144 * Handle x86 legacy IO (in/out) 145 */ 146 Tick handleKvmExitIO() override; 147 148 Tick handleKvmExitIRQWindowOpen() override; 149 150 /** 151 * Check if there are pending events in the vCPU that prevents it 152 * from being drained. 153 * 154 * There are cases after interrupt injection where the interrupt 155 * is still pending in the guest. This method detects such cases 156 * and requests additional draining. 157 * 158 * @return False if there are pending events in the guest, True 159 * otherwise. 160 */ 161 bool archIsDrained() const override; 162 163 private: 164 /** 165 * Support routines to update the state of the KVM CPU from gem5's 166 * state representation. 167 * 168 * @{ 169 */ 170 /** Update integer registers */ 171 void updateKvmStateRegs(); 172 /** Update control registers (CRx, segments, etc.) */ 173 void updateKvmStateSRegs(); 174 /** 175 * Update FPU and SIMD registers 176 * 177 * This method uses the appropriate (depending on availability and 178 * user configuration) kernel API by calling 179 * updateKvmStateFPULegacy() or updateKvmStateFPUXSave(). 180 * 181 * @see updateKvmStateFPULegacy() 182 * @see updateKvmStateFPUXSave() 183 */ 184 void updateKvmStateFPU(); 185 /** 186 * Update FPU and SIMD registers using the legacy API 187 * 188 * @note This method should normally only be called by 189 * updateKvmStateFPU() which automatically chooses between 190 * available APIs. 191 */ 192 void updateKvmStateFPULegacy(); 193 /** 194 * Update FPU and SIMD registers using the XSave API 195 * 196 * @note This method should normally only be called by 197 * updateKvmStateFPU() which automatically chooses between 198 * available APIs. 199 */ 200 void updateKvmStateFPUXSave(); 201 /** Update MSR registers */ 202 void updateKvmStateMSRs(); 203 /** @} */ 204 205 /** 206 * Support routines to update the state of gem5's thread context from 207 * KVM's state representation. 208 * 209 * @{ 210 */ 211 /** Update integer registers */ 212 void updateThreadContextRegs(const struct kvm_regs ®s, 213 const struct kvm_sregs &sregs); 214 /** Update control registers (CRx, segments, etc.) */ 215 void updateThreadContextSRegs(const struct kvm_sregs &sregs); 216 /** Update FPU and SIMD registers using the legacy API */ 217 void updateThreadContextFPU(const struct kvm_fpu &fpu); 218 /** Update FPU and SIMD registers using the XSave API */ 219 void updateThreadContextXSave(const struct kvm_xsave &kxsave); 220 /** Update MSR registers */ 221 void updateThreadContextMSRs(); 222 /** @} */ 223 224 /** Transfer gem5's CPUID values into the virtual CPU. */ 225 void updateCPUID(); 226 227 /** 228 * Handle a 32-bit IO access that should be mapped to a MiscReg. 229 * 230 * @note This method can only be called on when handling IO after 231 * a KVM_EXIT_IO. 232 * 233 * @param miscreg Register to map the current IO access to. 234 */ 235 void handleIOMiscReg32(int miscreg); 236 237 /** Cached intersection of supported MSRs */ 238 mutable Kvm::MSRIndexVector cachedMsrIntersection; 239 240 /** @{ */ 241 /** Kvm::capDebugRegs() available? */ 242 bool haveDebugRegs; 243 /** Kvm::capXSave() available? */ 244 bool haveXSave; 245 /** 246 * Should the XSave interface be used to sync the FPU and SIMD 247 * registers? 248 */ 249 bool useXSave; 250 /** Kvm::capXCRs() available? */ 251 bool haveXCRs; 252 /** @} */ 253}; 254 255#endif 256