base.hh revision 9651
19651SAndreas.Sandberg@ARM.com/*
29651SAndreas.Sandberg@ARM.com * Copyright (c) 2012 ARM Limited
39651SAndreas.Sandberg@ARM.com * All rights reserved
49651SAndreas.Sandberg@ARM.com *
59651SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall
69651SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual
79651SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating
89651SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software
99651SAndreas.Sandberg@ARM.com * licensed hereunder.  You may use the software subject to the license
109651SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated
119651SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software,
129651SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form.
139651SAndreas.Sandberg@ARM.com *
149651SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
159651SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
169651SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
179651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
189651SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
199651SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
209651SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
219651SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
229651SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
239651SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
249651SAndreas.Sandberg@ARM.com *
259651SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
269651SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
279651SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
289651SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
299651SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
309651SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
319651SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
329651SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
339651SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
349651SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
359651SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
369651SAndreas.Sandberg@ARM.com *
379651SAndreas.Sandberg@ARM.com * Authors: Andreas Sandberg
389651SAndreas.Sandberg@ARM.com */
399651SAndreas.Sandberg@ARM.com
409651SAndreas.Sandberg@ARM.com#ifndef __CPU_KVM_BASE_HH__
419651SAndreas.Sandberg@ARM.com#define __CPU_KVM_BASE_HH__
429651SAndreas.Sandberg@ARM.com
439651SAndreas.Sandberg@ARM.com#include <memory>
449651SAndreas.Sandberg@ARM.com
459651SAndreas.Sandberg@ARM.com#include "base/statistics.hh"
469651SAndreas.Sandberg@ARM.com#include "cpu/kvm/perfevent.hh"
479651SAndreas.Sandberg@ARM.com#include "cpu/kvm/timer.hh"
489651SAndreas.Sandberg@ARM.com#include "cpu/kvm/vm.hh"
499651SAndreas.Sandberg@ARM.com#include "cpu/base.hh"
509651SAndreas.Sandberg@ARM.com#include "cpu/simple_thread.hh"
519651SAndreas.Sandberg@ARM.com
529651SAndreas.Sandberg@ARM.com/** Signal to use to trigger time-based exits from KVM */
539651SAndreas.Sandberg@ARM.com#define KVM_TIMER_SIGNAL SIGRTMIN
549651SAndreas.Sandberg@ARM.com
559651SAndreas.Sandberg@ARM.com// forward declarations
569651SAndreas.Sandberg@ARM.comclass ThreadContext;
579651SAndreas.Sandberg@ARM.comstruct BaseKvmCPUParams;
589651SAndreas.Sandberg@ARM.com
599651SAndreas.Sandberg@ARM.com/**
609651SAndreas.Sandberg@ARM.com * Base class for KVM based CPU models
619651SAndreas.Sandberg@ARM.com *
629651SAndreas.Sandberg@ARM.com * All architecture specific KVM implementation should inherit from
639651SAndreas.Sandberg@ARM.com * this class. The most basic CPU models only need to override the
649651SAndreas.Sandberg@ARM.com * updateKvmState() and updateThreadContext() methods to implement
659651SAndreas.Sandberg@ARM.com * state synchronization between gem5 and KVM.
669651SAndreas.Sandberg@ARM.com *
679651SAndreas.Sandberg@ARM.com * The architecture specific implementation is also responsible for
689651SAndreas.Sandberg@ARM.com * delivering interrupts into the VM. This is typically done by
699651SAndreas.Sandberg@ARM.com * overriding tick() and checking the thread context before entering
709651SAndreas.Sandberg@ARM.com * into the VM. In order to deliver an interrupt, the implementation
719651SAndreas.Sandberg@ARM.com * then calls KvmVM::setIRQLine() or BaseKvmCPU::kvmInterrupt()
729651SAndreas.Sandberg@ARM.com * depending on the specifics of the underlying hardware/drivers.
739651SAndreas.Sandberg@ARM.com */
749651SAndreas.Sandberg@ARM.comclass BaseKvmCPU : public BaseCPU
759651SAndreas.Sandberg@ARM.com{
769651SAndreas.Sandberg@ARM.com  public:
779651SAndreas.Sandberg@ARM.com    BaseKvmCPU(BaseKvmCPUParams *params);
789651SAndreas.Sandberg@ARM.com    virtual ~BaseKvmCPU();
799651SAndreas.Sandberg@ARM.com
809651SAndreas.Sandberg@ARM.com    void init();
819651SAndreas.Sandberg@ARM.com    void startup();
829651SAndreas.Sandberg@ARM.com    void regStats();
839651SAndreas.Sandberg@ARM.com
849651SAndreas.Sandberg@ARM.com    void serializeThread(std::ostream &os, ThreadID tid);
859651SAndreas.Sandberg@ARM.com    void unserializeThread(Checkpoint *cp, const std::string &section,
869651SAndreas.Sandberg@ARM.com                           ThreadID tid);
879651SAndreas.Sandberg@ARM.com
889651SAndreas.Sandberg@ARM.com    unsigned int drain(DrainManager *dm);
899651SAndreas.Sandberg@ARM.com    void drainResume();
909651SAndreas.Sandberg@ARM.com
919651SAndreas.Sandberg@ARM.com    void switchOut();
929651SAndreas.Sandberg@ARM.com    void takeOverFrom(BaseCPU *cpu);
939651SAndreas.Sandberg@ARM.com
949651SAndreas.Sandberg@ARM.com    void verifyMemoryMode() const;
959651SAndreas.Sandberg@ARM.com
969651SAndreas.Sandberg@ARM.com    CpuPort &getDataPort() { return dataPort; }
979651SAndreas.Sandberg@ARM.com    CpuPort &getInstPort() { return instPort; }
989651SAndreas.Sandberg@ARM.com
999651SAndreas.Sandberg@ARM.com    void wakeup();
1009651SAndreas.Sandberg@ARM.com    void activateContext(ThreadID thread_num, Cycles delay);
1019651SAndreas.Sandberg@ARM.com    void suspendContext(ThreadID thread_num);
1029651SAndreas.Sandberg@ARM.com    void deallocateContext(ThreadID thread_num);
1039651SAndreas.Sandberg@ARM.com    void haltContext(ThreadID thread_num);
1049651SAndreas.Sandberg@ARM.com
1059651SAndreas.Sandberg@ARM.com    Counter totalInsts() const;
1069651SAndreas.Sandberg@ARM.com    Counter totalOps() const;
1079651SAndreas.Sandberg@ARM.com
1089651SAndreas.Sandberg@ARM.com    /** Dump the internal state to the terminal. */
1099651SAndreas.Sandberg@ARM.com    virtual void dump();
1109651SAndreas.Sandberg@ARM.com
1119651SAndreas.Sandberg@ARM.com    /** SimpleThread object, provides all the architectural state. */
1129651SAndreas.Sandberg@ARM.com    SimpleThread *thread;
1139651SAndreas.Sandberg@ARM.com
1149651SAndreas.Sandberg@ARM.com    /** ThreadContext object, provides an interface for external
1159651SAndreas.Sandberg@ARM.com     * objects to modify this thread's state.
1169651SAndreas.Sandberg@ARM.com     */
1179651SAndreas.Sandberg@ARM.com    ThreadContext *tc;
1189651SAndreas.Sandberg@ARM.com
1199651SAndreas.Sandberg@ARM.com    KvmVM &vm;
1209651SAndreas.Sandberg@ARM.com
1219651SAndreas.Sandberg@ARM.com  protected:
1229651SAndreas.Sandberg@ARM.com    enum Status {
1239651SAndreas.Sandberg@ARM.com        /** Context not scheduled in KVM */
1249651SAndreas.Sandberg@ARM.com        Idle,
1259651SAndreas.Sandberg@ARM.com        /** Running normally */
1269651SAndreas.Sandberg@ARM.com        Running,
1279651SAndreas.Sandberg@ARM.com    };
1289651SAndreas.Sandberg@ARM.com
1299651SAndreas.Sandberg@ARM.com    /** CPU run state */
1309651SAndreas.Sandberg@ARM.com    Status _status;
1319651SAndreas.Sandberg@ARM.com
1329651SAndreas.Sandberg@ARM.com    /**
1339651SAndreas.Sandberg@ARM.com     * Execute the CPU until the next event in the main event queue or
1349651SAndreas.Sandberg@ARM.com     * until the guest needs service from gem5.
1359651SAndreas.Sandberg@ARM.com     *
1369651SAndreas.Sandberg@ARM.com     * @note This method is virtual in order to allow implementations
1379651SAndreas.Sandberg@ARM.com     * to check for architecture specific events (e.g., interrupts)
1389651SAndreas.Sandberg@ARM.com     * before entering the VM.
1399651SAndreas.Sandberg@ARM.com     */
1409651SAndreas.Sandberg@ARM.com    virtual void tick();
1419651SAndreas.Sandberg@ARM.com
1429651SAndreas.Sandberg@ARM.com    /**
1439651SAndreas.Sandberg@ARM.com     * Request KVM to run the guest for a given number of ticks. The
1449651SAndreas.Sandberg@ARM.com     * method returns the approximate number of ticks executed.
1459651SAndreas.Sandberg@ARM.com     *
1469651SAndreas.Sandberg@ARM.com     * @note The returned number of ticks can be both larger or
1479651SAndreas.Sandberg@ARM.com     * smaller than the requested number of ticks. A smaller number
1489651SAndreas.Sandberg@ARM.com     * can, for example, occur when the guest executes MMIO. A larger
1499651SAndreas.Sandberg@ARM.com     * number is typically due to performance counter inaccuracies.
1509651SAndreas.Sandberg@ARM.com     *
1519651SAndreas.Sandberg@ARM.com     * @param ticks Number of ticks to execute
1529651SAndreas.Sandberg@ARM.com     * @return Number of ticks executed (see note)
1539651SAndreas.Sandberg@ARM.com     */
1549651SAndreas.Sandberg@ARM.com    Tick kvmRun(Tick ticks);
1559651SAndreas.Sandberg@ARM.com
1569651SAndreas.Sandberg@ARM.com    /**
1579651SAndreas.Sandberg@ARM.com     * Get a pointer to the kvm_run structure containing all the input
1589651SAndreas.Sandberg@ARM.com     * and output parameters from kvmRun().
1599651SAndreas.Sandberg@ARM.com     */
1609651SAndreas.Sandberg@ARM.com    struct kvm_run *getKvmRunState() { return _kvmRun; };
1619651SAndreas.Sandberg@ARM.com
1629651SAndreas.Sandberg@ARM.com    /**
1639651SAndreas.Sandberg@ARM.com     * Retrieve a pointer to guest data stored at the end of the
1649651SAndreas.Sandberg@ARM.com     * kvm_run structure. This is mainly used for PIO operations
1659651SAndreas.Sandberg@ARM.com     * (KVM_EXIT_IO).
1669651SAndreas.Sandberg@ARM.com     *
1679651SAndreas.Sandberg@ARM.com     * @param offset Offset as specified by the kvm_run structure
1689651SAndreas.Sandberg@ARM.com     * @return Pointer to guest data
1699651SAndreas.Sandberg@ARM.com     */
1709651SAndreas.Sandberg@ARM.com    uint8_t *getGuestData(uint64_t offset) const {
1719651SAndreas.Sandberg@ARM.com        return (uint8_t *)_kvmRun + offset;
1729651SAndreas.Sandberg@ARM.com    };
1739651SAndreas.Sandberg@ARM.com
1749651SAndreas.Sandberg@ARM.com    /**
1759651SAndreas.Sandberg@ARM.com     * @addtogroup KvmInterrupts
1769651SAndreas.Sandberg@ARM.com     * @{
1779651SAndreas.Sandberg@ARM.com     */
1789651SAndreas.Sandberg@ARM.com    /**
1799651SAndreas.Sandberg@ARM.com     * Send a non-maskable interrupt to the guest
1809651SAndreas.Sandberg@ARM.com     *
1819651SAndreas.Sandberg@ARM.com     * @note The presence of this call depends on Kvm::capUserNMI().
1829651SAndreas.Sandberg@ARM.com     */
1839651SAndreas.Sandberg@ARM.com    void kvmNonMaskableInterrupt();
1849651SAndreas.Sandberg@ARM.com
1859651SAndreas.Sandberg@ARM.com    /**
1869651SAndreas.Sandberg@ARM.com     * Send a normal interrupt to the guest
1879651SAndreas.Sandberg@ARM.com     *
1889651SAndreas.Sandberg@ARM.com     * @note Make sure that ready_for_interrupt_injection in kvm_run
1899651SAndreas.Sandberg@ARM.com     * is set prior to calling this function. If not, an interrupt
1909651SAndreas.Sandberg@ARM.com     * window must be requested by setting request_interrupt_window in
1919651SAndreas.Sandberg@ARM.com     * kvm_run to 1 and restarting the guest.
1929651SAndreas.Sandberg@ARM.com     *
1939651SAndreas.Sandberg@ARM.com     * @param interrupt Structure describing the interrupt to send
1949651SAndreas.Sandberg@ARM.com     */
1959651SAndreas.Sandberg@ARM.com    void kvmInterrupt(const struct kvm_interrupt &interrupt);
1969651SAndreas.Sandberg@ARM.com
1979651SAndreas.Sandberg@ARM.com    /** @} */
1989651SAndreas.Sandberg@ARM.com
1999651SAndreas.Sandberg@ARM.com    /** @{ */
2009651SAndreas.Sandberg@ARM.com    /**
2019651SAndreas.Sandberg@ARM.com     * Get/Set the register state of the guest vCPU
2029651SAndreas.Sandberg@ARM.com     *
2039651SAndreas.Sandberg@ARM.com     * KVM has two different interfaces for accessing the state of the
2049651SAndreas.Sandberg@ARM.com     * guest CPU. One interface updates 'normal' registers and one
2059651SAndreas.Sandberg@ARM.com     * updates 'special' registers. The distinction between special
2069651SAndreas.Sandberg@ARM.com     * and normal registers isn't very clear and is architecture
2079651SAndreas.Sandberg@ARM.com     * dependent.
2089651SAndreas.Sandberg@ARM.com     */
2099651SAndreas.Sandberg@ARM.com    void getRegisters(struct kvm_regs &regs) const;
2109651SAndreas.Sandberg@ARM.com    void setRegisters(const struct kvm_regs &regs);
2119651SAndreas.Sandberg@ARM.com    void getSpecialRegisters(struct kvm_sregs &regs) const;
2129651SAndreas.Sandberg@ARM.com    void setSpecialRegisters(const struct kvm_sregs &regs);
2139651SAndreas.Sandberg@ARM.com    /** @} */
2149651SAndreas.Sandberg@ARM.com
2159651SAndreas.Sandberg@ARM.com    /** @{ */
2169651SAndreas.Sandberg@ARM.com    /**
2179651SAndreas.Sandberg@ARM.com     * Get/Set the guest FPU/vector state
2189651SAndreas.Sandberg@ARM.com     */
2199651SAndreas.Sandberg@ARM.com    void getFPUState(struct kvm_fpu &state) const;
2209651SAndreas.Sandberg@ARM.com    void setFPUState(const struct kvm_fpu &state);
2219651SAndreas.Sandberg@ARM.com    /** @} */
2229651SAndreas.Sandberg@ARM.com
2239651SAndreas.Sandberg@ARM.com    /** @{ */
2249651SAndreas.Sandberg@ARM.com    /**
2259651SAndreas.Sandberg@ARM.com     * Get/Set single register using the KVM_(SET|GET)_ONE_REG API.
2269651SAndreas.Sandberg@ARM.com     *
2279651SAndreas.Sandberg@ARM.com     * @note The presence of this call depends on Kvm::capOneReg().
2289651SAndreas.Sandberg@ARM.com     */
2299651SAndreas.Sandberg@ARM.com    void setOneReg(uint64_t id, const void *addr);
2309651SAndreas.Sandberg@ARM.com    void setOneReg(uint64_t id, uint64_t value) { setOneReg(id, &value); }
2319651SAndreas.Sandberg@ARM.com    void setOneReg(uint64_t id, uint32_t value) { setOneReg(id, &value); }
2329651SAndreas.Sandberg@ARM.com    void getOneReg(uint64_t id, void *addr) const;
2339651SAndreas.Sandberg@ARM.com    uint64_t getOneRegU64(uint64_t id) const {
2349651SAndreas.Sandberg@ARM.com        uint64_t value;
2359651SAndreas.Sandberg@ARM.com        getOneReg(id, &value);
2369651SAndreas.Sandberg@ARM.com        return value;
2379651SAndreas.Sandberg@ARM.com    }
2389651SAndreas.Sandberg@ARM.com    uint32_t getOneRegU32(uint64_t id) const {
2399651SAndreas.Sandberg@ARM.com        uint32_t value;
2409651SAndreas.Sandberg@ARM.com        getOneReg(id, &value);
2419651SAndreas.Sandberg@ARM.com        return value;
2429651SAndreas.Sandberg@ARM.com    }
2439651SAndreas.Sandberg@ARM.com    /** @} */
2449651SAndreas.Sandberg@ARM.com
2459651SAndreas.Sandberg@ARM.com    /**
2469651SAndreas.Sandberg@ARM.com     * Get and format one register for printout.
2479651SAndreas.Sandberg@ARM.com     *
2489651SAndreas.Sandberg@ARM.com     * This function call getOneReg() to retrieve the contents of one
2499651SAndreas.Sandberg@ARM.com     * register and automatically formats it for printing.
2509651SAndreas.Sandberg@ARM.com     *
2519651SAndreas.Sandberg@ARM.com     * @note The presence of this call depends on Kvm::capOneReg().
2529651SAndreas.Sandberg@ARM.com     */
2539651SAndreas.Sandberg@ARM.com    std::string getAndFormatOneReg(uint64_t id) const;
2549651SAndreas.Sandberg@ARM.com
2559651SAndreas.Sandberg@ARM.com    /** @{ */
2569651SAndreas.Sandberg@ARM.com    /**
2579651SAndreas.Sandberg@ARM.com     * Update the KVM state from the current thread context
2589651SAndreas.Sandberg@ARM.com     *
2599651SAndreas.Sandberg@ARM.com     * The base CPU calls this method before starting the guest CPU
2609651SAndreas.Sandberg@ARM.com     * when the contextDirty flag is set. The architecture dependent
2619651SAndreas.Sandberg@ARM.com     * CPU implementation is expected to update all guest state
2629651SAndreas.Sandberg@ARM.com     * (registers, special registers, and FPU state).
2639651SAndreas.Sandberg@ARM.com     */
2649651SAndreas.Sandberg@ARM.com    virtual void updateKvmState() = 0;
2659651SAndreas.Sandberg@ARM.com
2669651SAndreas.Sandberg@ARM.com    /**
2679651SAndreas.Sandberg@ARM.com     * Update the current thread context with the KVM state
2689651SAndreas.Sandberg@ARM.com     *
2699651SAndreas.Sandberg@ARM.com     * The base CPU after the guest updates any of the KVM state. In
2709651SAndreas.Sandberg@ARM.com     * practice, this happens after kvmRun is called. The architecture
2719651SAndreas.Sandberg@ARM.com     * dependent code is expected to read the state of the guest CPU
2729651SAndreas.Sandberg@ARM.com     * and update gem5's thread state.
2739651SAndreas.Sandberg@ARM.com     */
2749651SAndreas.Sandberg@ARM.com    virtual void updateThreadContext() = 0;
2759651SAndreas.Sandberg@ARM.com    /** @} */
2769651SAndreas.Sandberg@ARM.com
2779651SAndreas.Sandberg@ARM.com    /** @{ */
2789651SAndreas.Sandberg@ARM.com    /**
2799651SAndreas.Sandberg@ARM.com     * Main kvmRun exit handler, calls the relevant handleKvmExit*
2809651SAndreas.Sandberg@ARM.com     * depending on exit type.
2819651SAndreas.Sandberg@ARM.com     *
2829651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the exit request
2839651SAndreas.Sandberg@ARM.com     */
2849651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExit();
2859651SAndreas.Sandberg@ARM.com
2869651SAndreas.Sandberg@ARM.com    /**
2879651SAndreas.Sandberg@ARM.com     * The guest performed a legacy IO request (out/inp on x86)
2889651SAndreas.Sandberg@ARM.com     *
2899651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the IO request
2909651SAndreas.Sandberg@ARM.com     */
2919651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitIO();
2929651SAndreas.Sandberg@ARM.com
2939651SAndreas.Sandberg@ARM.com    /**
2949651SAndreas.Sandberg@ARM.com     * The guest requested a monitor service using a hypercall
2959651SAndreas.Sandberg@ARM.com     *
2969651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the hypercall
2979651SAndreas.Sandberg@ARM.com     */
2989651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitHypercall();
2999651SAndreas.Sandberg@ARM.com
3009651SAndreas.Sandberg@ARM.com    /**
3019651SAndreas.Sandberg@ARM.com     * The guest exited because an interrupt window was requested
3029651SAndreas.Sandberg@ARM.com     *
3039651SAndreas.Sandberg@ARM.com     * The guest exited because an interrupt window was requested
3049651SAndreas.Sandberg@ARM.com     * (request_interrupt_window in the kvm_run structure was set to 1
3059651SAndreas.Sandberg@ARM.com     * before calling kvmRun) and it is now ready to receive
3069651SAndreas.Sandberg@ARM.com     *
3079651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the IRQ
3089651SAndreas.Sandberg@ARM.com     */
3099651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitIRQWindowOpen();
3109651SAndreas.Sandberg@ARM.com
3119651SAndreas.Sandberg@ARM.com    /**
3129651SAndreas.Sandberg@ARM.com     * An unknown architecture dependent error occurred when starting
3139651SAndreas.Sandberg@ARM.com     * the vCPU
3149651SAndreas.Sandberg@ARM.com     *
3159651SAndreas.Sandberg@ARM.com     * The kvm_run data structure contains the hardware error
3169651SAndreas.Sandberg@ARM.com     * code. The defaults behavior of this method just prints the HW
3179651SAndreas.Sandberg@ARM.com     * error code and panics. Architecture dependent implementations
3189651SAndreas.Sandberg@ARM.com     * may want to override this method to provide better,
3199651SAndreas.Sandberg@ARM.com     * hardware-aware, error messages.
3209651SAndreas.Sandberg@ARM.com     *
3219651SAndreas.Sandberg@ARM.com     * @return Number of ticks delay the next CPU tick
3229651SAndreas.Sandberg@ARM.com     */
3239651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitUnknown();
3249651SAndreas.Sandberg@ARM.com
3259651SAndreas.Sandberg@ARM.com    /**
3269651SAndreas.Sandberg@ARM.com     * An unhandled virtualization exception occured
3279651SAndreas.Sandberg@ARM.com     *
3289651SAndreas.Sandberg@ARM.com     * Some KVM virtualization drivers return unhandled exceptions to
3299651SAndreas.Sandberg@ARM.com     * the user-space monitor. This interface is currently only used
3309651SAndreas.Sandberg@ARM.com     * by the Intel VMX KVM driver.
3319651SAndreas.Sandberg@ARM.com     *
3329651SAndreas.Sandberg@ARM.com     * @return Number of ticks delay the next CPU tick
3339651SAndreas.Sandberg@ARM.com     */
3349651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitException();
3359651SAndreas.Sandberg@ARM.com
3369651SAndreas.Sandberg@ARM.com    /**
3379651SAndreas.Sandberg@ARM.com     * KVM failed to start the virtualized CPU
3389651SAndreas.Sandberg@ARM.com     *
3399651SAndreas.Sandberg@ARM.com     * The kvm_run data structure contains the hardware-specific error
3409651SAndreas.Sandberg@ARM.com     * code.
3419651SAndreas.Sandberg@ARM.com     *
3429651SAndreas.Sandberg@ARM.com     * @return Number of ticks delay the next CPU tick
3439651SAndreas.Sandberg@ARM.com     */
3449651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitFailEntry();
3459651SAndreas.Sandberg@ARM.com    /** @} */
3469651SAndreas.Sandberg@ARM.com
3479651SAndreas.Sandberg@ARM.com    /**
3489651SAndreas.Sandberg@ARM.com     * Inject a memory mapped IO request into gem5
3499651SAndreas.Sandberg@ARM.com     *
3509651SAndreas.Sandberg@ARM.com     * @param paddr Physical address
3519651SAndreas.Sandberg@ARM.com     * @param data Pointer to the source/destination buffer
3529651SAndreas.Sandberg@ARM.com     * @param size Memory access size
3539651SAndreas.Sandberg@ARM.com     * @param write True if write, False if read
3549651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the memory access
3559651SAndreas.Sandberg@ARM.com     */
3569651SAndreas.Sandberg@ARM.com    Tick doMMIOAccess(Addr paddr, void *data, int size, bool write);
3579651SAndreas.Sandberg@ARM.com
3589651SAndreas.Sandberg@ARM.com
3599651SAndreas.Sandberg@ARM.com    /**
3609651SAndreas.Sandberg@ARM.com     * @addtogroup KvmIoctl
3619651SAndreas.Sandberg@ARM.com     * @{
3629651SAndreas.Sandberg@ARM.com     */
3639651SAndreas.Sandberg@ARM.com    /**
3649651SAndreas.Sandberg@ARM.com     * vCPU ioctl interface.
3659651SAndreas.Sandberg@ARM.com     *
3669651SAndreas.Sandberg@ARM.com     * @param request KVM vCPU request
3679651SAndreas.Sandberg@ARM.com     * @param p1 Optional request parameter
3689651SAndreas.Sandberg@ARM.com     *
3699651SAndreas.Sandberg@ARM.com     * @return -1 on error (error number in errno), ioctl dependent
3709651SAndreas.Sandberg@ARM.com     * value otherwise.
3719651SAndreas.Sandberg@ARM.com     */
3729651SAndreas.Sandberg@ARM.com    int ioctl(int request, long p1) const;
3739651SAndreas.Sandberg@ARM.com    int ioctl(int request, void *p1) const {
3749651SAndreas.Sandberg@ARM.com        return ioctl(request, (long)p1);
3759651SAndreas.Sandberg@ARM.com    }
3769651SAndreas.Sandberg@ARM.com    int ioctl(int request) const {
3779651SAndreas.Sandberg@ARM.com        return ioctl(request, 0L);
3789651SAndreas.Sandberg@ARM.com    }
3799651SAndreas.Sandberg@ARM.com    /** @} */
3809651SAndreas.Sandberg@ARM.com
3819651SAndreas.Sandberg@ARM.com    /** Port for data requests */
3829651SAndreas.Sandberg@ARM.com    CpuPort dataPort;
3839651SAndreas.Sandberg@ARM.com
3849651SAndreas.Sandberg@ARM.com    /** Unused dummy port for the instruction interface */
3859651SAndreas.Sandberg@ARM.com    CpuPort instPort;
3869651SAndreas.Sandberg@ARM.com
3879651SAndreas.Sandberg@ARM.com    /** Pre-allocated MMIO memory request */
3889651SAndreas.Sandberg@ARM.com    Request mmio_req;
3899651SAndreas.Sandberg@ARM.com
3909651SAndreas.Sandberg@ARM.com    /**
3919651SAndreas.Sandberg@ARM.com     * Is the gem5 context dirty? Set to true to force an update of
3929651SAndreas.Sandberg@ARM.com     * the KVM vCPU state upon the next call to kvmRun().
3939651SAndreas.Sandberg@ARM.com     */
3949651SAndreas.Sandberg@ARM.com    bool contextDirty;
3959651SAndreas.Sandberg@ARM.com
3969651SAndreas.Sandberg@ARM.com    /** KVM internal ID of the vCPU */
3979651SAndreas.Sandberg@ARM.com    const long vcpuID;
3989651SAndreas.Sandberg@ARM.com
3999651SAndreas.Sandberg@ARM.com  private:
4009651SAndreas.Sandberg@ARM.com    struct TickEvent : public Event
4019651SAndreas.Sandberg@ARM.com    {
4029651SAndreas.Sandberg@ARM.com        BaseKvmCPU &cpu;
4039651SAndreas.Sandberg@ARM.com
4049651SAndreas.Sandberg@ARM.com        TickEvent(BaseKvmCPU &c)
4059651SAndreas.Sandberg@ARM.com            : Event(CPU_Tick_Pri), cpu(c) {}
4069651SAndreas.Sandberg@ARM.com
4079651SAndreas.Sandberg@ARM.com        void process() { cpu.tick(); }
4089651SAndreas.Sandberg@ARM.com
4099651SAndreas.Sandberg@ARM.com        const char *description() const {
4109651SAndreas.Sandberg@ARM.com            return "BaseKvmCPU tick";
4119651SAndreas.Sandberg@ARM.com        }
4129651SAndreas.Sandberg@ARM.com    };
4139651SAndreas.Sandberg@ARM.com
4149651SAndreas.Sandberg@ARM.com    /**
4159651SAndreas.Sandberg@ARM.com     * Service MMIO requests in the mmioRing.
4169651SAndreas.Sandberg@ARM.com     *
4179651SAndreas.Sandberg@ARM.com     *
4189651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the MMIO requests in
4199651SAndreas.Sandberg@ARM.com     * the MMIO ring buffer
4209651SAndreas.Sandberg@ARM.com     */
4219651SAndreas.Sandberg@ARM.com    Tick flushCoalescedMMIO();
4229651SAndreas.Sandberg@ARM.com
4239651SAndreas.Sandberg@ARM.com    /**
4249651SAndreas.Sandberg@ARM.com     * Setup a signal handler to catch the timer signal used to
4259651SAndreas.Sandberg@ARM.com     * switch back to the monitor.
4269651SAndreas.Sandberg@ARM.com     */
4279651SAndreas.Sandberg@ARM.com    void setupSignalHandler();
4289651SAndreas.Sandberg@ARM.com
4299651SAndreas.Sandberg@ARM.com    /** Setup hardware performance counters */
4309651SAndreas.Sandberg@ARM.com    void setupCounters();
4319651SAndreas.Sandberg@ARM.com
4329651SAndreas.Sandberg@ARM.com    /** @{ */
4339651SAndreas.Sandberg@ARM.com    /** Start/stop counting HW performance events */
4349651SAndreas.Sandberg@ARM.com    void startCounters();
4359651SAndreas.Sandberg@ARM.com    void stopCounters();
4369651SAndreas.Sandberg@ARM.com    /** @} */
4379651SAndreas.Sandberg@ARM.com
4389651SAndreas.Sandberg@ARM.com    /** KVM vCPU file descriptor */
4399651SAndreas.Sandberg@ARM.com    int vcpuFD;
4409651SAndreas.Sandberg@ARM.com    /** Size of MMAPed kvm_run area */
4419651SAndreas.Sandberg@ARM.com    int vcpuMMapSize;
4429651SAndreas.Sandberg@ARM.com    /**
4439651SAndreas.Sandberg@ARM.com     * Pointer to the kvm_run structure used to communicate parameters
4449651SAndreas.Sandberg@ARM.com     * with KVM.
4459651SAndreas.Sandberg@ARM.com     *
4469651SAndreas.Sandberg@ARM.com     * @note This is the base pointer of the MMAPed KVM region. The
4479651SAndreas.Sandberg@ARM.com     * first page contains the kvm_run structure. Subsequent pages may
4489651SAndreas.Sandberg@ARM.com     * contain other data such as the MMIO ring buffer.
4499651SAndreas.Sandberg@ARM.com     */
4509651SAndreas.Sandberg@ARM.com    struct kvm_run *_kvmRun;
4519651SAndreas.Sandberg@ARM.com    /**
4529651SAndreas.Sandberg@ARM.com     * Coalesced MMIO ring buffer. NULL if coalesced MMIO is not
4539651SAndreas.Sandberg@ARM.com     * supported.
4549651SAndreas.Sandberg@ARM.com     */
4559651SAndreas.Sandberg@ARM.com    struct kvm_coalesced_mmio_ring *mmioRing;
4569651SAndreas.Sandberg@ARM.com    /** Cached page size of the host */
4579651SAndreas.Sandberg@ARM.com    const long pageSize;
4589651SAndreas.Sandberg@ARM.com
4599651SAndreas.Sandberg@ARM.com    TickEvent tickEvent;
4609651SAndreas.Sandberg@ARM.com
4619651SAndreas.Sandberg@ARM.com    /** @{ */
4629651SAndreas.Sandberg@ARM.com    /** Guest performance counters */
4639651SAndreas.Sandberg@ARM.com    PerfKvmCounter hwCycles;
4649651SAndreas.Sandberg@ARM.com    PerfKvmCounter hwInstructions;
4659651SAndreas.Sandberg@ARM.com    /** @} */
4669651SAndreas.Sandberg@ARM.com
4679651SAndreas.Sandberg@ARM.com    /**
4689651SAndreas.Sandberg@ARM.com     * Timer used to force execution into the monitor after a
4699651SAndreas.Sandberg@ARM.com     * specified number of simulation tick equivalents have executed
4709651SAndreas.Sandberg@ARM.com     * in the guest. This counter generates the signal specified by
4719651SAndreas.Sandberg@ARM.com     * KVM_TIMER_SIGNAL.
4729651SAndreas.Sandberg@ARM.com     */
4739651SAndreas.Sandberg@ARM.com    std::unique_ptr<BaseKvmTimer> runTimer;
4749651SAndreas.Sandberg@ARM.com
4759651SAndreas.Sandberg@ARM.com    float hostFactor;
4769651SAndreas.Sandberg@ARM.com
4779651SAndreas.Sandberg@ARM.com  public:
4789651SAndreas.Sandberg@ARM.com    /* @{ */
4799651SAndreas.Sandberg@ARM.com    Stats::Scalar numVMExits;
4809651SAndreas.Sandberg@ARM.com    Stats::Scalar numMMIO;
4819651SAndreas.Sandberg@ARM.com    Stats::Scalar numCoalescedMMIO;
4829651SAndreas.Sandberg@ARM.com    Stats::Scalar numIO;
4839651SAndreas.Sandberg@ARM.com    Stats::Scalar numHalt;
4849651SAndreas.Sandberg@ARM.com    Stats::Scalar numInterrupts;
4859651SAndreas.Sandberg@ARM.com    Stats::Scalar numHypercalls;
4869651SAndreas.Sandberg@ARM.com    /* @} */
4879651SAndreas.Sandberg@ARM.com};
4889651SAndreas.Sandberg@ARM.com
4899651SAndreas.Sandberg@ARM.com#endif
490