base.hh revision 11943
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 10011341Sandreas.hansson@arm.com MasterPort &getDataPort() override { return dataPort; } 10111341Sandreas.hansson@arm.com MasterPort &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 ®s) const; 3499651SAndreas.Sandberg@ARM.com void setRegisters(const struct kvm_regs ®s); 3509651SAndreas.Sandberg@ARM.com void getSpecialRegisters(struct kvm_sregs ®s) const; 3519651SAndreas.Sandberg@ARM.com void setSpecialRegisters(const struct kvm_sregs ®s); 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 /** 4229652SAndreas.Sandberg@ARM.com * Update the KVM if the thread context is dirty. 4239652SAndreas.Sandberg@ARM.com */ 4249652SAndreas.Sandberg@ARM.com void syncKvmState(); 4259651SAndreas.Sandberg@ARM.com /** @} */ 4269651SAndreas.Sandberg@ARM.com 4279651SAndreas.Sandberg@ARM.com /** @{ */ 4289651SAndreas.Sandberg@ARM.com /** 4299651SAndreas.Sandberg@ARM.com * Main kvmRun exit handler, calls the relevant handleKvmExit* 4309651SAndreas.Sandberg@ARM.com * depending on exit type. 4319651SAndreas.Sandberg@ARM.com * 4329651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the exit request 4339651SAndreas.Sandberg@ARM.com */ 4349651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExit(); 4359651SAndreas.Sandberg@ARM.com 4369651SAndreas.Sandberg@ARM.com /** 4379651SAndreas.Sandberg@ARM.com * The guest performed a legacy IO request (out/inp on x86) 4389651SAndreas.Sandberg@ARM.com * 4399651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the IO request 4409651SAndreas.Sandberg@ARM.com */ 4419651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitIO(); 4429651SAndreas.Sandberg@ARM.com 4439651SAndreas.Sandberg@ARM.com /** 4449651SAndreas.Sandberg@ARM.com * The guest requested a monitor service using a hypercall 4459651SAndreas.Sandberg@ARM.com * 4469651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the hypercall 4479651SAndreas.Sandberg@ARM.com */ 4489651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitHypercall(); 4499651SAndreas.Sandberg@ARM.com 4509651SAndreas.Sandberg@ARM.com /** 4519651SAndreas.Sandberg@ARM.com * The guest exited because an interrupt window was requested 4529651SAndreas.Sandberg@ARM.com * 4539651SAndreas.Sandberg@ARM.com * The guest exited because an interrupt window was requested 4549651SAndreas.Sandberg@ARM.com * (request_interrupt_window in the kvm_run structure was set to 1 4559651SAndreas.Sandberg@ARM.com * before calling kvmRun) and it is now ready to receive 4569651SAndreas.Sandberg@ARM.com * 4579651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the IRQ 4589651SAndreas.Sandberg@ARM.com */ 4599651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitIRQWindowOpen(); 4609651SAndreas.Sandberg@ARM.com 4619651SAndreas.Sandberg@ARM.com /** 4629651SAndreas.Sandberg@ARM.com * An unknown architecture dependent error occurred when starting 4639651SAndreas.Sandberg@ARM.com * the vCPU 4649651SAndreas.Sandberg@ARM.com * 4659651SAndreas.Sandberg@ARM.com * The kvm_run data structure contains the hardware error 4669651SAndreas.Sandberg@ARM.com * code. The defaults behavior of this method just prints the HW 4679651SAndreas.Sandberg@ARM.com * error code and panics. Architecture dependent implementations 4689651SAndreas.Sandberg@ARM.com * may want to override this method to provide better, 4699651SAndreas.Sandberg@ARM.com * hardware-aware, error messages. 4709651SAndreas.Sandberg@ARM.com * 4719651SAndreas.Sandberg@ARM.com * @return Number of ticks delay the next CPU tick 4729651SAndreas.Sandberg@ARM.com */ 4739651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitUnknown(); 4749651SAndreas.Sandberg@ARM.com 4759651SAndreas.Sandberg@ARM.com /** 4769651SAndreas.Sandberg@ARM.com * An unhandled virtualization exception occured 4779651SAndreas.Sandberg@ARM.com * 4789651SAndreas.Sandberg@ARM.com * Some KVM virtualization drivers return unhandled exceptions to 4799651SAndreas.Sandberg@ARM.com * the user-space monitor. This interface is currently only used 4809651SAndreas.Sandberg@ARM.com * by the Intel VMX KVM driver. 4819651SAndreas.Sandberg@ARM.com * 4829651SAndreas.Sandberg@ARM.com * @return Number of ticks delay the next CPU tick 4839651SAndreas.Sandberg@ARM.com */ 4849651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitException(); 4859651SAndreas.Sandberg@ARM.com 4869651SAndreas.Sandberg@ARM.com /** 4879651SAndreas.Sandberg@ARM.com * KVM failed to start the virtualized CPU 4889651SAndreas.Sandberg@ARM.com * 4899651SAndreas.Sandberg@ARM.com * The kvm_run data structure contains the hardware-specific error 4909651SAndreas.Sandberg@ARM.com * code. 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 handleKvmExitFailEntry(); 4959651SAndreas.Sandberg@ARM.com /** @} */ 4969651SAndreas.Sandberg@ARM.com 4979651SAndreas.Sandberg@ARM.com /** 4989753Sandreas@sandberg.pp.se * Is the architecture specific code in a state that prevents 4999753Sandreas@sandberg.pp.se * draining? 5009753Sandreas@sandberg.pp.se * 5019753Sandreas@sandberg.pp.se * This method should return false if there are any pending events 5029753Sandreas@sandberg.pp.se * in the guest vCPU that won't be carried over to the gem5 state 5039753Sandreas@sandberg.pp.se * and thus will prevent correct checkpointing or CPU handover. It 5049753Sandreas@sandberg.pp.se * might, for example, check for pending interrupts that have been 5059753Sandreas@sandberg.pp.se * passed to the vCPU but not acknowledged by the OS. Architecures 5069753Sandreas@sandberg.pp.se * implementing this method <i>must</i> override 5079753Sandreas@sandberg.pp.se * kvmRunDrain(). 5089753Sandreas@sandberg.pp.se * 5099753Sandreas@sandberg.pp.se * @see BaseKvmCPU::kvmRunDrain() 5109753Sandreas@sandberg.pp.se * 5119753Sandreas@sandberg.pp.se * @return true if the vCPU is drained, false otherwise. 5129753Sandreas@sandberg.pp.se */ 5139753Sandreas@sandberg.pp.se virtual bool archIsDrained() const { return true; } 5149753Sandreas@sandberg.pp.se 5159753Sandreas@sandberg.pp.se /** 5169651SAndreas.Sandberg@ARM.com * Inject a memory mapped IO request into gem5 5179651SAndreas.Sandberg@ARM.com * 5189651SAndreas.Sandberg@ARM.com * @param paddr Physical address 5199651SAndreas.Sandberg@ARM.com * @param data Pointer to the source/destination buffer 5209651SAndreas.Sandberg@ARM.com * @param size Memory access size 5219651SAndreas.Sandberg@ARM.com * @param write True if write, False if read 5229651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the memory access 5239651SAndreas.Sandberg@ARM.com */ 5249651SAndreas.Sandberg@ARM.com Tick doMMIOAccess(Addr paddr, void *data, int size, bool write); 5259651SAndreas.Sandberg@ARM.com 5269753Sandreas@sandberg.pp.se /** @{ */ 5279753Sandreas@sandberg.pp.se /** 5289753Sandreas@sandberg.pp.se * Set the signal mask used in kvmRun() 5299753Sandreas@sandberg.pp.se * 5309753Sandreas@sandberg.pp.se * This method allows the signal mask of the thread executing 5319753Sandreas@sandberg.pp.se * kvmRun() to be overridden inside the actual system call. This 5329753Sandreas@sandberg.pp.se * allows us to mask timer signals used to force KVM exits while 5339753Sandreas@sandberg.pp.se * in gem5. 5349753Sandreas@sandberg.pp.se * 5359753Sandreas@sandberg.pp.se * The signal mask can be disabled by setting it to NULL. 5369753Sandreas@sandberg.pp.se * 5379753Sandreas@sandberg.pp.se * @param mask Signals to mask 5389753Sandreas@sandberg.pp.se */ 5399753Sandreas@sandberg.pp.se void setSignalMask(const sigset_t *mask); 5409753Sandreas@sandberg.pp.se /** @} */ 5419651SAndreas.Sandberg@ARM.com 5429651SAndreas.Sandberg@ARM.com /** 5439651SAndreas.Sandberg@ARM.com * @addtogroup KvmIoctl 5449651SAndreas.Sandberg@ARM.com * @{ 5459651SAndreas.Sandberg@ARM.com */ 5469651SAndreas.Sandberg@ARM.com /** 5479651SAndreas.Sandberg@ARM.com * vCPU ioctl interface. 5489651SAndreas.Sandberg@ARM.com * 5499651SAndreas.Sandberg@ARM.com * @param request KVM vCPU request 5509651SAndreas.Sandberg@ARM.com * @param p1 Optional request parameter 5519651SAndreas.Sandberg@ARM.com * 5529651SAndreas.Sandberg@ARM.com * @return -1 on error (error number in errno), ioctl dependent 5539651SAndreas.Sandberg@ARM.com * value otherwise. 5549651SAndreas.Sandberg@ARM.com */ 5559651SAndreas.Sandberg@ARM.com int ioctl(int request, long p1) const; 5569651SAndreas.Sandberg@ARM.com int ioctl(int request, void *p1) const { 5579651SAndreas.Sandberg@ARM.com return ioctl(request, (long)p1); 5589651SAndreas.Sandberg@ARM.com } 5599651SAndreas.Sandberg@ARM.com int ioctl(int request) const { 5609651SAndreas.Sandberg@ARM.com return ioctl(request, 0L); 5619651SAndreas.Sandberg@ARM.com } 5629651SAndreas.Sandberg@ARM.com /** @} */ 5639651SAndreas.Sandberg@ARM.com 5649688Sandreas@sandberg.pp.se 5659688Sandreas@sandberg.pp.se /** 56611629Smichael.lebeane@amd.com * KVM memory port. Uses default MasterPort behavior and provides an 56711629Smichael.lebeane@amd.com * interface for KVM to transparently submit atomic or timing requests. 5689688Sandreas@sandberg.pp.se */ 5699688Sandreas@sandberg.pp.se class KVMCpuPort : public MasterPort 5709688Sandreas@sandberg.pp.se { 5719688Sandreas@sandberg.pp.se 5729688Sandreas@sandberg.pp.se public: 5739688Sandreas@sandberg.pp.se KVMCpuPort(const std::string &_name, BaseKvmCPU *_cpu) 57411629Smichael.lebeane@amd.com : MasterPort(_name, _cpu), cpu(_cpu), activeMMIOReqs(0) 5759688Sandreas@sandberg.pp.se { } 57611629Smichael.lebeane@amd.com /** 57711629Smichael.lebeane@amd.com * Interface to send Atomic or Timing IO request. Assumes that the pkt 57811629Smichael.lebeane@amd.com * and corresponding req have been dynamically allocated and deletes 57911629Smichael.lebeane@amd.com * them both if the system is in atomic mode. 58011629Smichael.lebeane@amd.com */ 58111629Smichael.lebeane@amd.com Tick submitIO(PacketPtr pkt); 58211629Smichael.lebeane@amd.com 58311629Smichael.lebeane@amd.com /** Returns next valid state after one or more IO accesses */ 58411629Smichael.lebeane@amd.com Status nextIOState() const; 5859688Sandreas@sandberg.pp.se 5869688Sandreas@sandberg.pp.se protected: 58711629Smichael.lebeane@amd.com /** KVM cpu pointer for finishMMIOPending() callback */ 58811629Smichael.lebeane@amd.com BaseKvmCPU *cpu; 5899688Sandreas@sandberg.pp.se 59011629Smichael.lebeane@amd.com /** Pending MMIO packets */ 59111629Smichael.lebeane@amd.com std::queue<PacketPtr> pendingMMIOPkts; 59211629Smichael.lebeane@amd.com 59311629Smichael.lebeane@amd.com /** Number of MMIO requests in flight */ 59411629Smichael.lebeane@amd.com unsigned int activeMMIOReqs; 59511629Smichael.lebeane@amd.com 59611629Smichael.lebeane@amd.com bool recvTimingResp(PacketPtr pkt) override; 59711629Smichael.lebeane@amd.com 59811629Smichael.lebeane@amd.com void recvReqRetry() override; 5999688Sandreas@sandberg.pp.se 6009688Sandreas@sandberg.pp.se }; 6019688Sandreas@sandberg.pp.se 6029651SAndreas.Sandberg@ARM.com /** Port for data requests */ 6039688Sandreas@sandberg.pp.se KVMCpuPort dataPort; 6049651SAndreas.Sandberg@ARM.com 6059651SAndreas.Sandberg@ARM.com /** Unused dummy port for the instruction interface */ 6069688Sandreas@sandberg.pp.se KVMCpuPort instPort; 6079651SAndreas.Sandberg@ARM.com 6089651SAndreas.Sandberg@ARM.com /** 60911399Sandreas.sandberg@arm.com * Be conservative and always synchronize the thread context on 61011399Sandreas.sandberg@arm.com * KVM entry/exit. 61111399Sandreas.sandberg@arm.com */ 61211399Sandreas.sandberg@arm.com const bool alwaysSyncTC; 61311399Sandreas.sandberg@arm.com 61411399Sandreas.sandberg@arm.com /** 6159651SAndreas.Sandberg@ARM.com * Is the gem5 context dirty? Set to true to force an update of 6169651SAndreas.Sandberg@ARM.com * the KVM vCPU state upon the next call to kvmRun(). 6179651SAndreas.Sandberg@ARM.com */ 6189652SAndreas.Sandberg@ARM.com bool threadContextDirty; 6199652SAndreas.Sandberg@ARM.com 6209652SAndreas.Sandberg@ARM.com /** 6219652SAndreas.Sandberg@ARM.com * Is the KVM state dirty? Set to true to force an update of 6229652SAndreas.Sandberg@ARM.com * the KVM vCPU state upon the next call to kvmRun(). 6239652SAndreas.Sandberg@ARM.com */ 6249652SAndreas.Sandberg@ARM.com bool kvmStateDirty; 6259651SAndreas.Sandberg@ARM.com 6269651SAndreas.Sandberg@ARM.com /** KVM internal ID of the vCPU */ 6279651SAndreas.Sandberg@ARM.com const long vcpuID; 6289651SAndreas.Sandberg@ARM.com 62910114Sandreas@sandberg.pp.se /** ID of the vCPU thread */ 63010114Sandreas@sandberg.pp.se pthread_t vcpuThread; 63110114Sandreas@sandberg.pp.se 6329651SAndreas.Sandberg@ARM.com private: 6339651SAndreas.Sandberg@ARM.com struct TickEvent : public Event 6349651SAndreas.Sandberg@ARM.com { 6359651SAndreas.Sandberg@ARM.com BaseKvmCPU &cpu; 6369651SAndreas.Sandberg@ARM.com 6379651SAndreas.Sandberg@ARM.com TickEvent(BaseKvmCPU &c) 6389651SAndreas.Sandberg@ARM.com : Event(CPU_Tick_Pri), cpu(c) {} 6399651SAndreas.Sandberg@ARM.com 6409651SAndreas.Sandberg@ARM.com void process() { cpu.tick(); } 6419651SAndreas.Sandberg@ARM.com 6429651SAndreas.Sandberg@ARM.com const char *description() const { 6439651SAndreas.Sandberg@ARM.com return "BaseKvmCPU tick"; 6449651SAndreas.Sandberg@ARM.com } 6459651SAndreas.Sandberg@ARM.com }; 6469651SAndreas.Sandberg@ARM.com 6479651SAndreas.Sandberg@ARM.com /** 6489651SAndreas.Sandberg@ARM.com * Service MMIO requests in the mmioRing. 6499651SAndreas.Sandberg@ARM.com * 6509651SAndreas.Sandberg@ARM.com * 6519651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the MMIO requests in 6529651SAndreas.Sandberg@ARM.com * the MMIO ring buffer 6539651SAndreas.Sandberg@ARM.com */ 6549651SAndreas.Sandberg@ARM.com Tick flushCoalescedMMIO(); 6559651SAndreas.Sandberg@ARM.com 6569651SAndreas.Sandberg@ARM.com /** 6579651SAndreas.Sandberg@ARM.com * Setup a signal handler to catch the timer signal used to 6589651SAndreas.Sandberg@ARM.com * switch back to the monitor. 6599651SAndreas.Sandberg@ARM.com */ 6609651SAndreas.Sandberg@ARM.com void setupSignalHandler(); 6619651SAndreas.Sandberg@ARM.com 6629753Sandreas@sandberg.pp.se /** 6639753Sandreas@sandberg.pp.se * Discard a (potentially) pending signal. 6649753Sandreas@sandberg.pp.se * 6659753Sandreas@sandberg.pp.se * @param signum Signal to discard 6669753Sandreas@sandberg.pp.se * @return true if the signal was pending, false otherwise. 6679753Sandreas@sandberg.pp.se */ 6689753Sandreas@sandberg.pp.se bool discardPendingSignal(int signum) const; 6699753Sandreas@sandberg.pp.se 67010073Sandreas@sandberg.pp.se /** 67110073Sandreas@sandberg.pp.se * Thread-specific initialization. 67210073Sandreas@sandberg.pp.se * 67310073Sandreas@sandberg.pp.se * Some KVM-related initialization requires us to know the TID of 67410073Sandreas@sandberg.pp.se * the thread that is going to execute our event queue. For 67510073Sandreas@sandberg.pp.se * example, when setting up timers, we need to know the TID of the 67610073Sandreas@sandberg.pp.se * thread executing in KVM in order to deliver the timer signal to 67710073Sandreas@sandberg.pp.se * that thread. This method is called as the first event in this 67810073Sandreas@sandberg.pp.se * SimObject's event queue. 67910073Sandreas@sandberg.pp.se * 68010073Sandreas@sandberg.pp.se * @see startup 68110073Sandreas@sandberg.pp.se */ 68210073Sandreas@sandberg.pp.se void startupThread(); 68310073Sandreas@sandberg.pp.se 6849753Sandreas@sandberg.pp.se /** Try to drain the CPU if a drain is pending */ 6859753Sandreas@sandberg.pp.se bool tryDrain(); 6869753Sandreas@sandberg.pp.se 6879753Sandreas@sandberg.pp.se /** Execute the KVM_RUN ioctl */ 6889753Sandreas@sandberg.pp.se void ioctlRun(); 6899753Sandreas@sandberg.pp.se 6909651SAndreas.Sandberg@ARM.com /** KVM vCPU file descriptor */ 6919651SAndreas.Sandberg@ARM.com int vcpuFD; 6929651SAndreas.Sandberg@ARM.com /** Size of MMAPed kvm_run area */ 6939651SAndreas.Sandberg@ARM.com int vcpuMMapSize; 6949651SAndreas.Sandberg@ARM.com /** 6959651SAndreas.Sandberg@ARM.com * Pointer to the kvm_run structure used to communicate parameters 6969651SAndreas.Sandberg@ARM.com * with KVM. 6979651SAndreas.Sandberg@ARM.com * 6989651SAndreas.Sandberg@ARM.com * @note This is the base pointer of the MMAPed KVM region. The 6999651SAndreas.Sandberg@ARM.com * first page contains the kvm_run structure. Subsequent pages may 7009651SAndreas.Sandberg@ARM.com * contain other data such as the MMIO ring buffer. 7019651SAndreas.Sandberg@ARM.com */ 7029651SAndreas.Sandberg@ARM.com struct kvm_run *_kvmRun; 7039651SAndreas.Sandberg@ARM.com /** 7049651SAndreas.Sandberg@ARM.com * Coalesced MMIO ring buffer. NULL if coalesced MMIO is not 7059651SAndreas.Sandberg@ARM.com * supported. 7069651SAndreas.Sandberg@ARM.com */ 7079651SAndreas.Sandberg@ARM.com struct kvm_coalesced_mmio_ring *mmioRing; 7089651SAndreas.Sandberg@ARM.com /** Cached page size of the host */ 7099651SAndreas.Sandberg@ARM.com const long pageSize; 7109651SAndreas.Sandberg@ARM.com 7119651SAndreas.Sandberg@ARM.com TickEvent tickEvent; 7129651SAndreas.Sandberg@ARM.com 7139892Sandreas@sandberg.pp.se /** 7149892Sandreas@sandberg.pp.se * Setup an instruction break if there is one pending. 7159892Sandreas@sandberg.pp.se * 7169892Sandreas@sandberg.pp.se * Check if there are pending instruction breaks in the CPU's 7179892Sandreas@sandberg.pp.se * instruction event queue and schedule an instruction break using 7189892Sandreas@sandberg.pp.se * PerfEvent. 7199892Sandreas@sandberg.pp.se * 7209892Sandreas@sandberg.pp.se * @note This method doesn't currently handle the main system 7219892Sandreas@sandberg.pp.se * instruction event queue. 7229892Sandreas@sandberg.pp.se */ 7239892Sandreas@sandberg.pp.se void setupInstStop(); 7249892Sandreas@sandberg.pp.se 7259651SAndreas.Sandberg@ARM.com /** @{ */ 7269892Sandreas@sandberg.pp.se /** Setup hardware performance counters */ 7279892Sandreas@sandberg.pp.se void setupCounters(); 7289892Sandreas@sandberg.pp.se 7299892Sandreas@sandberg.pp.se /** 7309892Sandreas@sandberg.pp.se * Setup the guest instruction counter. 7319892Sandreas@sandberg.pp.se * 7329892Sandreas@sandberg.pp.se * Setup the guest instruction counter and optionally request a 7339892Sandreas@sandberg.pp.se * signal every N instructions executed by the guest. This method 7349892Sandreas@sandberg.pp.se * will re-attach the counter if the counter has already been 7359892Sandreas@sandberg.pp.se * attached and its sampling settings have changed. 7369892Sandreas@sandberg.pp.se * 7379892Sandreas@sandberg.pp.se * @param period Signal period, set to 0 to disable signaling. 7389892Sandreas@sandberg.pp.se */ 7399892Sandreas@sandberg.pp.se void setupInstCounter(uint64_t period = 0); 7409892Sandreas@sandberg.pp.se 7419892Sandreas@sandberg.pp.se /** Currently active instruction count breakpoint */ 7429892Sandreas@sandberg.pp.se uint64_t activeInstPeriod; 7439892Sandreas@sandberg.pp.se 7449892Sandreas@sandberg.pp.se /** 7459892Sandreas@sandberg.pp.se * Guest cycle counter. 7469892Sandreas@sandberg.pp.se * 7479892Sandreas@sandberg.pp.se * This is the group leader of all performance counters measuring 7489892Sandreas@sandberg.pp.se * the guest system. It can be used in conjunction with the 7499892Sandreas@sandberg.pp.se * PerfKvmTimer (see perfControlledByTimer) to trigger exits from 7509892Sandreas@sandberg.pp.se * KVM. 7519892Sandreas@sandberg.pp.se */ 7529651SAndreas.Sandberg@ARM.com PerfKvmCounter hwCycles; 7539892Sandreas@sandberg.pp.se 7549892Sandreas@sandberg.pp.se /** 7559892Sandreas@sandberg.pp.se * Guest instruction counter. 7569892Sandreas@sandberg.pp.se * 7579892Sandreas@sandberg.pp.se * This counter is typically only used to measure the number of 7589892Sandreas@sandberg.pp.se * instructions executed by the guest. However, it can also be 7599892Sandreas@sandberg.pp.se * used to trigger exits from KVM if the configuration script 7609892Sandreas@sandberg.pp.se * requests an exit after a certain number of instructions. 7619892Sandreas@sandberg.pp.se * 7629892Sandreas@sandberg.pp.se * @see setupInstBreak 7639892Sandreas@sandberg.pp.se * @see scheduleInstStop 7649892Sandreas@sandberg.pp.se */ 7659651SAndreas.Sandberg@ARM.com PerfKvmCounter hwInstructions; 7669651SAndreas.Sandberg@ARM.com 7679651SAndreas.Sandberg@ARM.com /** 7689655SAndreas.Sandberg@ARM.com * Does the runTimer control the performance counters? 7699655SAndreas.Sandberg@ARM.com * 7709655SAndreas.Sandberg@ARM.com * The run timer will automatically enable and disable performance 7719655SAndreas.Sandberg@ARM.com * counters if a PerfEvent-based timer is used to control KVM 7729655SAndreas.Sandberg@ARM.com * exits. 7739655SAndreas.Sandberg@ARM.com */ 7749655SAndreas.Sandberg@ARM.com bool perfControlledByTimer; 7759892Sandreas@sandberg.pp.se /** @} */ 7769655SAndreas.Sandberg@ARM.com 7779655SAndreas.Sandberg@ARM.com /** 7789651SAndreas.Sandberg@ARM.com * Timer used to force execution into the monitor after a 7799651SAndreas.Sandberg@ARM.com * specified number of simulation tick equivalents have executed 7809651SAndreas.Sandberg@ARM.com * in the guest. This counter generates the signal specified by 7819651SAndreas.Sandberg@ARM.com * KVM_TIMER_SIGNAL. 7829651SAndreas.Sandberg@ARM.com */ 7839651SAndreas.Sandberg@ARM.com std::unique_ptr<BaseKvmTimer> runTimer; 7849651SAndreas.Sandberg@ARM.com 7859754Sandreas@sandberg.pp.se /** Host factor as specified in the configuration */ 7869651SAndreas.Sandberg@ARM.com float hostFactor; 7879651SAndreas.Sandberg@ARM.com 7889651SAndreas.Sandberg@ARM.com public: 7899651SAndreas.Sandberg@ARM.com /* @{ */ 7909684Sandreas@sandberg.pp.se Stats::Scalar numInsts; 7919651SAndreas.Sandberg@ARM.com Stats::Scalar numVMExits; 7929755Sandreas@sandberg.pp.se Stats::Scalar numVMHalfEntries; 7939755Sandreas@sandberg.pp.se Stats::Scalar numExitSignal; 7949651SAndreas.Sandberg@ARM.com Stats::Scalar numMMIO; 7959651SAndreas.Sandberg@ARM.com Stats::Scalar numCoalescedMMIO; 7969651SAndreas.Sandberg@ARM.com Stats::Scalar numIO; 7979651SAndreas.Sandberg@ARM.com Stats::Scalar numHalt; 7989651SAndreas.Sandberg@ARM.com Stats::Scalar numInterrupts; 7999651SAndreas.Sandberg@ARM.com Stats::Scalar numHypercalls; 8009651SAndreas.Sandberg@ARM.com /* @} */ 8019752Sandreas@sandberg.pp.se 8029752Sandreas@sandberg.pp.se /** Number of instructions executed by the CPU */ 8039752Sandreas@sandberg.pp.se Counter ctrInsts; 8049651SAndreas.Sandberg@ARM.com}; 8059651SAndreas.Sandberg@ARM.com 8069651SAndreas.Sandberg@ARM.com#endif 807