base.hh revision 9735
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 969688Sandreas@sandberg.pp.se MasterPort &getDataPort() { return dataPort; } 979688Sandreas@sandberg.pp.se MasterPort &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 /** 1579735Sandreas@sandberg.pp.se * Get the value of the hardware cycle counter in the guest. 1589735Sandreas@sandberg.pp.se * 1599735Sandreas@sandberg.pp.se * This method is supposed to return the total number of cycles 1609735Sandreas@sandberg.pp.se * executed in hardware mode relative to some arbitrary point in 1619735Sandreas@sandberg.pp.se * the past. It's mainly used when estimating the number of cycles 1629735Sandreas@sandberg.pp.se * actually executed by the CPU in kvmRun(). The default behavior 1639735Sandreas@sandberg.pp.se * of this method is to use the cycles performance counter, but 1649735Sandreas@sandberg.pp.se * some architectures may want to use internal registers instead. 1659735Sandreas@sandberg.pp.se * 1669735Sandreas@sandberg.pp.se * @return Number of host cycles executed relative to an undefined 1679735Sandreas@sandberg.pp.se * point in the past. 1689735Sandreas@sandberg.pp.se */ 1699735Sandreas@sandberg.pp.se virtual uint64_t getHostCycles() const; 1709735Sandreas@sandberg.pp.se 1719735Sandreas@sandberg.pp.se /** 1729651SAndreas.Sandberg@ARM.com * Request KVM to run the guest for a given number of ticks. The 1739651SAndreas.Sandberg@ARM.com * method returns the approximate number of ticks executed. 1749651SAndreas.Sandberg@ARM.com * 1759651SAndreas.Sandberg@ARM.com * @note The returned number of ticks can be both larger or 1769651SAndreas.Sandberg@ARM.com * smaller than the requested number of ticks. A smaller number 1779651SAndreas.Sandberg@ARM.com * can, for example, occur when the guest executes MMIO. A larger 1789651SAndreas.Sandberg@ARM.com * number is typically due to performance counter inaccuracies. 1799651SAndreas.Sandberg@ARM.com * 1809651SAndreas.Sandberg@ARM.com * @param ticks Number of ticks to execute 1819651SAndreas.Sandberg@ARM.com * @return Number of ticks executed (see note) 1829651SAndreas.Sandberg@ARM.com */ 1839651SAndreas.Sandberg@ARM.com Tick kvmRun(Tick ticks); 1849651SAndreas.Sandberg@ARM.com 1859651SAndreas.Sandberg@ARM.com /** 1869651SAndreas.Sandberg@ARM.com * Get a pointer to the kvm_run structure containing all the input 1879651SAndreas.Sandberg@ARM.com * and output parameters from kvmRun(). 1889651SAndreas.Sandberg@ARM.com */ 1899651SAndreas.Sandberg@ARM.com struct kvm_run *getKvmRunState() { return _kvmRun; }; 1909651SAndreas.Sandberg@ARM.com 1919651SAndreas.Sandberg@ARM.com /** 1929651SAndreas.Sandberg@ARM.com * Retrieve a pointer to guest data stored at the end of the 1939651SAndreas.Sandberg@ARM.com * kvm_run structure. This is mainly used for PIO operations 1949651SAndreas.Sandberg@ARM.com * (KVM_EXIT_IO). 1959651SAndreas.Sandberg@ARM.com * 1969651SAndreas.Sandberg@ARM.com * @param offset Offset as specified by the kvm_run structure 1979651SAndreas.Sandberg@ARM.com * @return Pointer to guest data 1989651SAndreas.Sandberg@ARM.com */ 1999651SAndreas.Sandberg@ARM.com uint8_t *getGuestData(uint64_t offset) const { 2009651SAndreas.Sandberg@ARM.com return (uint8_t *)_kvmRun + offset; 2019651SAndreas.Sandberg@ARM.com }; 2029651SAndreas.Sandberg@ARM.com 2039651SAndreas.Sandberg@ARM.com /** 2049651SAndreas.Sandberg@ARM.com * @addtogroup KvmInterrupts 2059651SAndreas.Sandberg@ARM.com * @{ 2069651SAndreas.Sandberg@ARM.com */ 2079651SAndreas.Sandberg@ARM.com /** 2089651SAndreas.Sandberg@ARM.com * Send a non-maskable interrupt to the guest 2099651SAndreas.Sandberg@ARM.com * 2109651SAndreas.Sandberg@ARM.com * @note The presence of this call depends on Kvm::capUserNMI(). 2119651SAndreas.Sandberg@ARM.com */ 2129651SAndreas.Sandberg@ARM.com void kvmNonMaskableInterrupt(); 2139651SAndreas.Sandberg@ARM.com 2149651SAndreas.Sandberg@ARM.com /** 2159651SAndreas.Sandberg@ARM.com * Send a normal interrupt to the guest 2169651SAndreas.Sandberg@ARM.com * 2179651SAndreas.Sandberg@ARM.com * @note Make sure that ready_for_interrupt_injection in kvm_run 2189651SAndreas.Sandberg@ARM.com * is set prior to calling this function. If not, an interrupt 2199651SAndreas.Sandberg@ARM.com * window must be requested by setting request_interrupt_window in 2209651SAndreas.Sandberg@ARM.com * kvm_run to 1 and restarting the guest. 2219651SAndreas.Sandberg@ARM.com * 2229651SAndreas.Sandberg@ARM.com * @param interrupt Structure describing the interrupt to send 2239651SAndreas.Sandberg@ARM.com */ 2249651SAndreas.Sandberg@ARM.com void kvmInterrupt(const struct kvm_interrupt &interrupt); 2259651SAndreas.Sandberg@ARM.com 2269651SAndreas.Sandberg@ARM.com /** @} */ 2279651SAndreas.Sandberg@ARM.com 2289651SAndreas.Sandberg@ARM.com /** @{ */ 2299651SAndreas.Sandberg@ARM.com /** 2309651SAndreas.Sandberg@ARM.com * Get/Set the register state of the guest vCPU 2319651SAndreas.Sandberg@ARM.com * 2329651SAndreas.Sandberg@ARM.com * KVM has two different interfaces for accessing the state of the 2339651SAndreas.Sandberg@ARM.com * guest CPU. One interface updates 'normal' registers and one 2349651SAndreas.Sandberg@ARM.com * updates 'special' registers. The distinction between special 2359651SAndreas.Sandberg@ARM.com * and normal registers isn't very clear and is architecture 2369651SAndreas.Sandberg@ARM.com * dependent. 2379651SAndreas.Sandberg@ARM.com */ 2389651SAndreas.Sandberg@ARM.com void getRegisters(struct kvm_regs ®s) const; 2399651SAndreas.Sandberg@ARM.com void setRegisters(const struct kvm_regs ®s); 2409651SAndreas.Sandberg@ARM.com void getSpecialRegisters(struct kvm_sregs ®s) const; 2419651SAndreas.Sandberg@ARM.com void setSpecialRegisters(const struct kvm_sregs ®s); 2429651SAndreas.Sandberg@ARM.com /** @} */ 2439651SAndreas.Sandberg@ARM.com 2449651SAndreas.Sandberg@ARM.com /** @{ */ 2459651SAndreas.Sandberg@ARM.com /** 2469651SAndreas.Sandberg@ARM.com * Get/Set the guest FPU/vector state 2479651SAndreas.Sandberg@ARM.com */ 2489651SAndreas.Sandberg@ARM.com void getFPUState(struct kvm_fpu &state) const; 2499651SAndreas.Sandberg@ARM.com void setFPUState(const struct kvm_fpu &state); 2509651SAndreas.Sandberg@ARM.com /** @} */ 2519651SAndreas.Sandberg@ARM.com 2529651SAndreas.Sandberg@ARM.com /** @{ */ 2539651SAndreas.Sandberg@ARM.com /** 2549651SAndreas.Sandberg@ARM.com * Get/Set single register using the KVM_(SET|GET)_ONE_REG API. 2559651SAndreas.Sandberg@ARM.com * 2569651SAndreas.Sandberg@ARM.com * @note The presence of this call depends on Kvm::capOneReg(). 2579651SAndreas.Sandberg@ARM.com */ 2589651SAndreas.Sandberg@ARM.com void setOneReg(uint64_t id, const void *addr); 2599651SAndreas.Sandberg@ARM.com void setOneReg(uint64_t id, uint64_t value) { setOneReg(id, &value); } 2609651SAndreas.Sandberg@ARM.com void setOneReg(uint64_t id, uint32_t value) { setOneReg(id, &value); } 2619651SAndreas.Sandberg@ARM.com void getOneReg(uint64_t id, void *addr) const; 2629651SAndreas.Sandberg@ARM.com uint64_t getOneRegU64(uint64_t id) const { 2639651SAndreas.Sandberg@ARM.com uint64_t value; 2649651SAndreas.Sandberg@ARM.com getOneReg(id, &value); 2659651SAndreas.Sandberg@ARM.com return value; 2669651SAndreas.Sandberg@ARM.com } 2679651SAndreas.Sandberg@ARM.com uint32_t getOneRegU32(uint64_t id) const { 2689651SAndreas.Sandberg@ARM.com uint32_t value; 2699651SAndreas.Sandberg@ARM.com getOneReg(id, &value); 2709651SAndreas.Sandberg@ARM.com return value; 2719651SAndreas.Sandberg@ARM.com } 2729651SAndreas.Sandberg@ARM.com /** @} */ 2739651SAndreas.Sandberg@ARM.com 2749651SAndreas.Sandberg@ARM.com /** 2759651SAndreas.Sandberg@ARM.com * Get and format one register for printout. 2769651SAndreas.Sandberg@ARM.com * 2779651SAndreas.Sandberg@ARM.com * This function call getOneReg() to retrieve the contents of one 2789651SAndreas.Sandberg@ARM.com * register and automatically formats it for printing. 2799651SAndreas.Sandberg@ARM.com * 2809651SAndreas.Sandberg@ARM.com * @note The presence of this call depends on Kvm::capOneReg(). 2819651SAndreas.Sandberg@ARM.com */ 2829651SAndreas.Sandberg@ARM.com std::string getAndFormatOneReg(uint64_t id) const; 2839651SAndreas.Sandberg@ARM.com 2849651SAndreas.Sandberg@ARM.com /** @{ */ 2859651SAndreas.Sandberg@ARM.com /** 2869651SAndreas.Sandberg@ARM.com * Update the KVM state from the current thread context 2879651SAndreas.Sandberg@ARM.com * 2889651SAndreas.Sandberg@ARM.com * The base CPU calls this method before starting the guest CPU 2899651SAndreas.Sandberg@ARM.com * when the contextDirty flag is set. The architecture dependent 2909651SAndreas.Sandberg@ARM.com * CPU implementation is expected to update all guest state 2919651SAndreas.Sandberg@ARM.com * (registers, special registers, and FPU state). 2929651SAndreas.Sandberg@ARM.com */ 2939651SAndreas.Sandberg@ARM.com virtual void updateKvmState() = 0; 2949651SAndreas.Sandberg@ARM.com 2959651SAndreas.Sandberg@ARM.com /** 2969651SAndreas.Sandberg@ARM.com * Update the current thread context with the KVM state 2979651SAndreas.Sandberg@ARM.com * 2989651SAndreas.Sandberg@ARM.com * The base CPU after the guest updates any of the KVM state. In 2999651SAndreas.Sandberg@ARM.com * practice, this happens after kvmRun is called. The architecture 3009651SAndreas.Sandberg@ARM.com * dependent code is expected to read the state of the guest CPU 3019651SAndreas.Sandberg@ARM.com * and update gem5's thread state. 3029651SAndreas.Sandberg@ARM.com */ 3039651SAndreas.Sandberg@ARM.com virtual void updateThreadContext() = 0; 3049652SAndreas.Sandberg@ARM.com 3059652SAndreas.Sandberg@ARM.com /** 3069652SAndreas.Sandberg@ARM.com * Update a thread context if the KVM state is dirty with respect 3079652SAndreas.Sandberg@ARM.com * to the cached thread context. 3089652SAndreas.Sandberg@ARM.com */ 3099652SAndreas.Sandberg@ARM.com void syncThreadContext(); 3109652SAndreas.Sandberg@ARM.com 3119652SAndreas.Sandberg@ARM.com /** 3129652SAndreas.Sandberg@ARM.com * Update the KVM if the thread context is dirty. 3139652SAndreas.Sandberg@ARM.com */ 3149652SAndreas.Sandberg@ARM.com void syncKvmState(); 3159651SAndreas.Sandberg@ARM.com /** @} */ 3169651SAndreas.Sandberg@ARM.com 3179651SAndreas.Sandberg@ARM.com /** @{ */ 3189651SAndreas.Sandberg@ARM.com /** 3199651SAndreas.Sandberg@ARM.com * Main kvmRun exit handler, calls the relevant handleKvmExit* 3209651SAndreas.Sandberg@ARM.com * depending on exit type. 3219651SAndreas.Sandberg@ARM.com * 3229651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the exit request 3239651SAndreas.Sandberg@ARM.com */ 3249651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExit(); 3259651SAndreas.Sandberg@ARM.com 3269651SAndreas.Sandberg@ARM.com /** 3279651SAndreas.Sandberg@ARM.com * The guest performed a legacy IO request (out/inp on x86) 3289651SAndreas.Sandberg@ARM.com * 3299651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the IO request 3309651SAndreas.Sandberg@ARM.com */ 3319651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitIO(); 3329651SAndreas.Sandberg@ARM.com 3339651SAndreas.Sandberg@ARM.com /** 3349651SAndreas.Sandberg@ARM.com * The guest requested a monitor service using a hypercall 3359651SAndreas.Sandberg@ARM.com * 3369651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the hypercall 3379651SAndreas.Sandberg@ARM.com */ 3389651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitHypercall(); 3399651SAndreas.Sandberg@ARM.com 3409651SAndreas.Sandberg@ARM.com /** 3419651SAndreas.Sandberg@ARM.com * The guest exited because an interrupt window was requested 3429651SAndreas.Sandberg@ARM.com * 3439651SAndreas.Sandberg@ARM.com * The guest exited because an interrupt window was requested 3449651SAndreas.Sandberg@ARM.com * (request_interrupt_window in the kvm_run structure was set to 1 3459651SAndreas.Sandberg@ARM.com * before calling kvmRun) and it is now ready to receive 3469651SAndreas.Sandberg@ARM.com * 3479651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the IRQ 3489651SAndreas.Sandberg@ARM.com */ 3499651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitIRQWindowOpen(); 3509651SAndreas.Sandberg@ARM.com 3519651SAndreas.Sandberg@ARM.com /** 3529651SAndreas.Sandberg@ARM.com * An unknown architecture dependent error occurred when starting 3539651SAndreas.Sandberg@ARM.com * the vCPU 3549651SAndreas.Sandberg@ARM.com * 3559651SAndreas.Sandberg@ARM.com * The kvm_run data structure contains the hardware error 3569651SAndreas.Sandberg@ARM.com * code. The defaults behavior of this method just prints the HW 3579651SAndreas.Sandberg@ARM.com * error code and panics. Architecture dependent implementations 3589651SAndreas.Sandberg@ARM.com * may want to override this method to provide better, 3599651SAndreas.Sandberg@ARM.com * hardware-aware, error messages. 3609651SAndreas.Sandberg@ARM.com * 3619651SAndreas.Sandberg@ARM.com * @return Number of ticks delay the next CPU tick 3629651SAndreas.Sandberg@ARM.com */ 3639651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitUnknown(); 3649651SAndreas.Sandberg@ARM.com 3659651SAndreas.Sandberg@ARM.com /** 3669651SAndreas.Sandberg@ARM.com * An unhandled virtualization exception occured 3679651SAndreas.Sandberg@ARM.com * 3689651SAndreas.Sandberg@ARM.com * Some KVM virtualization drivers return unhandled exceptions to 3699651SAndreas.Sandberg@ARM.com * the user-space monitor. This interface is currently only used 3709651SAndreas.Sandberg@ARM.com * by the Intel VMX KVM driver. 3719651SAndreas.Sandberg@ARM.com * 3729651SAndreas.Sandberg@ARM.com * @return Number of ticks delay the next CPU tick 3739651SAndreas.Sandberg@ARM.com */ 3749651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitException(); 3759651SAndreas.Sandberg@ARM.com 3769651SAndreas.Sandberg@ARM.com /** 3779651SAndreas.Sandberg@ARM.com * KVM failed to start the virtualized CPU 3789651SAndreas.Sandberg@ARM.com * 3799651SAndreas.Sandberg@ARM.com * The kvm_run data structure contains the hardware-specific error 3809651SAndreas.Sandberg@ARM.com * code. 3819651SAndreas.Sandberg@ARM.com * 3829651SAndreas.Sandberg@ARM.com * @return Number of ticks delay the next CPU tick 3839651SAndreas.Sandberg@ARM.com */ 3849651SAndreas.Sandberg@ARM.com virtual Tick handleKvmExitFailEntry(); 3859651SAndreas.Sandberg@ARM.com /** @} */ 3869651SAndreas.Sandberg@ARM.com 3879651SAndreas.Sandberg@ARM.com /** 3889651SAndreas.Sandberg@ARM.com * Inject a memory mapped IO request into gem5 3899651SAndreas.Sandberg@ARM.com * 3909651SAndreas.Sandberg@ARM.com * @param paddr Physical address 3919651SAndreas.Sandberg@ARM.com * @param data Pointer to the source/destination buffer 3929651SAndreas.Sandberg@ARM.com * @param size Memory access size 3939651SAndreas.Sandberg@ARM.com * @param write True if write, False if read 3949651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the memory access 3959651SAndreas.Sandberg@ARM.com */ 3969651SAndreas.Sandberg@ARM.com Tick doMMIOAccess(Addr paddr, void *data, int size, bool write); 3979651SAndreas.Sandberg@ARM.com 3989651SAndreas.Sandberg@ARM.com 3999651SAndreas.Sandberg@ARM.com /** 4009651SAndreas.Sandberg@ARM.com * @addtogroup KvmIoctl 4019651SAndreas.Sandberg@ARM.com * @{ 4029651SAndreas.Sandberg@ARM.com */ 4039651SAndreas.Sandberg@ARM.com /** 4049651SAndreas.Sandberg@ARM.com * vCPU ioctl interface. 4059651SAndreas.Sandberg@ARM.com * 4069651SAndreas.Sandberg@ARM.com * @param request KVM vCPU request 4079651SAndreas.Sandberg@ARM.com * @param p1 Optional request parameter 4089651SAndreas.Sandberg@ARM.com * 4099651SAndreas.Sandberg@ARM.com * @return -1 on error (error number in errno), ioctl dependent 4109651SAndreas.Sandberg@ARM.com * value otherwise. 4119651SAndreas.Sandberg@ARM.com */ 4129651SAndreas.Sandberg@ARM.com int ioctl(int request, long p1) const; 4139651SAndreas.Sandberg@ARM.com int ioctl(int request, void *p1) const { 4149651SAndreas.Sandberg@ARM.com return ioctl(request, (long)p1); 4159651SAndreas.Sandberg@ARM.com } 4169651SAndreas.Sandberg@ARM.com int ioctl(int request) const { 4179651SAndreas.Sandberg@ARM.com return ioctl(request, 0L); 4189651SAndreas.Sandberg@ARM.com } 4199651SAndreas.Sandberg@ARM.com /** @} */ 4209651SAndreas.Sandberg@ARM.com 4219688Sandreas@sandberg.pp.se 4229688Sandreas@sandberg.pp.se /** 4239688Sandreas@sandberg.pp.se * KVM memory port. Uses the default MasterPort behavior, but 4249688Sandreas@sandberg.pp.se * panics on timing accesses. 4259688Sandreas@sandberg.pp.se */ 4269688Sandreas@sandberg.pp.se class KVMCpuPort : public MasterPort 4279688Sandreas@sandberg.pp.se { 4289688Sandreas@sandberg.pp.se 4299688Sandreas@sandberg.pp.se public: 4309688Sandreas@sandberg.pp.se KVMCpuPort(const std::string &_name, BaseKvmCPU *_cpu) 4319688Sandreas@sandberg.pp.se : MasterPort(_name, _cpu) 4329688Sandreas@sandberg.pp.se { } 4339688Sandreas@sandberg.pp.se 4349688Sandreas@sandberg.pp.se protected: 4359688Sandreas@sandberg.pp.se bool recvTimingResp(PacketPtr pkt) 4369688Sandreas@sandberg.pp.se { 4379688Sandreas@sandberg.pp.se panic("The KVM CPU doesn't expect recvTimingResp!\n"); 4389688Sandreas@sandberg.pp.se return true; 4399688Sandreas@sandberg.pp.se } 4409688Sandreas@sandberg.pp.se 4419688Sandreas@sandberg.pp.se void recvRetry() 4429688Sandreas@sandberg.pp.se { 4439688Sandreas@sandberg.pp.se panic("The KVM CPU doesn't expect recvRetry!\n"); 4449688Sandreas@sandberg.pp.se } 4459688Sandreas@sandberg.pp.se 4469688Sandreas@sandberg.pp.se }; 4479688Sandreas@sandberg.pp.se 4489651SAndreas.Sandberg@ARM.com /** Port for data requests */ 4499688Sandreas@sandberg.pp.se KVMCpuPort dataPort; 4509651SAndreas.Sandberg@ARM.com 4519651SAndreas.Sandberg@ARM.com /** Unused dummy port for the instruction interface */ 4529688Sandreas@sandberg.pp.se KVMCpuPort instPort; 4539651SAndreas.Sandberg@ARM.com 4549651SAndreas.Sandberg@ARM.com /** Pre-allocated MMIO memory request */ 4559651SAndreas.Sandberg@ARM.com Request mmio_req; 4569651SAndreas.Sandberg@ARM.com 4579651SAndreas.Sandberg@ARM.com /** 4589651SAndreas.Sandberg@ARM.com * Is the gem5 context dirty? Set to true to force an update of 4599651SAndreas.Sandberg@ARM.com * the KVM vCPU state upon the next call to kvmRun(). 4609651SAndreas.Sandberg@ARM.com */ 4619652SAndreas.Sandberg@ARM.com bool threadContextDirty; 4629652SAndreas.Sandberg@ARM.com 4639652SAndreas.Sandberg@ARM.com /** 4649652SAndreas.Sandberg@ARM.com * Is the KVM state dirty? Set to true to force an update of 4659652SAndreas.Sandberg@ARM.com * the KVM vCPU state upon the next call to kvmRun(). 4669652SAndreas.Sandberg@ARM.com */ 4679652SAndreas.Sandberg@ARM.com bool kvmStateDirty; 4689651SAndreas.Sandberg@ARM.com 4699651SAndreas.Sandberg@ARM.com /** KVM internal ID of the vCPU */ 4709651SAndreas.Sandberg@ARM.com const long vcpuID; 4719651SAndreas.Sandberg@ARM.com 4729651SAndreas.Sandberg@ARM.com private: 4739651SAndreas.Sandberg@ARM.com struct TickEvent : public Event 4749651SAndreas.Sandberg@ARM.com { 4759651SAndreas.Sandberg@ARM.com BaseKvmCPU &cpu; 4769651SAndreas.Sandberg@ARM.com 4779651SAndreas.Sandberg@ARM.com TickEvent(BaseKvmCPU &c) 4789651SAndreas.Sandberg@ARM.com : Event(CPU_Tick_Pri), cpu(c) {} 4799651SAndreas.Sandberg@ARM.com 4809651SAndreas.Sandberg@ARM.com void process() { cpu.tick(); } 4819651SAndreas.Sandberg@ARM.com 4829651SAndreas.Sandberg@ARM.com const char *description() const { 4839651SAndreas.Sandberg@ARM.com return "BaseKvmCPU tick"; 4849651SAndreas.Sandberg@ARM.com } 4859651SAndreas.Sandberg@ARM.com }; 4869651SAndreas.Sandberg@ARM.com 4879651SAndreas.Sandberg@ARM.com /** 4889651SAndreas.Sandberg@ARM.com * Service MMIO requests in the mmioRing. 4899651SAndreas.Sandberg@ARM.com * 4909651SAndreas.Sandberg@ARM.com * 4919651SAndreas.Sandberg@ARM.com * @return Number of ticks spent servicing the MMIO requests in 4929651SAndreas.Sandberg@ARM.com * the MMIO ring buffer 4939651SAndreas.Sandberg@ARM.com */ 4949651SAndreas.Sandberg@ARM.com Tick flushCoalescedMMIO(); 4959651SAndreas.Sandberg@ARM.com 4969651SAndreas.Sandberg@ARM.com /** 4979651SAndreas.Sandberg@ARM.com * Setup a signal handler to catch the timer signal used to 4989651SAndreas.Sandberg@ARM.com * switch back to the monitor. 4999651SAndreas.Sandberg@ARM.com */ 5009651SAndreas.Sandberg@ARM.com void setupSignalHandler(); 5019651SAndreas.Sandberg@ARM.com 5029651SAndreas.Sandberg@ARM.com /** Setup hardware performance counters */ 5039651SAndreas.Sandberg@ARM.com void setupCounters(); 5049651SAndreas.Sandberg@ARM.com 5059651SAndreas.Sandberg@ARM.com /** KVM vCPU file descriptor */ 5069651SAndreas.Sandberg@ARM.com int vcpuFD; 5079651SAndreas.Sandberg@ARM.com /** Size of MMAPed kvm_run area */ 5089651SAndreas.Sandberg@ARM.com int vcpuMMapSize; 5099651SAndreas.Sandberg@ARM.com /** 5109651SAndreas.Sandberg@ARM.com * Pointer to the kvm_run structure used to communicate parameters 5119651SAndreas.Sandberg@ARM.com * with KVM. 5129651SAndreas.Sandberg@ARM.com * 5139651SAndreas.Sandberg@ARM.com * @note This is the base pointer of the MMAPed KVM region. The 5149651SAndreas.Sandberg@ARM.com * first page contains the kvm_run structure. Subsequent pages may 5159651SAndreas.Sandberg@ARM.com * contain other data such as the MMIO ring buffer. 5169651SAndreas.Sandberg@ARM.com */ 5179651SAndreas.Sandberg@ARM.com struct kvm_run *_kvmRun; 5189651SAndreas.Sandberg@ARM.com /** 5199651SAndreas.Sandberg@ARM.com * Coalesced MMIO ring buffer. NULL if coalesced MMIO is not 5209651SAndreas.Sandberg@ARM.com * supported. 5219651SAndreas.Sandberg@ARM.com */ 5229651SAndreas.Sandberg@ARM.com struct kvm_coalesced_mmio_ring *mmioRing; 5239651SAndreas.Sandberg@ARM.com /** Cached page size of the host */ 5249651SAndreas.Sandberg@ARM.com const long pageSize; 5259651SAndreas.Sandberg@ARM.com 5269651SAndreas.Sandberg@ARM.com TickEvent tickEvent; 5279651SAndreas.Sandberg@ARM.com 5289651SAndreas.Sandberg@ARM.com /** @{ */ 5299651SAndreas.Sandberg@ARM.com /** Guest performance counters */ 5309651SAndreas.Sandberg@ARM.com PerfKvmCounter hwCycles; 5319651SAndreas.Sandberg@ARM.com PerfKvmCounter hwInstructions; 5329651SAndreas.Sandberg@ARM.com /** @} */ 5339651SAndreas.Sandberg@ARM.com 5349651SAndreas.Sandberg@ARM.com /** 5359655SAndreas.Sandberg@ARM.com * Does the runTimer control the performance counters? 5369655SAndreas.Sandberg@ARM.com * 5379655SAndreas.Sandberg@ARM.com * The run timer will automatically enable and disable performance 5389655SAndreas.Sandberg@ARM.com * counters if a PerfEvent-based timer is used to control KVM 5399655SAndreas.Sandberg@ARM.com * exits. 5409655SAndreas.Sandberg@ARM.com */ 5419655SAndreas.Sandberg@ARM.com bool perfControlledByTimer; 5429655SAndreas.Sandberg@ARM.com 5439655SAndreas.Sandberg@ARM.com /** 5449651SAndreas.Sandberg@ARM.com * Timer used to force execution into the monitor after a 5459651SAndreas.Sandberg@ARM.com * specified number of simulation tick equivalents have executed 5469651SAndreas.Sandberg@ARM.com * in the guest. This counter generates the signal specified by 5479651SAndreas.Sandberg@ARM.com * KVM_TIMER_SIGNAL. 5489651SAndreas.Sandberg@ARM.com */ 5499651SAndreas.Sandberg@ARM.com std::unique_ptr<BaseKvmTimer> runTimer; 5509651SAndreas.Sandberg@ARM.com 5519651SAndreas.Sandberg@ARM.com float hostFactor; 5529651SAndreas.Sandberg@ARM.com 5539651SAndreas.Sandberg@ARM.com public: 5549651SAndreas.Sandberg@ARM.com /* @{ */ 5559684Sandreas@sandberg.pp.se Stats::Scalar numInsts; 5569651SAndreas.Sandberg@ARM.com Stats::Scalar numVMExits; 5579651SAndreas.Sandberg@ARM.com Stats::Scalar numMMIO; 5589651SAndreas.Sandberg@ARM.com Stats::Scalar numCoalescedMMIO; 5599651SAndreas.Sandberg@ARM.com Stats::Scalar numIO; 5609651SAndreas.Sandberg@ARM.com Stats::Scalar numHalt; 5619651SAndreas.Sandberg@ARM.com Stats::Scalar numInterrupts; 5629651SAndreas.Sandberg@ARM.com Stats::Scalar numHypercalls; 5639651SAndreas.Sandberg@ARM.com /* @} */ 5649651SAndreas.Sandberg@ARM.com}; 5659651SAndreas.Sandberg@ARM.com 5669651SAndreas.Sandberg@ARM.com#endif 567