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