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 &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() 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 &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
256