19883Sandreas@sandberg.pp.se/*
29883Sandreas@sandberg.pp.se * Copyright (c) 2013 Andreas Sandberg
39883Sandreas@sandberg.pp.se * All rights reserved
49883Sandreas@sandberg.pp.se *
59883Sandreas@sandberg.pp.se * Redistribution and use in source and binary forms, with or without
69883Sandreas@sandberg.pp.se * modification, are permitted provided that the following conditions are
79883Sandreas@sandberg.pp.se * met: redistributions of source code must retain the above copyright
89883Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer;
99883Sandreas@sandberg.pp.se * redistributions in binary form must reproduce the above copyright
109883Sandreas@sandberg.pp.se * notice, this list of conditions and the following disclaimer in the
119883Sandreas@sandberg.pp.se * documentation and/or other materials provided with the distribution;
129883Sandreas@sandberg.pp.se * neither the name of the copyright holders nor the names of its
139883Sandreas@sandberg.pp.se * contributors may be used to endorse or promote products derived from
149883Sandreas@sandberg.pp.se * this software without specific prior written permission.
159883Sandreas@sandberg.pp.se *
169883Sandreas@sandberg.pp.se * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
179883Sandreas@sandberg.pp.se * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
189883Sandreas@sandberg.pp.se * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
199883Sandreas@sandberg.pp.se * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
209883Sandreas@sandberg.pp.se * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
219883Sandreas@sandberg.pp.se * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
229883Sandreas@sandberg.pp.se * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239883Sandreas@sandberg.pp.se * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249883Sandreas@sandberg.pp.se * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259883Sandreas@sandberg.pp.se * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
269883Sandreas@sandberg.pp.se * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279883Sandreas@sandberg.pp.se *
289883Sandreas@sandberg.pp.se * Authors: Andreas Sandberg
299883Sandreas@sandberg.pp.se */
309883Sandreas@sandberg.pp.se
319883Sandreas@sandberg.pp.se#ifndef __CPU_KVM_X86_CPU_HH__
329883Sandreas@sandberg.pp.se#define __CPU_KVM_X86_CPU_HH__
339883Sandreas@sandberg.pp.se
349883Sandreas@sandberg.pp.se#include "cpu/kvm/base.hh"
359883Sandreas@sandberg.pp.se#include "cpu/kvm/vm.hh"
369883Sandreas@sandberg.pp.se#include "params/X86KvmCPU.hh"
379883Sandreas@sandberg.pp.se
389883Sandreas@sandberg.pp.se/**
399883Sandreas@sandberg.pp.se * x86 implementation of a KVM-based hardware virtualized CPU.
409883Sandreas@sandberg.pp.se */
419883Sandreas@sandberg.pp.seclass X86KvmCPU : public BaseKvmCPU
429883Sandreas@sandberg.pp.se{
439883Sandreas@sandberg.pp.se  public:
449883Sandreas@sandberg.pp.se    X86KvmCPU(X86KvmCPUParams *params);
459883Sandreas@sandberg.pp.se    virtual ~X86KvmCPU();
469883Sandreas@sandberg.pp.se
4711341Sandreas.hansson@arm.com    void startup() override;
489883Sandreas@sandberg.pp.se
499883Sandreas@sandberg.pp.se    /** @{ */
5011168Sandreas.hansson@arm.com    void dump() const override;
519883Sandreas@sandberg.pp.se    void dumpFpuRegs() const;
529883Sandreas@sandberg.pp.se    void dumpIntRegs() const;
539883Sandreas@sandberg.pp.se    void dumpSpecRegs() const;
549883Sandreas@sandberg.pp.se    void dumpDebugRegs() const;
559883Sandreas@sandberg.pp.se    void dumpXCRs() const;
569883Sandreas@sandberg.pp.se    void dumpXSave() const;
579883Sandreas@sandberg.pp.se    void dumpVCpuEvents() const;
589883Sandreas@sandberg.pp.se    void dumpMSRs() const;
599883Sandreas@sandberg.pp.se    /** @} */
609883Sandreas@sandberg.pp.se
619883Sandreas@sandberg.pp.se  protected:
629883Sandreas@sandberg.pp.se    typedef std::vector<struct kvm_msr_entry> KvmMSRVector;
639883Sandreas@sandberg.pp.se
6411341Sandreas.hansson@arm.com    Tick kvmRun(Tick ticks) override;
659883Sandreas@sandberg.pp.se
669883Sandreas@sandberg.pp.se    /**
679883Sandreas@sandberg.pp.se     * Run the virtual CPU until draining completes.
689883Sandreas@sandberg.pp.se     *
699883Sandreas@sandberg.pp.se     * In addition to the base functionality provided by
709883Sandreas@sandberg.pp.se     * BaseKvmCPU::kvmRunDrain(), this method handles x86-specific
719883Sandreas@sandberg.pp.se     * cases where there are pending interrupt events in the virtual
729883Sandreas@sandberg.pp.se     * CPU.  These are handled by requesting an interrupt window if
739883Sandreas@sandberg.pp.se     * interrupts are pending (causing the vCPU to execute until
749883Sandreas@sandberg.pp.se     * interrupts can be delivered again).
759883Sandreas@sandberg.pp.se     *
769883Sandreas@sandberg.pp.se     * @see BaseKvmCPU::kvmRunDrain()
779883Sandreas@sandberg.pp.se     * @see archIsDrained()
789883Sandreas@sandberg.pp.se     *
799883Sandreas@sandberg.pp.se     * @return Number of ticks executed
809883Sandreas@sandberg.pp.se     */
8111341Sandreas.hansson@arm.com    Tick kvmRunDrain() override;
829883Sandreas@sandberg.pp.se
839883Sandreas@sandberg.pp.se    /** Wrapper that synchronizes state in kvm_run */
849883Sandreas@sandberg.pp.se    Tick kvmRunWrapper(Tick ticks);
859883Sandreas@sandberg.pp.se
8611341Sandreas.hansson@arm.com    uint64_t getHostCycles() const override;
879883Sandreas@sandberg.pp.se
889883Sandreas@sandberg.pp.se    /**
899883Sandreas@sandberg.pp.se     * Methods to access CPUID information using the extended
909883Sandreas@sandberg.pp.se     * API. Only available if Kvm::capExtendedCPUID() is true.
919883Sandreas@sandberg.pp.se     *
929883Sandreas@sandberg.pp.se     * @{
939883Sandreas@sandberg.pp.se     */
949883Sandreas@sandberg.pp.se    void setCPUID(const struct kvm_cpuid2 &cpuid);
959883Sandreas@sandberg.pp.se    void setCPUID(const Kvm::CPUIDVector &cpuid);
969883Sandreas@sandberg.pp.se    /** @} */
979883Sandreas@sandberg.pp.se
989883Sandreas@sandberg.pp.se    /**
999883Sandreas@sandberg.pp.se     * Methods to access MSRs in the guest.
1009883Sandreas@sandberg.pp.se     *
1019883Sandreas@sandberg.pp.se     * @{
1029883Sandreas@sandberg.pp.se     */
1039883Sandreas@sandberg.pp.se    void setMSRs(const struct kvm_msrs &msrs);
1049883Sandreas@sandberg.pp.se    void setMSRs(const KvmMSRVector &msrs);
1059883Sandreas@sandberg.pp.se    void getMSRs(struct kvm_msrs &msrs) const;
1069883Sandreas@sandberg.pp.se    void setMSR(uint32_t index, uint64_t value);
1079883Sandreas@sandberg.pp.se    uint64_t getMSR(uint32_t index) const;
1089883Sandreas@sandberg.pp.se    /** @} */
1099883Sandreas@sandberg.pp.se
1109883Sandreas@sandberg.pp.se    /**
1119883Sandreas@sandberg.pp.se     * Get a list of MSRs supported by both gem5 and KVM.
1129883Sandreas@sandberg.pp.se     *
1139883Sandreas@sandberg.pp.se     * @note This method uses an internal cache and only generates the
1149883Sandreas@sandberg.pp.se     * MSR list once.
1159883Sandreas@sandberg.pp.se     *
1169883Sandreas@sandberg.pp.se     * @return reference to a list of msr indices
1179883Sandreas@sandberg.pp.se     */
1189883Sandreas@sandberg.pp.se    const Kvm::MSRIndexVector &getMsrIntersection() const;
1199883Sandreas@sandberg.pp.se
1209883Sandreas@sandberg.pp.se    /**
1219883Sandreas@sandberg.pp.se     * Wrappers around KVM's state transfer methods.
1229883Sandreas@sandberg.pp.se     *
1239883Sandreas@sandberg.pp.se     * @{
1249883Sandreas@sandberg.pp.se     */
1259883Sandreas@sandberg.pp.se    void getDebugRegisters(struct kvm_debugregs &regs) const;
1269883Sandreas@sandberg.pp.se    void setDebugRegisters(const struct kvm_debugregs &regs);
1279883Sandreas@sandberg.pp.se    void getXCRs(struct kvm_xcrs &regs) const;
1289883Sandreas@sandberg.pp.se    void setXCRs(const struct kvm_xcrs &regs);
1299883Sandreas@sandberg.pp.se    void getXSave(struct kvm_xsave &xsave) const;
1309883Sandreas@sandberg.pp.se    void setXSave(const struct kvm_xsave &xsave);
1319883Sandreas@sandberg.pp.se    void getVCpuEvents(struct kvm_vcpu_events &events) const;
1329883Sandreas@sandberg.pp.se    void setVCpuEvents(const struct kvm_vcpu_events &events);
1339883Sandreas@sandberg.pp.se    /** @} */
1349883Sandreas@sandberg.pp.se
13511341Sandreas.hansson@arm.com    void updateKvmState() override;
13611341Sandreas.hansson@arm.com    void updateThreadContext() override;
1379883Sandreas@sandberg.pp.se
1389883Sandreas@sandberg.pp.se    /**
1399883Sandreas@sandberg.pp.se     * Inject pending interrupts from gem5 into the virtual CPU.
1409883Sandreas@sandberg.pp.se     */
1419883Sandreas@sandberg.pp.se    void deliverInterrupts();
1429883Sandreas@sandberg.pp.se
1439883Sandreas@sandberg.pp.se    /**
1449883Sandreas@sandberg.pp.se     * Handle x86 legacy IO (in/out)
1459883Sandreas@sandberg.pp.se     */
14611341Sandreas.hansson@arm.com    Tick handleKvmExitIO() override;
1479883Sandreas@sandberg.pp.se
14811341Sandreas.hansson@arm.com    Tick handleKvmExitIRQWindowOpen() override;
1499883Sandreas@sandberg.pp.se
1509883Sandreas@sandberg.pp.se    /**
1519883Sandreas@sandberg.pp.se     * Check if there are pending events in the vCPU that prevents it
1529883Sandreas@sandberg.pp.se     * from being drained.
1539883Sandreas@sandberg.pp.se     *
1549883Sandreas@sandberg.pp.se     * There are cases after interrupt injection where the interrupt
1559883Sandreas@sandberg.pp.se     * is still pending in the guest. This method detects such cases
1569883Sandreas@sandberg.pp.se     * and requests additional draining.
1579883Sandreas@sandberg.pp.se     *
1589883Sandreas@sandberg.pp.se     * @return False if there are pending events in the guest, True
1599883Sandreas@sandberg.pp.se     * otherwise.
1609883Sandreas@sandberg.pp.se     */
16111341Sandreas.hansson@arm.com    bool archIsDrained() const override;
1629883Sandreas@sandberg.pp.se
1639883Sandreas@sandberg.pp.se  private:
1649883Sandreas@sandberg.pp.se    /**
1659883Sandreas@sandberg.pp.se     * Support routines to update the state of the KVM CPU from gem5's
1669883Sandreas@sandberg.pp.se     * state representation.
1679883Sandreas@sandberg.pp.se     *
1689883Sandreas@sandberg.pp.se     * @{
1699883Sandreas@sandberg.pp.se     */
1709883Sandreas@sandberg.pp.se    /** Update integer registers */
1719883Sandreas@sandberg.pp.se    void updateKvmStateRegs();
1729883Sandreas@sandberg.pp.se    /** Update control registers (CRx, segments, etc.) */
1739883Sandreas@sandberg.pp.se    void updateKvmStateSRegs();
1749890Sandreas@sandberg.pp.se    /**
1759890Sandreas@sandberg.pp.se     * Update FPU and SIMD registers
1769890Sandreas@sandberg.pp.se     *
1779890Sandreas@sandberg.pp.se     * This method uses the appropriate (depending on availability and
1789890Sandreas@sandberg.pp.se     * user configuration) kernel API by calling
1799890Sandreas@sandberg.pp.se     * updateKvmStateFPULegacy() or updateKvmStateFPUXSave().
1809890Sandreas@sandberg.pp.se     *
1819890Sandreas@sandberg.pp.se     * @see updateKvmStateFPULegacy()
1829890Sandreas@sandberg.pp.se     * @see updateKvmStateFPUXSave()
1839890Sandreas@sandberg.pp.se     */
1849883Sandreas@sandberg.pp.se    void updateKvmStateFPU();
1859890Sandreas@sandberg.pp.se    /**
1869890Sandreas@sandberg.pp.se     * Update FPU and SIMD registers using the legacy API
1879890Sandreas@sandberg.pp.se     *
1889890Sandreas@sandberg.pp.se     * @note This method should normally only be called by
1899890Sandreas@sandberg.pp.se     * updateKvmStateFPU() which automatically chooses between
1909890Sandreas@sandberg.pp.se     * available APIs.
1919890Sandreas@sandberg.pp.se     */
1929890Sandreas@sandberg.pp.se    void updateKvmStateFPULegacy();
1939890Sandreas@sandberg.pp.se    /**
1949890Sandreas@sandberg.pp.se     * Update FPU and SIMD registers using the XSave API
1959890Sandreas@sandberg.pp.se     *
1969890Sandreas@sandberg.pp.se     * @note This method should normally only be called by
1979890Sandreas@sandberg.pp.se     * updateKvmStateFPU() which automatically chooses between
1989890Sandreas@sandberg.pp.se     * available APIs.
1999890Sandreas@sandberg.pp.se     */
2009890Sandreas@sandberg.pp.se    void updateKvmStateFPUXSave();
2019883Sandreas@sandberg.pp.se    /** Update MSR registers */
2029883Sandreas@sandberg.pp.se    void updateKvmStateMSRs();
2039883Sandreas@sandberg.pp.se    /** @} */
2049883Sandreas@sandberg.pp.se
2059883Sandreas@sandberg.pp.se    /**
2069883Sandreas@sandberg.pp.se     * Support routines to update the state of gem5's thread context from
2079883Sandreas@sandberg.pp.se     * KVM's state representation.
2089883Sandreas@sandberg.pp.se     *
2099883Sandreas@sandberg.pp.se     * @{
2109883Sandreas@sandberg.pp.se     */
2119883Sandreas@sandberg.pp.se    /** Update integer registers */
21210113Sandreas@sandberg.pp.se    void updateThreadContextRegs(const struct kvm_regs &regs,
21310113Sandreas@sandberg.pp.se                                 const struct kvm_sregs &sregs);
2149883Sandreas@sandberg.pp.se    /** Update control registers (CRx, segments, etc.) */
21510113Sandreas@sandberg.pp.se    void updateThreadContextSRegs(const struct kvm_sregs &sregs);
2169890Sandreas@sandberg.pp.se    /** Update FPU and SIMD registers using the legacy API */
21710113Sandreas@sandberg.pp.se    void updateThreadContextFPU(const struct kvm_fpu &fpu);
2189890Sandreas@sandberg.pp.se    /** Update FPU and SIMD registers using the XSave API */
21910113Sandreas@sandberg.pp.se    void updateThreadContextXSave(const struct kvm_xsave &kxsave);
2209883Sandreas@sandberg.pp.se    /** Update MSR registers */
2219883Sandreas@sandberg.pp.se    void updateThreadContextMSRs();
2229883Sandreas@sandberg.pp.se    /** @} */
2239883Sandreas@sandberg.pp.se
2249883Sandreas@sandberg.pp.se    /** Transfer gem5's CPUID values into the virtual CPU. */
2259883Sandreas@sandberg.pp.se    void updateCPUID();
2269883Sandreas@sandberg.pp.se
2279883Sandreas@sandberg.pp.se    /**
2289883Sandreas@sandberg.pp.se     * Handle a 32-bit IO access that should be mapped to a MiscReg.
2299883Sandreas@sandberg.pp.se     *
2309883Sandreas@sandberg.pp.se     * @note This method can only be called on when handling IO after
2319883Sandreas@sandberg.pp.se     * a KVM_EXIT_IO.
2329883Sandreas@sandberg.pp.se     *
2339883Sandreas@sandberg.pp.se     * @param miscreg Register to map the current IO access to.
2349883Sandreas@sandberg.pp.se     */
2359883Sandreas@sandberg.pp.se    void handleIOMiscReg32(int miscreg);
2369883Sandreas@sandberg.pp.se
2379883Sandreas@sandberg.pp.se    /** Cached intersection of supported MSRs */
2389883Sandreas@sandberg.pp.se    mutable Kvm::MSRIndexVector cachedMsrIntersection;
2399883Sandreas@sandberg.pp.se
2409883Sandreas@sandberg.pp.se    /** @{ */
2419883Sandreas@sandberg.pp.se    /** Kvm::capDebugRegs() available? */
2429883Sandreas@sandberg.pp.se    bool haveDebugRegs;
2439883Sandreas@sandberg.pp.se    /** Kvm::capXSave() available? */
2449883Sandreas@sandberg.pp.se    bool haveXSave;
2459890Sandreas@sandberg.pp.se    /**
2469890Sandreas@sandberg.pp.se     * Should the XSave interface be used to sync the FPU and SIMD
2479890Sandreas@sandberg.pp.se     * registers?
2489890Sandreas@sandberg.pp.se     */
2499890Sandreas@sandberg.pp.se    bool useXSave;
2509883Sandreas@sandberg.pp.se    /** Kvm::capXCRs() available? */
2519883Sandreas@sandberg.pp.se    bool haveXCRs;
2529883Sandreas@sandberg.pp.se    /** @} */
2539883Sandreas@sandberg.pp.se};
2549883Sandreas@sandberg.pp.se
2559883Sandreas@sandberg.pp.se#endif
256