x86_cpu.hh (10653:e3fc6bc7f97e) x86_cpu.hh (10905:a6ca6831e775)
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();
48
49 /** @{ */
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();
48
49 /** @{ */
50 void dump();
50 void dump() const M5_ATTR_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);
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();
82
83 /** Wrapper that synchronizes state in kvm_run */
84 Tick kvmRunWrapper(Tick ticks);
85
86 uint64_t getHostCycles() const;
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 &regs) const;
126 void setDebugRegisters(const struct kvm_debugregs &regs);
127 void getXCRs(struct kvm_xcrs &regs) const;
128 void setXCRs(const struct kvm_xcrs &regs);
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();
136 void updateThreadContext();
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();
147
148 Tick handleKvmExitIRQWindowOpen();
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;
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 &regs,
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
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);
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();
82
83 /** Wrapper that synchronizes state in kvm_run */
84 Tick kvmRunWrapper(Tick ticks);
85
86 uint64_t getHostCycles() const;
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 &regs) const;
126 void setDebugRegisters(const struct kvm_debugregs &regs);
127 void getXCRs(struct kvm_xcrs &regs) const;
128 void setXCRs(const struct kvm_xcrs &regs);
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();
136 void updateThreadContext();
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();
147
148 Tick handleKvmExitIRQWindowOpen();
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;
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 &regs,
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