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