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
4310114Sandreas@sandberg.pp.se#include <pthread.h>
4410114Sandreas@sandberg.pp.se
4510114Sandreas@sandberg.pp.se#include <csignal>
469651SAndreas.Sandberg@ARM.com#include <memory>
4711629Smichael.lebeane@amd.com#include <queue>
489651SAndreas.Sandberg@ARM.com
499651SAndreas.Sandberg@ARM.com#include "base/statistics.hh"
509651SAndreas.Sandberg@ARM.com#include "cpu/kvm/perfevent.hh"
519651SAndreas.Sandberg@ARM.com#include "cpu/kvm/timer.hh"
529651SAndreas.Sandberg@ARM.com#include "cpu/kvm/vm.hh"
539651SAndreas.Sandberg@ARM.com#include "cpu/base.hh"
549651SAndreas.Sandberg@ARM.com#include "cpu/simple_thread.hh"
559651SAndreas.Sandberg@ARM.com
5610114Sandreas@sandberg.pp.se/** Signal to use to trigger exits from KVM */
5710114Sandreas@sandberg.pp.se#define KVM_KICK_SIGNAL SIGRTMIN
589892Sandreas@sandberg.pp.se
599651SAndreas.Sandberg@ARM.com// forward declarations
609651SAndreas.Sandberg@ARM.comclass ThreadContext;
619651SAndreas.Sandberg@ARM.comstruct BaseKvmCPUParams;
629651SAndreas.Sandberg@ARM.com
639651SAndreas.Sandberg@ARM.com/**
649651SAndreas.Sandberg@ARM.com * Base class for KVM based CPU models
659651SAndreas.Sandberg@ARM.com *
669651SAndreas.Sandberg@ARM.com * All architecture specific KVM implementation should inherit from
679651SAndreas.Sandberg@ARM.com * this class. The most basic CPU models only need to override the
689651SAndreas.Sandberg@ARM.com * updateKvmState() and updateThreadContext() methods to implement
699651SAndreas.Sandberg@ARM.com * state synchronization between gem5 and KVM.
709651SAndreas.Sandberg@ARM.com *
719651SAndreas.Sandberg@ARM.com * The architecture specific implementation is also responsible for
729651SAndreas.Sandberg@ARM.com * delivering interrupts into the VM. This is typically done by
739651SAndreas.Sandberg@ARM.com * overriding tick() and checking the thread context before entering
749651SAndreas.Sandberg@ARM.com * into the VM. In order to deliver an interrupt, the implementation
759651SAndreas.Sandberg@ARM.com * then calls KvmVM::setIRQLine() or BaseKvmCPU::kvmInterrupt()
769651SAndreas.Sandberg@ARM.com * depending on the specifics of the underlying hardware/drivers.
779651SAndreas.Sandberg@ARM.com */
789651SAndreas.Sandberg@ARM.comclass BaseKvmCPU : public BaseCPU
799651SAndreas.Sandberg@ARM.com{
809651SAndreas.Sandberg@ARM.com  public:
819651SAndreas.Sandberg@ARM.com    BaseKvmCPU(BaseKvmCPUParams *params);
829651SAndreas.Sandberg@ARM.com    virtual ~BaseKvmCPU();
839651SAndreas.Sandberg@ARM.com
8411341Sandreas.hansson@arm.com    void init() override;
8511341Sandreas.hansson@arm.com    void startup() override;
8611341Sandreas.hansson@arm.com    void regStats() override;
879651SAndreas.Sandberg@ARM.com
8811168Sandreas.hansson@arm.com    void serializeThread(CheckpointOut &cp, ThreadID tid) const override;
8911168Sandreas.hansson@arm.com    void unserializeThread(CheckpointIn &cp, ThreadID tid) override;
909651SAndreas.Sandberg@ARM.com
9111168Sandreas.hansson@arm.com    DrainState drain() override;
9211168Sandreas.hansson@arm.com    void drainResume() override;
9311363Sandreas@sandberg.pp.se    void notifyFork() override;
949651SAndreas.Sandberg@ARM.com
9511341Sandreas.hansson@arm.com    void switchOut() override;
9611341Sandreas.hansson@arm.com    void takeOverFrom(BaseCPU *cpu) override;
979651SAndreas.Sandberg@ARM.com
9811341Sandreas.hansson@arm.com    void verifyMemoryMode() const override;
999651SAndreas.Sandberg@ARM.com
10014198Sgabeblack@google.com    Port &getDataPort() override { return dataPort; }
10114198Sgabeblack@google.com    Port &getInstPort() override { return instPort; }
1029651SAndreas.Sandberg@ARM.com
10311168Sandreas.hansson@arm.com    void wakeup(ThreadID tid = 0) override;
10411341Sandreas.hansson@arm.com    void activateContext(ThreadID thread_num) override;
10511341Sandreas.hansson@arm.com    void suspendContext(ThreadID thread_num) override;
1069651SAndreas.Sandberg@ARM.com    void deallocateContext(ThreadID thread_num);
10711341Sandreas.hansson@arm.com    void haltContext(ThreadID thread_num) override;
1089651SAndreas.Sandberg@ARM.com
10911943SCurtis.Dunham@arm.com    long getVCpuID() const { return vcpuID; }
11011341Sandreas.hansson@arm.com    ThreadContext *getContext(int tn) override;
1119652SAndreas.Sandberg@ARM.com
11211341Sandreas.hansson@arm.com    Counter totalInsts() const override;
11311341Sandreas.hansson@arm.com    Counter totalOps() const override;
1149651SAndreas.Sandberg@ARM.com
11511629Smichael.lebeane@amd.com    /**
11611629Smichael.lebeane@amd.com     * Callback from KvmCPUPort to transition the CPU out of RunningMMIOPending
11711629Smichael.lebeane@amd.com     * when all timing requests have completed.
11811629Smichael.lebeane@amd.com     */
11911629Smichael.lebeane@amd.com    void finishMMIOPending();
12011629Smichael.lebeane@amd.com
1219651SAndreas.Sandberg@ARM.com    /** Dump the internal state to the terminal. */
12210905Sandreas.sandberg@arm.com    virtual void dump() const;
1239651SAndreas.Sandberg@ARM.com
1249652SAndreas.Sandberg@ARM.com    /**
12510114Sandreas@sandberg.pp.se     * Force an exit from KVM.
12610114Sandreas@sandberg.pp.se     *
12710114Sandreas@sandberg.pp.se     * Send a signal to the thread owning this vCPU to get it to exit
12810114Sandreas@sandberg.pp.se     * from KVM. Ignored if the vCPU is not executing.
12910114Sandreas@sandberg.pp.se     */
13010114Sandreas@sandberg.pp.se    void kick() const { pthread_kill(vcpuThread, KVM_KICK_SIGNAL); }
13110114Sandreas@sandberg.pp.se
13210114Sandreas@sandberg.pp.se    /**
1339652SAndreas.Sandberg@ARM.com     * A cached copy of a thread's state in the form of a SimpleThread
1349652SAndreas.Sandberg@ARM.com     * object.
1359652SAndreas.Sandberg@ARM.com     *
1369652SAndreas.Sandberg@ARM.com     * Normally the actual thread state is stored in the KVM vCPU. If KVM has
1379652SAndreas.Sandberg@ARM.com     * been running this copy is will be out of date. If we recently handled
1389652SAndreas.Sandberg@ARM.com     * some events within gem5 that required state to be updated this could be
1399652SAndreas.Sandberg@ARM.com     * the most up-to-date copy. When getContext() or updateThreadContext() is
1409652SAndreas.Sandberg@ARM.com     * called this copy gets updated.  The method syncThreadContext can
1419652SAndreas.Sandberg@ARM.com     * be used within a KVM CPU to update the thread context if the
1429652SAndreas.Sandberg@ARM.com     * KVM state is dirty (i.e., the vCPU has been run since the last
1439652SAndreas.Sandberg@ARM.com     * update).
1449652SAndreas.Sandberg@ARM.com     */
1459651SAndreas.Sandberg@ARM.com    SimpleThread *thread;
1469651SAndreas.Sandberg@ARM.com
1479651SAndreas.Sandberg@ARM.com    /** ThreadContext object, provides an interface for external
1489651SAndreas.Sandberg@ARM.com     * objects to modify this thread's state.
1499651SAndreas.Sandberg@ARM.com     */
1509651SAndreas.Sandberg@ARM.com    ThreadContext *tc;
1519651SAndreas.Sandberg@ARM.com
1529651SAndreas.Sandberg@ARM.com    KvmVM &vm;
1539651SAndreas.Sandberg@ARM.com
1549651SAndreas.Sandberg@ARM.com  protected:
1559753Sandreas@sandberg.pp.se    /**
1569753Sandreas@sandberg.pp.se     *
1579753Sandreas@sandberg.pp.se     * @dot
1589753Sandreas@sandberg.pp.se     *   digraph {
1599753Sandreas@sandberg.pp.se     *     Idle;
1609753Sandreas@sandberg.pp.se     *     Running;
1619753Sandreas@sandberg.pp.se     *     RunningService;
1629753Sandreas@sandberg.pp.se     *     RunningServiceCompletion;
16311629Smichael.lebeane@amd.com     *     RunningMMIOPending;
1649753Sandreas@sandberg.pp.se     *
1659753Sandreas@sandberg.pp.se     *     Idle -> Idle;
1669753Sandreas@sandberg.pp.se     *     Idle -> Running [label="activateContext()", URL="\ref activateContext"];
1679753Sandreas@sandberg.pp.se     *     Running -> Running [label="tick()", URL="\ref tick"];
1689753Sandreas@sandberg.pp.se     *     Running -> RunningService [label="tick()", URL="\ref tick"];
1699753Sandreas@sandberg.pp.se     *     Running -> Idle [label="suspendContext()", URL="\ref suspendContext"];
1709753Sandreas@sandberg.pp.se     *     Running -> Idle [label="drain()", URL="\ref drain"];
1719753Sandreas@sandberg.pp.se     *     Idle -> Running [label="drainResume()", URL="\ref drainResume"];
1729753Sandreas@sandberg.pp.se     *     RunningService -> RunningServiceCompletion [label="handleKvmExit()", URL="\ref handleKvmExit"];
17311629Smichael.lebeane@amd.com     *     RunningService -> RunningMMIOPending [label="handleKvmExit()", URL="\ref handleKvmExit"];
17411629Smichael.lebeane@amd.com     *     RunningMMIOPending -> RunningServiceCompletion [label="finishMMIOPending()", URL="\ref finishMMIOPending"];
1759753Sandreas@sandberg.pp.se     *     RunningServiceCompletion -> Running [label="tick()", URL="\ref tick"];
1769753Sandreas@sandberg.pp.se     *     RunningServiceCompletion -> RunningService [label="tick()", URL="\ref tick"];
1779753Sandreas@sandberg.pp.se     *   }
1789753Sandreas@sandberg.pp.se     * @enddot
1799753Sandreas@sandberg.pp.se     */
1809651SAndreas.Sandberg@ARM.com    enum Status {
1819753Sandreas@sandberg.pp.se        /** Context not scheduled in KVM.
1829753Sandreas@sandberg.pp.se         *
1839753Sandreas@sandberg.pp.se         * The CPU generally enters this state when the guest execute
1849753Sandreas@sandberg.pp.se         * an instruction that halts the CPU (e.g., WFI on ARM or HLT
1859753Sandreas@sandberg.pp.se         * on X86) if KVM traps this instruction. Ticks are not
1869753Sandreas@sandberg.pp.se         * scheduled in this state.
1879753Sandreas@sandberg.pp.se         *
1889753Sandreas@sandberg.pp.se         * @see suspendContext()
1899753Sandreas@sandberg.pp.se         */
1909651SAndreas.Sandberg@ARM.com        Idle,
1919753Sandreas@sandberg.pp.se        /** Running normally.
1929753Sandreas@sandberg.pp.se         *
1939753Sandreas@sandberg.pp.se         * This is the normal run state of the CPU. KVM will be
1949753Sandreas@sandberg.pp.se         * entered next time tick() is called.
1959753Sandreas@sandberg.pp.se         */
1969651SAndreas.Sandberg@ARM.com        Running,
1979753Sandreas@sandberg.pp.se        /** Requiring service at the beginning of the next cycle.
1989753Sandreas@sandberg.pp.se         *
1999753Sandreas@sandberg.pp.se         * The virtual machine has exited and requires service, tick()
2009753Sandreas@sandberg.pp.se         * will call handleKvmExit() on the next cycle. The next state
2019753Sandreas@sandberg.pp.se         * after running service is determined in handleKvmExit() and
2029753Sandreas@sandberg.pp.se         * depends on what kind of service the guest requested:
2039753Sandreas@sandberg.pp.se         * <ul>
20411629Smichael.lebeane@amd.com         *   <li>IO/MMIO (Atomic): RunningServiceCompletion
20511629Smichael.lebeane@amd.com         *   <li>IO/MMIO (Timing): RunningMMIOPending
2069753Sandreas@sandberg.pp.se         *   <li>Halt: Idle
2079753Sandreas@sandberg.pp.se         *   <li>Others: Running
2089753Sandreas@sandberg.pp.se         * </ul>
2099753Sandreas@sandberg.pp.se         */
2109753Sandreas@sandberg.pp.se        RunningService,
21111629Smichael.lebeane@amd.com        /** Timing MMIO request in flight or stalled.
21211629Smichael.lebeane@amd.com         *
21311629Smichael.lebeane@amd.com         *  The VM has requested IO/MMIO and we are in timing mode.  A timing
21411629Smichael.lebeane@amd.com         *  request is either stalled (and will be retried with recvReqRetry())
21511629Smichael.lebeane@amd.com         *  or it is in flight.  After the timing request is complete, the CPU
21611629Smichael.lebeane@amd.com         *  will transition to the RunningServiceCompletion state.
21711629Smichael.lebeane@amd.com         */
21811629Smichael.lebeane@amd.com        RunningMMIOPending,
2199753Sandreas@sandberg.pp.se        /** Service completion in progress.
2209753Sandreas@sandberg.pp.se         *
2219753Sandreas@sandberg.pp.se         * The VM has requested service that requires KVM to be
2229753Sandreas@sandberg.pp.se         * entered once in order to get to a consistent state. This
2239753Sandreas@sandberg.pp.se         * happens in handleKvmExit() or one of its friends after IO
2249753Sandreas@sandberg.pp.se         * exits. After executing tick(), the CPU will transition into
2259753Sandreas@sandberg.pp.se         * the Running or RunningService state.
2269753Sandreas@sandberg.pp.se         */
2279753Sandreas@sandberg.pp.se        RunningServiceCompletion,
2289651SAndreas.Sandberg@ARM.com    };
2299651SAndreas.Sandberg@ARM.com
2309651SAndreas.Sandberg@ARM.com    /** CPU run state */
2319651SAndreas.Sandberg@ARM.com    Status _status;
2329651SAndreas.Sandberg@ARM.com
2339651SAndreas.Sandberg@ARM.com    /**
2349651SAndreas.Sandberg@ARM.com     * Execute the CPU until the next event in the main event queue or
2359651SAndreas.Sandberg@ARM.com     * until the guest needs service from gem5.
2369651SAndreas.Sandberg@ARM.com     */
2379753Sandreas@sandberg.pp.se    void tick();
2389651SAndreas.Sandberg@ARM.com
2399651SAndreas.Sandberg@ARM.com    /**
2409735Sandreas@sandberg.pp.se     * Get the value of the hardware cycle counter in the guest.
2419735Sandreas@sandberg.pp.se     *
2429735Sandreas@sandberg.pp.se     * This method is supposed to return the total number of cycles
2439735Sandreas@sandberg.pp.se     * executed in hardware mode relative to some arbitrary point in
2449735Sandreas@sandberg.pp.se     * the past. It's mainly used when estimating the number of cycles
2459735Sandreas@sandberg.pp.se     * actually executed by the CPU in kvmRun(). The default behavior
2469735Sandreas@sandberg.pp.se     * of this method is to use the cycles performance counter, but
2479735Sandreas@sandberg.pp.se     * some architectures may want to use internal registers instead.
2489735Sandreas@sandberg.pp.se     *
2499735Sandreas@sandberg.pp.se     * @return Number of host cycles executed relative to an undefined
2509735Sandreas@sandberg.pp.se     * point in the past.
2519735Sandreas@sandberg.pp.se     */
2529735Sandreas@sandberg.pp.se    virtual uint64_t getHostCycles() const;
2539735Sandreas@sandberg.pp.se
2549735Sandreas@sandberg.pp.se    /**
2559651SAndreas.Sandberg@ARM.com     * Request KVM to run the guest for a given number of ticks. The
2569651SAndreas.Sandberg@ARM.com     * method returns the approximate number of ticks executed.
2579651SAndreas.Sandberg@ARM.com     *
2589651SAndreas.Sandberg@ARM.com     * @note The returned number of ticks can be both larger or
2599651SAndreas.Sandberg@ARM.com     * smaller than the requested number of ticks. A smaller number
2609651SAndreas.Sandberg@ARM.com     * can, for example, occur when the guest executes MMIO. A larger
2619651SAndreas.Sandberg@ARM.com     * number is typically due to performance counter inaccuracies.
2629651SAndreas.Sandberg@ARM.com     *
2639753Sandreas@sandberg.pp.se     * @note This method is virtual in order to allow implementations
2649753Sandreas@sandberg.pp.se     * to check for architecture specific events (e.g., interrupts)
2659753Sandreas@sandberg.pp.se     * before entering the VM.
2669753Sandreas@sandberg.pp.se     *
2679753Sandreas@sandberg.pp.se     * @note It is the response of the caller (normally tick()) to
2689753Sandreas@sandberg.pp.se     * make sure that the KVM state is synchronized and that the TC is
2699753Sandreas@sandberg.pp.se     * invalidated after entering KVM.
2709753Sandreas@sandberg.pp.se     *
27110112Sandreas@sandberg.pp.se     * @note This method does not normally cause any state
27210112Sandreas@sandberg.pp.se     * transitions. However, if it may suspend the CPU by suspending
27310112Sandreas@sandberg.pp.se     * the thread, which leads to a transition to the Idle state. In
27410112Sandreas@sandberg.pp.se     * such a case, kvm <i>must not</i> be entered.
27510112Sandreas@sandberg.pp.se     *
2769753Sandreas@sandberg.pp.se     * @param ticks Number of ticks to execute, set to 0 to exit
2779753Sandreas@sandberg.pp.se     * immediately after finishing pending operations.
2789651SAndreas.Sandberg@ARM.com     * @return Number of ticks executed (see note)
2799651SAndreas.Sandberg@ARM.com     */
2809753Sandreas@sandberg.pp.se    virtual Tick kvmRun(Tick ticks);
2819753Sandreas@sandberg.pp.se
2829753Sandreas@sandberg.pp.se    /**
2839753Sandreas@sandberg.pp.se     * Request the CPU to run until draining completes.
2849753Sandreas@sandberg.pp.se     *
2859753Sandreas@sandberg.pp.se     * This function normally calls kvmRun(0) to make KVM finish
2869753Sandreas@sandberg.pp.se     * pending MMIO operations. Architecures implementing
2879753Sandreas@sandberg.pp.se     * archIsDrained() must override this method.
2889753Sandreas@sandberg.pp.se     *
2899753Sandreas@sandberg.pp.se     * @see BaseKvmCPU::archIsDrained()
2909753Sandreas@sandberg.pp.se     *
2919753Sandreas@sandberg.pp.se     * @return Number of ticks executed
2929753Sandreas@sandberg.pp.se     */
2939753Sandreas@sandberg.pp.se    virtual Tick kvmRunDrain();
2949651SAndreas.Sandberg@ARM.com
2959651SAndreas.Sandberg@ARM.com    /**
2969651SAndreas.Sandberg@ARM.com     * Get a pointer to the kvm_run structure containing all the input
2979651SAndreas.Sandberg@ARM.com     * and output parameters from kvmRun().
2989651SAndreas.Sandberg@ARM.com     */
2999651SAndreas.Sandberg@ARM.com    struct kvm_run *getKvmRunState() { return _kvmRun; };
3009651SAndreas.Sandberg@ARM.com
3019651SAndreas.Sandberg@ARM.com    /**
3029651SAndreas.Sandberg@ARM.com     * Retrieve a pointer to guest data stored at the end of the
3039651SAndreas.Sandberg@ARM.com     * kvm_run structure. This is mainly used for PIO operations
3049651SAndreas.Sandberg@ARM.com     * (KVM_EXIT_IO).
3059651SAndreas.Sandberg@ARM.com     *
3069651SAndreas.Sandberg@ARM.com     * @param offset Offset as specified by the kvm_run structure
3079651SAndreas.Sandberg@ARM.com     * @return Pointer to guest data
3089651SAndreas.Sandberg@ARM.com     */
3099651SAndreas.Sandberg@ARM.com    uint8_t *getGuestData(uint64_t offset) const {
3109651SAndreas.Sandberg@ARM.com        return (uint8_t *)_kvmRun + offset;
3119651SAndreas.Sandberg@ARM.com    };
3129651SAndreas.Sandberg@ARM.com
3139651SAndreas.Sandberg@ARM.com    /**
3149651SAndreas.Sandberg@ARM.com     * @addtogroup KvmInterrupts
3159651SAndreas.Sandberg@ARM.com     * @{
3169651SAndreas.Sandberg@ARM.com     */
3179651SAndreas.Sandberg@ARM.com    /**
3189651SAndreas.Sandberg@ARM.com     * Send a non-maskable interrupt to the guest
3199651SAndreas.Sandberg@ARM.com     *
3209651SAndreas.Sandberg@ARM.com     * @note The presence of this call depends on Kvm::capUserNMI().
3219651SAndreas.Sandberg@ARM.com     */
3229651SAndreas.Sandberg@ARM.com    void kvmNonMaskableInterrupt();
3239651SAndreas.Sandberg@ARM.com
3249651SAndreas.Sandberg@ARM.com    /**
3259651SAndreas.Sandberg@ARM.com     * Send a normal interrupt to the guest
3269651SAndreas.Sandberg@ARM.com     *
3279651SAndreas.Sandberg@ARM.com     * @note Make sure that ready_for_interrupt_injection in kvm_run
3289651SAndreas.Sandberg@ARM.com     * is set prior to calling this function. If not, an interrupt
3299651SAndreas.Sandberg@ARM.com     * window must be requested by setting request_interrupt_window in
3309651SAndreas.Sandberg@ARM.com     * kvm_run to 1 and restarting the guest.
3319651SAndreas.Sandberg@ARM.com     *
3329651SAndreas.Sandberg@ARM.com     * @param interrupt Structure describing the interrupt to send
3339651SAndreas.Sandberg@ARM.com     */
3349651SAndreas.Sandberg@ARM.com    void kvmInterrupt(const struct kvm_interrupt &interrupt);
3359651SAndreas.Sandberg@ARM.com
3369651SAndreas.Sandberg@ARM.com    /** @} */
3379651SAndreas.Sandberg@ARM.com
3389651SAndreas.Sandberg@ARM.com    /** @{ */
3399651SAndreas.Sandberg@ARM.com    /**
3409651SAndreas.Sandberg@ARM.com     * Get/Set the register state of the guest vCPU
3419651SAndreas.Sandberg@ARM.com     *
3429651SAndreas.Sandberg@ARM.com     * KVM has two different interfaces for accessing the state of the
3439651SAndreas.Sandberg@ARM.com     * guest CPU. One interface updates 'normal' registers and one
3449651SAndreas.Sandberg@ARM.com     * updates 'special' registers. The distinction between special
3459651SAndreas.Sandberg@ARM.com     * and normal registers isn't very clear and is architecture
3469651SAndreas.Sandberg@ARM.com     * dependent.
3479651SAndreas.Sandberg@ARM.com     */
3489651SAndreas.Sandberg@ARM.com    void getRegisters(struct kvm_regs &regs) const;
3499651SAndreas.Sandberg@ARM.com    void setRegisters(const struct kvm_regs &regs);
3509651SAndreas.Sandberg@ARM.com    void getSpecialRegisters(struct kvm_sregs &regs) const;
3519651SAndreas.Sandberg@ARM.com    void setSpecialRegisters(const struct kvm_sregs &regs);
3529651SAndreas.Sandberg@ARM.com    /** @} */
3539651SAndreas.Sandberg@ARM.com
3549651SAndreas.Sandberg@ARM.com    /** @{ */
3559651SAndreas.Sandberg@ARM.com    /**
3569651SAndreas.Sandberg@ARM.com     * Get/Set the guest FPU/vector state
3579651SAndreas.Sandberg@ARM.com     */
3589651SAndreas.Sandberg@ARM.com    void getFPUState(struct kvm_fpu &state) const;
3599651SAndreas.Sandberg@ARM.com    void setFPUState(const struct kvm_fpu &state);
3609651SAndreas.Sandberg@ARM.com    /** @} */
3619651SAndreas.Sandberg@ARM.com
3629651SAndreas.Sandberg@ARM.com    /** @{ */
3639651SAndreas.Sandberg@ARM.com    /**
3649651SAndreas.Sandberg@ARM.com     * Get/Set single register using the KVM_(SET|GET)_ONE_REG API.
3659651SAndreas.Sandberg@ARM.com     *
3669651SAndreas.Sandberg@ARM.com     * @note The presence of this call depends on Kvm::capOneReg().
3679651SAndreas.Sandberg@ARM.com     */
3689651SAndreas.Sandberg@ARM.com    void setOneReg(uint64_t id, const void *addr);
3699651SAndreas.Sandberg@ARM.com    void setOneReg(uint64_t id, uint64_t value) { setOneReg(id, &value); }
3709651SAndreas.Sandberg@ARM.com    void setOneReg(uint64_t id, uint32_t value) { setOneReg(id, &value); }
3719651SAndreas.Sandberg@ARM.com    void getOneReg(uint64_t id, void *addr) const;
3729651SAndreas.Sandberg@ARM.com    uint64_t getOneRegU64(uint64_t id) const {
3739651SAndreas.Sandberg@ARM.com        uint64_t value;
3749651SAndreas.Sandberg@ARM.com        getOneReg(id, &value);
3759651SAndreas.Sandberg@ARM.com        return value;
3769651SAndreas.Sandberg@ARM.com    }
3779651SAndreas.Sandberg@ARM.com    uint32_t getOneRegU32(uint64_t id) const {
3789651SAndreas.Sandberg@ARM.com        uint32_t value;
3799651SAndreas.Sandberg@ARM.com        getOneReg(id, &value);
3809651SAndreas.Sandberg@ARM.com        return value;
3819651SAndreas.Sandberg@ARM.com    }
3829651SAndreas.Sandberg@ARM.com    /** @} */
3839651SAndreas.Sandberg@ARM.com
3849651SAndreas.Sandberg@ARM.com    /**
3859651SAndreas.Sandberg@ARM.com     * Get and format one register for printout.
3869651SAndreas.Sandberg@ARM.com     *
3879651SAndreas.Sandberg@ARM.com     * This function call getOneReg() to retrieve the contents of one
3889651SAndreas.Sandberg@ARM.com     * register and automatically formats it for printing.
3899651SAndreas.Sandberg@ARM.com     *
3909651SAndreas.Sandberg@ARM.com     * @note The presence of this call depends on Kvm::capOneReg().
3919651SAndreas.Sandberg@ARM.com     */
3929651SAndreas.Sandberg@ARM.com    std::string getAndFormatOneReg(uint64_t id) const;
3939651SAndreas.Sandberg@ARM.com
3949651SAndreas.Sandberg@ARM.com    /** @{ */
3959651SAndreas.Sandberg@ARM.com    /**
3969651SAndreas.Sandberg@ARM.com     * Update the KVM state from the current thread context
3979651SAndreas.Sandberg@ARM.com     *
3989651SAndreas.Sandberg@ARM.com     * The base CPU calls this method before starting the guest CPU
3999651SAndreas.Sandberg@ARM.com     * when the contextDirty flag is set. The architecture dependent
4009651SAndreas.Sandberg@ARM.com     * CPU implementation is expected to update all guest state
4019651SAndreas.Sandberg@ARM.com     * (registers, special registers, and FPU state).
4029651SAndreas.Sandberg@ARM.com     */
4039651SAndreas.Sandberg@ARM.com    virtual void updateKvmState() = 0;
4049651SAndreas.Sandberg@ARM.com
4059651SAndreas.Sandberg@ARM.com    /**
4069651SAndreas.Sandberg@ARM.com     * Update the current thread context with the KVM state
4079651SAndreas.Sandberg@ARM.com     *
4089651SAndreas.Sandberg@ARM.com     * The base CPU after the guest updates any of the KVM state. In
4099651SAndreas.Sandberg@ARM.com     * practice, this happens after kvmRun is called. The architecture
4109651SAndreas.Sandberg@ARM.com     * dependent code is expected to read the state of the guest CPU
4119651SAndreas.Sandberg@ARM.com     * and update gem5's thread state.
4129651SAndreas.Sandberg@ARM.com     */
4139651SAndreas.Sandberg@ARM.com    virtual void updateThreadContext() = 0;
4149652SAndreas.Sandberg@ARM.com
4159652SAndreas.Sandberg@ARM.com    /**
4169652SAndreas.Sandberg@ARM.com     * Update a thread context if the KVM state is dirty with respect
4179652SAndreas.Sandberg@ARM.com     * to the cached thread context.
4189652SAndreas.Sandberg@ARM.com     */
4199652SAndreas.Sandberg@ARM.com    void syncThreadContext();
4209652SAndreas.Sandberg@ARM.com
4219652SAndreas.Sandberg@ARM.com    /**
42212155Sandreas.sandberg@arm.com     * Get a pointer to the event queue owning devices.
42312155Sandreas.sandberg@arm.com     *
42412155Sandreas.sandberg@arm.com     * Devices always live in a separate device event queue when
42512155Sandreas.sandberg@arm.com     * running in multi-core mode. We need to temporarily migrate to
42612155Sandreas.sandberg@arm.com     * this queue when accessing devices. By convention, devices and
42712155Sandreas.sandberg@arm.com     * the VM use the same event queue.
42812155Sandreas.sandberg@arm.com     */
42912155Sandreas.sandberg@arm.com    EventQueue *deviceEventQueue() { return vm.eventQueue(); }
43012155Sandreas.sandberg@arm.com
43112155Sandreas.sandberg@arm.com    /**
4329652SAndreas.Sandberg@ARM.com     * Update the KVM if the thread context is dirty.
4339652SAndreas.Sandberg@ARM.com     */
4349652SAndreas.Sandberg@ARM.com    void syncKvmState();
4359651SAndreas.Sandberg@ARM.com    /** @} */
4369651SAndreas.Sandberg@ARM.com
4379651SAndreas.Sandberg@ARM.com    /** @{ */
4389651SAndreas.Sandberg@ARM.com    /**
4399651SAndreas.Sandberg@ARM.com     * Main kvmRun exit handler, calls the relevant handleKvmExit*
4409651SAndreas.Sandberg@ARM.com     * depending on exit type.
4419651SAndreas.Sandberg@ARM.com     *
4429651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the exit request
4439651SAndreas.Sandberg@ARM.com     */
4449651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExit();
4459651SAndreas.Sandberg@ARM.com
4469651SAndreas.Sandberg@ARM.com    /**
4479651SAndreas.Sandberg@ARM.com     * The guest performed a legacy IO request (out/inp on x86)
4489651SAndreas.Sandberg@ARM.com     *
4499651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the IO request
4509651SAndreas.Sandberg@ARM.com     */
4519651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitIO();
4529651SAndreas.Sandberg@ARM.com
4539651SAndreas.Sandberg@ARM.com    /**
4549651SAndreas.Sandberg@ARM.com     * The guest requested a monitor service using a hypercall
4559651SAndreas.Sandberg@ARM.com     *
4569651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the hypercall
4579651SAndreas.Sandberg@ARM.com     */
4589651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitHypercall();
4599651SAndreas.Sandberg@ARM.com
4609651SAndreas.Sandberg@ARM.com    /**
4619651SAndreas.Sandberg@ARM.com     * The guest exited because an interrupt window was requested
4629651SAndreas.Sandberg@ARM.com     *
4639651SAndreas.Sandberg@ARM.com     * The guest exited because an interrupt window was requested
4649651SAndreas.Sandberg@ARM.com     * (request_interrupt_window in the kvm_run structure was set to 1
4659651SAndreas.Sandberg@ARM.com     * before calling kvmRun) and it is now ready to receive
4669651SAndreas.Sandberg@ARM.com     *
4679651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the IRQ
4689651SAndreas.Sandberg@ARM.com     */
4699651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitIRQWindowOpen();
4709651SAndreas.Sandberg@ARM.com
4719651SAndreas.Sandberg@ARM.com    /**
4729651SAndreas.Sandberg@ARM.com     * An unknown architecture dependent error occurred when starting
4739651SAndreas.Sandberg@ARM.com     * the vCPU
4749651SAndreas.Sandberg@ARM.com     *
4759651SAndreas.Sandberg@ARM.com     * The kvm_run data structure contains the hardware error
4769651SAndreas.Sandberg@ARM.com     * code. The defaults behavior of this method just prints the HW
4779651SAndreas.Sandberg@ARM.com     * error code and panics. Architecture dependent implementations
4789651SAndreas.Sandberg@ARM.com     * may want to override this method to provide better,
4799651SAndreas.Sandberg@ARM.com     * hardware-aware, error messages.
4809651SAndreas.Sandberg@ARM.com     *
4819651SAndreas.Sandberg@ARM.com     * @return Number of ticks delay the next CPU tick
4829651SAndreas.Sandberg@ARM.com     */
4839651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitUnknown();
4849651SAndreas.Sandberg@ARM.com
4859651SAndreas.Sandberg@ARM.com    /**
4869651SAndreas.Sandberg@ARM.com     * An unhandled virtualization exception occured
4879651SAndreas.Sandberg@ARM.com     *
4889651SAndreas.Sandberg@ARM.com     * Some KVM virtualization drivers return unhandled exceptions to
4899651SAndreas.Sandberg@ARM.com     * the user-space monitor. This interface is currently only used
4909651SAndreas.Sandberg@ARM.com     * by the Intel VMX KVM driver.
4919651SAndreas.Sandberg@ARM.com     *
4929651SAndreas.Sandberg@ARM.com     * @return Number of ticks delay the next CPU tick
4939651SAndreas.Sandberg@ARM.com     */
4949651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitException();
4959651SAndreas.Sandberg@ARM.com
4969651SAndreas.Sandberg@ARM.com    /**
4979651SAndreas.Sandberg@ARM.com     * KVM failed to start the virtualized CPU
4989651SAndreas.Sandberg@ARM.com     *
4999651SAndreas.Sandberg@ARM.com     * The kvm_run data structure contains the hardware-specific error
5009651SAndreas.Sandberg@ARM.com     * code.
5019651SAndreas.Sandberg@ARM.com     *
5029651SAndreas.Sandberg@ARM.com     * @return Number of ticks delay the next CPU tick
5039651SAndreas.Sandberg@ARM.com     */
5049651SAndreas.Sandberg@ARM.com    virtual Tick handleKvmExitFailEntry();
5059651SAndreas.Sandberg@ARM.com    /** @} */
5069651SAndreas.Sandberg@ARM.com
5079651SAndreas.Sandberg@ARM.com    /**
5089753Sandreas@sandberg.pp.se     * Is the architecture specific code in a state that prevents
5099753Sandreas@sandberg.pp.se     * draining?
5109753Sandreas@sandberg.pp.se     *
5119753Sandreas@sandberg.pp.se     * This method should return false if there are any pending events
5129753Sandreas@sandberg.pp.se     * in the guest vCPU that won't be carried over to the gem5 state
5139753Sandreas@sandberg.pp.se     * and thus will prevent correct checkpointing or CPU handover. It
5149753Sandreas@sandberg.pp.se     * might, for example, check for pending interrupts that have been
5159753Sandreas@sandberg.pp.se     * passed to the vCPU but not acknowledged by the OS. Architecures
5169753Sandreas@sandberg.pp.se     * implementing this method <i>must</i> override
5179753Sandreas@sandberg.pp.se     * kvmRunDrain().
5189753Sandreas@sandberg.pp.se     *
5199753Sandreas@sandberg.pp.se     * @see BaseKvmCPU::kvmRunDrain()
5209753Sandreas@sandberg.pp.se     *
5219753Sandreas@sandberg.pp.se     * @return true if the vCPU is drained, false otherwise.
5229753Sandreas@sandberg.pp.se     */
5239753Sandreas@sandberg.pp.se    virtual bool archIsDrained() const { return true; }
5249753Sandreas@sandberg.pp.se
5259753Sandreas@sandberg.pp.se    /**
5269651SAndreas.Sandberg@ARM.com     * Inject a memory mapped IO request into gem5
5279651SAndreas.Sandberg@ARM.com     *
5289651SAndreas.Sandberg@ARM.com     * @param paddr Physical address
5299651SAndreas.Sandberg@ARM.com     * @param data Pointer to the source/destination buffer
5309651SAndreas.Sandberg@ARM.com     * @param size Memory access size
5319651SAndreas.Sandberg@ARM.com     * @param write True if write, False if read
5329651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the memory access
5339651SAndreas.Sandberg@ARM.com     */
5349651SAndreas.Sandberg@ARM.com    Tick doMMIOAccess(Addr paddr, void *data, int size, bool write);
5359651SAndreas.Sandberg@ARM.com
5369753Sandreas@sandberg.pp.se    /** @{ */
5379753Sandreas@sandberg.pp.se    /**
5389753Sandreas@sandberg.pp.se     * Set the signal mask used in kvmRun()
5399753Sandreas@sandberg.pp.se     *
5409753Sandreas@sandberg.pp.se     * This method allows the signal mask of the thread executing
5419753Sandreas@sandberg.pp.se     * kvmRun() to be overridden inside the actual system call. This
5429753Sandreas@sandberg.pp.se     * allows us to mask timer signals used to force KVM exits while
5439753Sandreas@sandberg.pp.se     * in gem5.
5449753Sandreas@sandberg.pp.se     *
5459753Sandreas@sandberg.pp.se     * The signal mask can be disabled by setting it to NULL.
5469753Sandreas@sandberg.pp.se     *
5479753Sandreas@sandberg.pp.se     * @param mask Signals to mask
5489753Sandreas@sandberg.pp.se     */
5499753Sandreas@sandberg.pp.se    void setSignalMask(const sigset_t *mask);
5509753Sandreas@sandberg.pp.se    /** @} */
5519651SAndreas.Sandberg@ARM.com
5529651SAndreas.Sandberg@ARM.com    /**
5539651SAndreas.Sandberg@ARM.com     * @addtogroup KvmIoctl
5549651SAndreas.Sandberg@ARM.com     * @{
5559651SAndreas.Sandberg@ARM.com     */
5569651SAndreas.Sandberg@ARM.com    /**
5579651SAndreas.Sandberg@ARM.com     * vCPU ioctl interface.
5589651SAndreas.Sandberg@ARM.com     *
5599651SAndreas.Sandberg@ARM.com     * @param request KVM vCPU request
5609651SAndreas.Sandberg@ARM.com     * @param p1 Optional request parameter
5619651SAndreas.Sandberg@ARM.com     *
5629651SAndreas.Sandberg@ARM.com     * @return -1 on error (error number in errno), ioctl dependent
5639651SAndreas.Sandberg@ARM.com     * value otherwise.
5649651SAndreas.Sandberg@ARM.com     */
5659651SAndreas.Sandberg@ARM.com    int ioctl(int request, long p1) const;
5669651SAndreas.Sandberg@ARM.com    int ioctl(int request, void *p1) const {
5679651SAndreas.Sandberg@ARM.com        return ioctl(request, (long)p1);
5689651SAndreas.Sandberg@ARM.com    }
5699651SAndreas.Sandberg@ARM.com    int ioctl(int request) const {
5709651SAndreas.Sandberg@ARM.com        return ioctl(request, 0L);
5719651SAndreas.Sandberg@ARM.com    }
5729651SAndreas.Sandberg@ARM.com    /** @} */
5739651SAndreas.Sandberg@ARM.com
5749688Sandreas@sandberg.pp.se
5759688Sandreas@sandberg.pp.se    /**
57611629Smichael.lebeane@amd.com     * KVM memory port.  Uses default MasterPort behavior and provides an
57711629Smichael.lebeane@amd.com     * interface for KVM to transparently submit atomic or timing requests.
5789688Sandreas@sandberg.pp.se     */
5799688Sandreas@sandberg.pp.se    class KVMCpuPort : public MasterPort
5809688Sandreas@sandberg.pp.se    {
5819688Sandreas@sandberg.pp.se
5829688Sandreas@sandberg.pp.se      public:
5839688Sandreas@sandberg.pp.se        KVMCpuPort(const std::string &_name, BaseKvmCPU *_cpu)
58411629Smichael.lebeane@amd.com            : MasterPort(_name, _cpu), cpu(_cpu), activeMMIOReqs(0)
5859688Sandreas@sandberg.pp.se        { }
58611629Smichael.lebeane@amd.com        /**
58711629Smichael.lebeane@amd.com         * Interface to send Atomic or Timing IO request.  Assumes that the pkt
58811629Smichael.lebeane@amd.com         * and corresponding req have been dynamically allocated and deletes
58911629Smichael.lebeane@amd.com         * them both if the system is in atomic mode.
59011629Smichael.lebeane@amd.com         */
59111629Smichael.lebeane@amd.com        Tick submitIO(PacketPtr pkt);
59211629Smichael.lebeane@amd.com
59311629Smichael.lebeane@amd.com        /** Returns next valid state after one or more IO accesses */
59411629Smichael.lebeane@amd.com        Status nextIOState() const;
5959688Sandreas@sandberg.pp.se
5969688Sandreas@sandberg.pp.se      protected:
59711629Smichael.lebeane@amd.com        /** KVM cpu pointer for finishMMIOPending() callback */
59811629Smichael.lebeane@amd.com        BaseKvmCPU *cpu;
5999688Sandreas@sandberg.pp.se
60011629Smichael.lebeane@amd.com        /** Pending MMIO packets */
60111629Smichael.lebeane@amd.com        std::queue<PacketPtr> pendingMMIOPkts;
60211629Smichael.lebeane@amd.com
60311629Smichael.lebeane@amd.com        /** Number of MMIO requests in flight */
60411629Smichael.lebeane@amd.com        unsigned int activeMMIOReqs;
60511629Smichael.lebeane@amd.com
60611629Smichael.lebeane@amd.com        bool recvTimingResp(PacketPtr pkt) override;
60711629Smichael.lebeane@amd.com
60811629Smichael.lebeane@amd.com        void recvReqRetry() override;
6099688Sandreas@sandberg.pp.se
6109688Sandreas@sandberg.pp.se    };
6119688Sandreas@sandberg.pp.se
6129651SAndreas.Sandberg@ARM.com    /** Port for data requests */
6139688Sandreas@sandberg.pp.se    KVMCpuPort dataPort;
6149651SAndreas.Sandberg@ARM.com
6159651SAndreas.Sandberg@ARM.com    /** Unused dummy port for the instruction interface */
6169688Sandreas@sandberg.pp.se    KVMCpuPort instPort;
6179651SAndreas.Sandberg@ARM.com
6189651SAndreas.Sandberg@ARM.com    /**
61911399Sandreas.sandberg@arm.com     * Be conservative and always synchronize the thread context on
62011399Sandreas.sandberg@arm.com     * KVM entry/exit.
62111399Sandreas.sandberg@arm.com     */
62211399Sandreas.sandberg@arm.com    const bool alwaysSyncTC;
62311399Sandreas.sandberg@arm.com
62411399Sandreas.sandberg@arm.com    /**
6259651SAndreas.Sandberg@ARM.com     * Is the gem5 context dirty? Set to true to force an update of
6269651SAndreas.Sandberg@ARM.com     * the KVM vCPU state upon the next call to kvmRun().
6279651SAndreas.Sandberg@ARM.com     */
6289652SAndreas.Sandberg@ARM.com    bool threadContextDirty;
6299652SAndreas.Sandberg@ARM.com
6309652SAndreas.Sandberg@ARM.com    /**
6319652SAndreas.Sandberg@ARM.com     * Is the KVM state dirty? Set to true to force an update of
6329652SAndreas.Sandberg@ARM.com     * the KVM vCPU state upon the next call to kvmRun().
6339652SAndreas.Sandberg@ARM.com     */
6349652SAndreas.Sandberg@ARM.com    bool kvmStateDirty;
6359651SAndreas.Sandberg@ARM.com
6369651SAndreas.Sandberg@ARM.com    /** KVM internal ID of the vCPU */
6379651SAndreas.Sandberg@ARM.com    const long vcpuID;
6389651SAndreas.Sandberg@ARM.com
63910114Sandreas@sandberg.pp.se    /** ID of the vCPU thread */
64010114Sandreas@sandberg.pp.se    pthread_t vcpuThread;
64110114Sandreas@sandberg.pp.se
6429651SAndreas.Sandberg@ARM.com  private:
6439651SAndreas.Sandberg@ARM.com    /**
6449651SAndreas.Sandberg@ARM.com     * Service MMIO requests in the mmioRing.
6459651SAndreas.Sandberg@ARM.com     *
6469651SAndreas.Sandberg@ARM.com     *
6479651SAndreas.Sandberg@ARM.com     * @return Number of ticks spent servicing the MMIO requests in
6489651SAndreas.Sandberg@ARM.com     * the MMIO ring buffer
6499651SAndreas.Sandberg@ARM.com     */
6509651SAndreas.Sandberg@ARM.com    Tick flushCoalescedMMIO();
6519651SAndreas.Sandberg@ARM.com
6529651SAndreas.Sandberg@ARM.com    /**
6539651SAndreas.Sandberg@ARM.com     * Setup a signal handler to catch the timer signal used to
6549651SAndreas.Sandberg@ARM.com     * switch back to the monitor.
6559651SAndreas.Sandberg@ARM.com     */
6569651SAndreas.Sandberg@ARM.com    void setupSignalHandler();
6579651SAndreas.Sandberg@ARM.com
6589753Sandreas@sandberg.pp.se    /**
6599753Sandreas@sandberg.pp.se     * Discard a (potentially) pending signal.
6609753Sandreas@sandberg.pp.se     *
6619753Sandreas@sandberg.pp.se     * @param signum Signal to discard
6629753Sandreas@sandberg.pp.se     * @return true if the signal was pending, false otherwise.
6639753Sandreas@sandberg.pp.se     */
6649753Sandreas@sandberg.pp.se    bool discardPendingSignal(int signum) const;
6659753Sandreas@sandberg.pp.se
66610073Sandreas@sandberg.pp.se    /**
66710073Sandreas@sandberg.pp.se     * Thread-specific initialization.
66810073Sandreas@sandberg.pp.se     *
66910073Sandreas@sandberg.pp.se     * Some KVM-related initialization requires us to know the TID of
67010073Sandreas@sandberg.pp.se     * the thread that is going to execute our event queue. For
67110073Sandreas@sandberg.pp.se     * example, when setting up timers, we need to know the TID of the
67210073Sandreas@sandberg.pp.se     * thread executing in KVM in order to deliver the timer signal to
67310073Sandreas@sandberg.pp.se     * that thread. This method is called as the first event in this
67410073Sandreas@sandberg.pp.se     * SimObject's event queue.
67510073Sandreas@sandberg.pp.se     *
67610073Sandreas@sandberg.pp.se     * @see startup
67710073Sandreas@sandberg.pp.se     */
67810073Sandreas@sandberg.pp.se    void startupThread();
67910073Sandreas@sandberg.pp.se
6809753Sandreas@sandberg.pp.se    /** Try to drain the CPU if a drain is pending */
6819753Sandreas@sandberg.pp.se    bool tryDrain();
6829753Sandreas@sandberg.pp.se
6839753Sandreas@sandberg.pp.se    /** Execute the KVM_RUN ioctl */
6849753Sandreas@sandberg.pp.se    void ioctlRun();
6859753Sandreas@sandberg.pp.se
6869651SAndreas.Sandberg@ARM.com    /** KVM vCPU file descriptor */
6879651SAndreas.Sandberg@ARM.com    int vcpuFD;
6889651SAndreas.Sandberg@ARM.com    /** Size of MMAPed kvm_run area */
6899651SAndreas.Sandberg@ARM.com    int vcpuMMapSize;
6909651SAndreas.Sandberg@ARM.com    /**
6919651SAndreas.Sandberg@ARM.com     * Pointer to the kvm_run structure used to communicate parameters
6929651SAndreas.Sandberg@ARM.com     * with KVM.
6939651SAndreas.Sandberg@ARM.com     *
6949651SAndreas.Sandberg@ARM.com     * @note This is the base pointer of the MMAPed KVM region. The
6959651SAndreas.Sandberg@ARM.com     * first page contains the kvm_run structure. Subsequent pages may
6969651SAndreas.Sandberg@ARM.com     * contain other data such as the MMIO ring buffer.
6979651SAndreas.Sandberg@ARM.com     */
6989651SAndreas.Sandberg@ARM.com    struct kvm_run *_kvmRun;
6999651SAndreas.Sandberg@ARM.com    /**
7009651SAndreas.Sandberg@ARM.com     * Coalesced MMIO ring buffer. NULL if coalesced MMIO is not
7019651SAndreas.Sandberg@ARM.com     * supported.
7029651SAndreas.Sandberg@ARM.com     */
7039651SAndreas.Sandberg@ARM.com    struct kvm_coalesced_mmio_ring *mmioRing;
7049651SAndreas.Sandberg@ARM.com    /** Cached page size of the host */
7059651SAndreas.Sandberg@ARM.com    const long pageSize;
7069651SAndreas.Sandberg@ARM.com
70712128Sspwilson2@wisc.edu    EventFunctionWrapper tickEvent;
7089651SAndreas.Sandberg@ARM.com
7099892Sandreas@sandberg.pp.se    /**
7109892Sandreas@sandberg.pp.se     * Setup an instruction break if there is one pending.
7119892Sandreas@sandberg.pp.se     *
7129892Sandreas@sandberg.pp.se     * Check if there are pending instruction breaks in the CPU's
7139892Sandreas@sandberg.pp.se     * instruction event queue and schedule an instruction break using
7149892Sandreas@sandberg.pp.se     * PerfEvent.
7159892Sandreas@sandberg.pp.se     *
7169892Sandreas@sandberg.pp.se     * @note This method doesn't currently handle the main system
7179892Sandreas@sandberg.pp.se     * instruction event queue.
7189892Sandreas@sandberg.pp.se     */
7199892Sandreas@sandberg.pp.se    void setupInstStop();
7209892Sandreas@sandberg.pp.se
7219651SAndreas.Sandberg@ARM.com    /** @{ */
7229892Sandreas@sandberg.pp.se    /** Setup hardware performance counters */
7239892Sandreas@sandberg.pp.se    void setupCounters();
7249892Sandreas@sandberg.pp.se
7259892Sandreas@sandberg.pp.se    /**
7269892Sandreas@sandberg.pp.se     * Setup the guest instruction counter.
7279892Sandreas@sandberg.pp.se     *
7289892Sandreas@sandberg.pp.se     * Setup the guest instruction counter and optionally request a
7299892Sandreas@sandberg.pp.se     * signal every N instructions executed by the guest. This method
7309892Sandreas@sandberg.pp.se     * will re-attach the counter if the counter has already been
7319892Sandreas@sandberg.pp.se     * attached and its sampling settings have changed.
7329892Sandreas@sandberg.pp.se     *
7339892Sandreas@sandberg.pp.se     * @param period Signal period, set to 0 to disable signaling.
7349892Sandreas@sandberg.pp.se     */
7359892Sandreas@sandberg.pp.se    void setupInstCounter(uint64_t period = 0);
7369892Sandreas@sandberg.pp.se
7379892Sandreas@sandberg.pp.se    /** Currently active instruction count breakpoint */
7389892Sandreas@sandberg.pp.se    uint64_t activeInstPeriod;
7399892Sandreas@sandberg.pp.se
7409892Sandreas@sandberg.pp.se    /**
7419892Sandreas@sandberg.pp.se     * Guest cycle counter.
7429892Sandreas@sandberg.pp.se     *
7439892Sandreas@sandberg.pp.se     * This is the group leader of all performance counters measuring
7449892Sandreas@sandberg.pp.se     * the guest system. It can be used in conjunction with the
7459892Sandreas@sandberg.pp.se     * PerfKvmTimer (see perfControlledByTimer) to trigger exits from
7469892Sandreas@sandberg.pp.se     * KVM.
7479892Sandreas@sandberg.pp.se     */
7489651SAndreas.Sandberg@ARM.com    PerfKvmCounter hwCycles;
7499892Sandreas@sandberg.pp.se
7509892Sandreas@sandberg.pp.se    /**
7519892Sandreas@sandberg.pp.se     * Guest instruction counter.
7529892Sandreas@sandberg.pp.se     *
7539892Sandreas@sandberg.pp.se     * This counter is typically only used to measure the number of
7549892Sandreas@sandberg.pp.se     * instructions executed by the guest. However, it can also be
7559892Sandreas@sandberg.pp.se     * used to trigger exits from KVM if the configuration script
7569892Sandreas@sandberg.pp.se     * requests an exit after a certain number of instructions.
7579892Sandreas@sandberg.pp.se     *
7589892Sandreas@sandberg.pp.se     * @see setupInstBreak
7599892Sandreas@sandberg.pp.se     * @see scheduleInstStop
7609892Sandreas@sandberg.pp.se     */
7619651SAndreas.Sandberg@ARM.com    PerfKvmCounter hwInstructions;
7629651SAndreas.Sandberg@ARM.com
7639651SAndreas.Sandberg@ARM.com    /**
7649655SAndreas.Sandberg@ARM.com     * Does the runTimer control the performance counters?
7659655SAndreas.Sandberg@ARM.com     *
7669655SAndreas.Sandberg@ARM.com     * The run timer will automatically enable and disable performance
7679655SAndreas.Sandberg@ARM.com     * counters if a PerfEvent-based timer is used to control KVM
7689655SAndreas.Sandberg@ARM.com     * exits.
7699655SAndreas.Sandberg@ARM.com     */
7709655SAndreas.Sandberg@ARM.com    bool perfControlledByTimer;
7719892Sandreas@sandberg.pp.se    /** @} */
7729655SAndreas.Sandberg@ARM.com
7739655SAndreas.Sandberg@ARM.com    /**
7749651SAndreas.Sandberg@ARM.com     * Timer used to force execution into the monitor after a
7759651SAndreas.Sandberg@ARM.com     * specified number of simulation tick equivalents have executed
7769651SAndreas.Sandberg@ARM.com     * in the guest. This counter generates the signal specified by
7779651SAndreas.Sandberg@ARM.com     * KVM_TIMER_SIGNAL.
7789651SAndreas.Sandberg@ARM.com     */
7799651SAndreas.Sandberg@ARM.com    std::unique_ptr<BaseKvmTimer> runTimer;
7809651SAndreas.Sandberg@ARM.com
7819754Sandreas@sandberg.pp.se    /** Host factor as specified in the configuration */
7829651SAndreas.Sandberg@ARM.com    float hostFactor;
7839651SAndreas.Sandberg@ARM.com
7849651SAndreas.Sandberg@ARM.com  public:
7859651SAndreas.Sandberg@ARM.com    /* @{ */
7869684Sandreas@sandberg.pp.se    Stats::Scalar numInsts;
7879651SAndreas.Sandberg@ARM.com    Stats::Scalar numVMExits;
7889755Sandreas@sandberg.pp.se    Stats::Scalar numVMHalfEntries;
7899755Sandreas@sandberg.pp.se    Stats::Scalar numExitSignal;
7909651SAndreas.Sandberg@ARM.com    Stats::Scalar numMMIO;
7919651SAndreas.Sandberg@ARM.com    Stats::Scalar numCoalescedMMIO;
7929651SAndreas.Sandberg@ARM.com    Stats::Scalar numIO;
7939651SAndreas.Sandberg@ARM.com    Stats::Scalar numHalt;
7949651SAndreas.Sandberg@ARM.com    Stats::Scalar numInterrupts;
7959651SAndreas.Sandberg@ARM.com    Stats::Scalar numHypercalls;
7969651SAndreas.Sandberg@ARM.com    /* @} */
7979752Sandreas@sandberg.pp.se
7989752Sandreas@sandberg.pp.se    /** Number of instructions executed by the CPU */
7999752Sandreas@sandberg.pp.se    Counter ctrInsts;
8009651SAndreas.Sandberg@ARM.com};
8019651SAndreas.Sandberg@ARM.com
8029651SAndreas.Sandberg@ARM.com#endif
803