base.cc revision 9984:94b8d1af6c81
11689SN/A/* 29948SAli.Saidi@ARM.com * Copyright (c) 2012 ARM Limited 37783SGiacomo.Gabrielli@arm.com * All rights reserved 47783SGiacomo.Gabrielli@arm.com * 57783SGiacomo.Gabrielli@arm.com * The license below extends only to copyright in the software and shall 67783SGiacomo.Gabrielli@arm.com * not be construed as granting a license to any other intellectual 77783SGiacomo.Gabrielli@arm.com * property including but not limited to intellectual property relating 87783SGiacomo.Gabrielli@arm.com * to a hardware implementation of the functionality of the software 97783SGiacomo.Gabrielli@arm.com * licensed hereunder. You may use the software subject to the license 107783SGiacomo.Gabrielli@arm.com * terms below provided that you ensure that this notice is replicated 117783SGiacomo.Gabrielli@arm.com * unmodified and in its entirety in all distributions of the software, 127783SGiacomo.Gabrielli@arm.com * modified or unmodified, in source code or in binary form. 137783SGiacomo.Gabrielli@arm.com * 142316SN/A * Redistribution and use in source and binary forms, with or without 151689SN/A * modification, are permitted provided that the following conditions are 161689SN/A * met: redistributions of source code must retain the above copyright 171689SN/A * notice, this list of conditions and the following disclaimer; 181689SN/A * redistributions in binary form must reproduce the above copyright 191689SN/A * notice, this list of conditions and the following disclaimer in the 201689SN/A * documentation and/or other materials provided with the distribution; 211689SN/A * neither the name of the copyright holders nor the names of its 221689SN/A * contributors may be used to endorse or promote products derived from 231689SN/A * this software without specific prior written permission. 241689SN/A * 251689SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 261689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 271689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 281689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 291689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 301689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 311689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 321689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 331689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 341689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 351689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 361689SN/A * 371689SN/A * Authors: Andreas Sandberg 381689SN/A */ 392665Ssaidi@eecs.umich.edu 402665Ssaidi@eecs.umich.edu#include <linux/kvm.h> 412965Sksewell@umich.edu#include <sys/ioctl.h> 421689SN/A#include <sys/mman.h> 439944Smatt.horsnell@ARM.com#include <unistd.h> 449944Smatt.horsnell@ARM.com 451689SN/A#include <cerrno> 462292SN/A#include <csignal> 479516SAli.Saidi@ARM.com#include <ostream> 482329SN/A 492292SN/A#include "arch/mmapped_ipr.hh" 503577Sgblack@eecs.umich.edu#include "arch/utility.hh" 518229Snate@binkert.org#include "cpu/kvm/base.hh" 525953Ssaidi@eecs.umich.edu#include "debug/Checkpoint.hh" 536658Snate@binkert.org#include "debug/Drain.hh" 548887Sgeoffrey.blake@arm.com#include "debug/Kvm.hh" 551717SN/A#include "debug/KvmIO.hh" 562292SN/A#include "debug/KvmRun.hh" 578662SAli.Saidi@ARM.com#include "params/BaseKvmCPU.hh" 588229Snate@binkert.org#include "sim/process.hh" 598229Snate@binkert.org#include "sim/system.hh" 608232Snate@binkert.org 618232Snate@binkert.org#include <signal.h> 628232Snate@binkert.org 639444SAndreas.Sandberg@ARM.com/* Used by some KVM macros */ 648232Snate@binkert.org#define PAGE_SIZE pageSize 659527SMatt.Horsnell@arm.com 666221Snate@binkert.orgvolatile bool timerOverflowed = false; 678230Snate@binkert.org 688793Sgblack@eecs.umich.eduBaseKvmCPU::BaseKvmCPU(BaseKvmCPUParams *params) 692292SN/A : BaseCPU(params), 706221Snate@binkert.org vm(*params->kvmVM), 715529Snate@binkert.org _status(Idle), 721061SN/A dataPort(name() + ".dcache_port", this), 732292SN/A instPort(name() + ".icache_port", this), 746221Snate@binkert.org threadContextDirty(true), 758581Ssteve.reinhardt@amd.com kvmStateDirty(false), 761060SN/A vcpuID(vm.allocVCPUID()), vcpuFD(-1), vcpuMMapSize(0), 771060SN/A _kvmRun(NULL), mmioRing(NULL), 781060SN/A pageSize(sysconf(_SC_PAGE_SIZE)), 791061SN/A tickEvent(*this), 801060SN/A activeInstPeriod(0), 812292SN/A perfControlledByTimer(params->usePerfOverflow), 821062SN/A hostFactor(params->hostFactor), 832316SN/A drainManager(NULL), 842316SN/A ctrInsts(0) 852292SN/A{ 862292SN/A if (pageSize == -1) 872292SN/A panic("KVM: Failed to determine host page size (%i)\n", 882292SN/A errno); 892292SN/A 905336Shines@cs.fsu.edu thread = new SimpleThread(this, 0, params->system, 912292SN/A params->itb, params->dtb, params->isa[0]); 924873Sstever@eecs.umich.edu thread->setStatus(ThreadContext::Halted); 932292SN/A tc = thread->getTC(); 942292SN/A threadContexts.push_back(tc); 952292SN/A 965529Snate@binkert.org setupCounters(); 974329Sktlim@umich.edu 984329Sktlim@umich.edu if (params->usePerfOverflow) 992292SN/A runTimer.reset(new PerfKvmTimer(hwCycles, 1002292SN/A KVM_TIMER_SIGNAL, 1012292SN/A params->hostFactor, 1022292SN/A params->hostFreq)); 1032292SN/A else 1042292SN/A runTimer.reset(new PosixKvmTimer(KVM_TIMER_SIGNAL, CLOCK_MONOTONIC, 1055529Snate@binkert.org params->hostFactor, 1062843Sktlim@umich.edu params->hostFreq)); 1078823Snilay@cs.wisc.edu} 1089513SAli.Saidi@ARM.com 1099513SAli.Saidi@ARM.comBaseKvmCPU::~BaseKvmCPU() 1102292SN/A{ 1112292SN/A if (_kvmRun) 1122292SN/A munmap(_kvmRun, vcpuMMapSize); 1132980Sgblack@eecs.umich.edu close(vcpuFD); 1142292SN/A} 1152292SN/A 1162292SN/Avoid 1172292SN/ABaseKvmCPU::init() 1182292SN/A{ 1192292SN/A BaseCPU::init(); 1202292SN/A 1212292SN/A if (numThreads != 1) 1222292SN/A fatal("KVM: Multithreading not supported"); 1238346Sksewell@umich.edu 1242292SN/A tc->initMemProxies(tc); 1252292SN/A 1262292SN/A // initialize CPU, including PC 1272292SN/A if (FullSystem && !switchedOut()) 1286221Snate@binkert.org TheISA::initCPU(tc, tc->contextId()); 1292292SN/A 1302292SN/A mmio_req.setThreadContext(tc->contextId(), 0); 1312292SN/A} 1328346Sksewell@umich.edu 1332292SN/Avoid 1342292SN/ABaseKvmCPU::startup() 1352292SN/A{ 1364329Sktlim@umich.edu const BaseKvmCPUParams * const p( 1372292SN/A dynamic_cast<const BaseKvmCPUParams *>(params())); 1382292SN/A 1392292SN/A Kvm &kvm(vm.kvm); 1402292SN/A 1412292SN/A BaseCPU::startup(); 1426221Snate@binkert.org 1436221Snate@binkert.org assert(vcpuFD == -1); 1446221Snate@binkert.org 1456221Snate@binkert.org // Tell the VM that a CPU is about to start. 1466221Snate@binkert.org vm.cpuStartup(); 1476221Snate@binkert.org 1486221Snate@binkert.org // We can't initialize KVM CPUs in BaseKvmCPU::init() since we are 1496221Snate@binkert.org // not guaranteed that the parent KVM VM has initialized at that 1507720Sgblack@eecs.umich.edu // point. Initialize virtual CPUs here instead. 1517855SAli.Saidi@ARM.com vcpuFD = vm.createVCPU(vcpuID); 1529437SAndreas.Sandberg@ARM.com 1532292SN/A // Setup signal handlers. This has to be done after the vCPU is 1543640Sktlim@umich.edu // created since it manipulates the vCPU signal mask. 1552292SN/A setupSignalHandler(); 1562292SN/A 1572292SN/A // Map the KVM run structure */ 1582292SN/A vcpuMMapSize = kvm.getVCPUMMapSize(); 1592292SN/A _kvmRun = (struct kvm_run *)mmap(0, vcpuMMapSize, 1602292SN/A PROT_READ | PROT_WRITE, MAP_SHARED, 1612292SN/A vcpuFD, 0); 1622292SN/A if (_kvmRun == MAP_FAILED) 1632292SN/A panic("KVM: Failed to map run data structure\n"); 1642292SN/A 1652292SN/A // Setup a pointer to the MMIO ring buffer if coalesced MMIO is 16610023Smatt.horsnell@ARM.com // available. The offset into the KVM's communication page is 16710023Smatt.horsnell@ARM.com // provided by the coalesced MMIO capability. 16810023Smatt.horsnell@ARM.com int mmioOffset(kvm.capCoalescedMMIO()); 16910023Smatt.horsnell@ARM.com if (!p->useCoalescedMMIO) { 17010023Smatt.horsnell@ARM.com inform("KVM: Coalesced MMIO disabled by config.\n"); 17110023Smatt.horsnell@ARM.com } else if (mmioOffset) { 17210023Smatt.horsnell@ARM.com inform("KVM: Coalesced IO available\n"); 17310023Smatt.horsnell@ARM.com mmioRing = (struct kvm_coalesced_mmio_ring *)( 1742292SN/A (char *)_kvmRun + (mmioOffset * pageSize)); 1752132SN/A } else { 1762301SN/A inform("KVM: Coalesced not supported by host OS\n"); 1771062SN/A } 1781062SN/A 1791062SN/A thread->startup(); 1801062SN/A} 1811062SN/A 1821062SN/Avoid 1831062SN/ABaseKvmCPU::regStats() 1841062SN/A{ 1851062SN/A using namespace Stats; 1861062SN/A 1871062SN/A BaseCPU::regStats(); 1881062SN/A 1891062SN/A numInsts 1901062SN/A .name(name() + ".committedInsts") 1911062SN/A .desc("Number of instructions committed") 1921062SN/A ; 1931062SN/A 1942292SN/A numVMExits 1951062SN/A .name(name() + ".numVMExits") 1968240Snate@binkert.org .desc("total number of KVM exits") 1971062SN/A ; 1981062SN/A 1991062SN/A numVMHalfEntries 2002301SN/A .name(name() + ".numVMHalfEntries") 2018834Satgutier@umich.edu .desc("number of KVM entries to finalize pending operations") 2026221Snate@binkert.org ; 2038834Satgutier@umich.edu 2042301SN/A numExitSignal 2052301SN/A .name(name() + ".numExitSignal") 2062301SN/A .desc("exits due to signal delivery") 2072301SN/A ; 2088834Satgutier@umich.edu 2098834Satgutier@umich.edu numMMIO 2108834Satgutier@umich.edu .name(name() + ".numMMIO") 2118834Satgutier@umich.edu .desc("number of VM exits due to memory mapped IO") 2128834Satgutier@umich.edu ; 2138834Satgutier@umich.edu 2148834Satgutier@umich.edu numCoalescedMMIO 2152316SN/A .name(name() + ".numCoalescedMMIO") 2166221Snate@binkert.org .desc("number of coalesced memory mapped IO requests") 2178240Snate@binkert.org ; 2182301SN/A 2192301SN/A numIO 2202301SN/A .name(name() + ".numIO") 2212301SN/A .desc("number of VM exits due to legacy IO") 2222316SN/A ; 2236221Snate@binkert.org 2248240Snate@binkert.org numHalt 2252301SN/A .name(name() + ".numHalt") 2262301SN/A .desc("number of VM exits due to wait for interrupt instructions") 2272301SN/A ; 2282301SN/A 2292316SN/A numInterrupts 2306221Snate@binkert.org .name(name() + ".numInterrupts") 2318240Snate@binkert.org .desc("number of interrupts delivered") 2322301SN/A ; 2332301SN/A 2342301SN/A numHypercalls 2352301SN/A .name(name() + ".numHypercalls") 2362316SN/A .desc("number of hypercalls") 2376221Snate@binkert.org ; 2388240Snate@binkert.org} 2392301SN/A 2402301SN/Avoid 2412301SN/ABaseKvmCPU::serializeThread(std::ostream &os, ThreadID tid) 2422301SN/A{ 2432316SN/A if (DTRACE(Checkpoint)) { 2446221Snate@binkert.org DPRINTF(Checkpoint, "KVM: Serializing thread %i:\n", tid); 2458240Snate@binkert.org dump(); 2462301SN/A } 2472301SN/A 2482301SN/A assert(tid == 0); 2492301SN/A assert(_status == Idle); 2507897Shestness@cs.utexas.edu thread->serialize(os); 2517897Shestness@cs.utexas.edu} 2528240Snate@binkert.org 2537897Shestness@cs.utexas.eduvoid 2547897Shestness@cs.utexas.eduBaseKvmCPU::unserializeThread(Checkpoint *cp, const std::string §ion, 2557897Shestness@cs.utexas.edu ThreadID tid) 2567897Shestness@cs.utexas.edu{ 2577897Shestness@cs.utexas.edu DPRINTF(Checkpoint, "KVM: Unserialize thread %i:\n", tid); 2587897Shestness@cs.utexas.edu 2598240Snate@binkert.org assert(tid == 0); 2607897Shestness@cs.utexas.edu assert(_status == Idle); 2617897Shestness@cs.utexas.edu thread->unserialize(cp, section); 2627897Shestness@cs.utexas.edu threadContextDirty = true; 2637897Shestness@cs.utexas.edu} 2647897Shestness@cs.utexas.edu 2657897Shestness@cs.utexas.eduunsigned int 2668240Snate@binkert.orgBaseKvmCPU::drain(DrainManager *dm) 2677897Shestness@cs.utexas.edu{ 2687897Shestness@cs.utexas.edu if (switchedOut()) 2697897Shestness@cs.utexas.edu return 0; 2707897Shestness@cs.utexas.edu 2712316SN/A DPRINTF(Drain, "BaseKvmCPU::drain\n"); 2726221Snate@binkert.org switch (_status) { 2738240Snate@binkert.org case Running: 2742301SN/A // The base KVM code is normally ready when it is in the 2752301SN/A // Running state, but the architecture specific code might be 2762301SN/A // of a different opinion. This may happen when the CPU been 2772301SN/A // notified of an event that hasn't been accepted by the vCPU 2782316SN/A // yet. 2798240Snate@binkert.org if (!archIsDrained()) { 2802301SN/A drainManager = dm; 2812301SN/A return 1; 2821062SN/A } 2831062SN/A 2841062SN/A // The state of the CPU is consistent, so we don't need to do 2851062SN/A // anything special to drain it. We simply de-schedule the 2862980Sgblack@eecs.umich.edu // tick event and enter the Idle state to prevent nasty things 2872292SN/A // like MMIOs from happening. 2882292SN/A if (tickEvent.scheduled()) 2892292SN/A deschedule(tickEvent); 2902292SN/A _status = Idle; 2912292SN/A 2922292SN/A /** FALLTHROUGH */ 2932292SN/A case Idle: 2941060SN/A // Idle, no need to drain 2951060SN/A assert(!tickEvent.scheduled()); 2961060SN/A 2971060SN/A // Sync the thread context here since we'll need it when we 2981060SN/A // switch CPUs or checkpoint the CPU. 2991060SN/A syncThreadContext(); 3001060SN/A 3011060SN/A return 0; 3021060SN/A 3031060SN/A case RunningServiceCompletion: 3041061SN/A // The CPU has just requested a service that was handled in 3051060SN/A // the RunningService state, but the results have still not 3062292SN/A // been reported to the CPU. Now, we /could/ probably just 3072292SN/A // update the register state ourselves instead of letting KVM 3082292SN/A // handle it, but that would be tricky. Instead, we enter KVM 3092292SN/A // and let it do its stuff. 3102292SN/A drainManager = dm; 3112292SN/A 3122292SN/A DPRINTF(Drain, "KVM CPU is waiting for service completion, " 3132292SN/A "requesting drain.\n"); 3142292SN/A return 1; 3152292SN/A 3162292SN/A case RunningService: 3171060SN/A // We need to drain since the CPU is waiting for service (e.g., MMIOs) 3181060SN/A drainManager = dm; 3191060SN/A 3201060SN/A DPRINTF(Drain, "KVM CPU is waiting for service, requesting drain.\n"); 3211060SN/A return 1; 3221060SN/A 3231060SN/A default: 3241061SN/A panic("KVM: Unhandled CPU state in drain()\n"); 3251060SN/A return 0; 3262292SN/A } 3271060SN/A} 3281060SN/A 3291060SN/Avoid 3301060SN/ABaseKvmCPU::drainResume() 3311060SN/A{ 3321060SN/A assert(!tickEvent.scheduled()); 3331060SN/A 3341061SN/A // We might have been switched out. In that case, we don't need to 3351060SN/A // do anything. 3362292SN/A if (switchedOut()) 3372292SN/A return; 3382292SN/A 3392292SN/A DPRINTF(Kvm, "drainResume\n"); 3402292SN/A verifyMemoryMode(); 3412292SN/A 3422292SN/A // The tick event is de-scheduled as a part of the draining 3436221Snate@binkert.org // process. Re-schedule it if the thread context is active. 3442292SN/A if (tc->status() == ThreadContext::Active) { 3452292SN/A schedule(tickEvent, nextCycle()); 3462292SN/A _status = Running; 3472292SN/A } else { 3482292SN/A _status = Idle; 3492292SN/A } 3502292SN/A} 3512292SN/A 3526221Snate@binkert.orgvoid 3536221Snate@binkert.orgBaseKvmCPU::switchOut() 3542292SN/A{ 3552292SN/A DPRINTF(Kvm, "switchOut\n"); 3562292SN/A 3572292SN/A BaseCPU::switchOut(); 3582292SN/A 3591060SN/A // We should have drained prior to executing a switchOut, which 3601060SN/A // means that the tick event shouldn't be scheduled and the CPU is 3611060SN/A // idle. 3621060SN/A assert(!tickEvent.scheduled()); 3631061SN/A assert(_status == Idle); 3641060SN/A} 3659427SAndreas.Sandberg@ARM.com 3661060SN/Avoid 3672292SN/ABaseKvmCPU::takeOverFrom(BaseCPU *cpu) 3682292SN/A{ 3691060SN/A DPRINTF(Kvm, "takeOverFrom\n"); 3702292SN/A 3716221Snate@binkert.org BaseCPU::takeOverFrom(cpu); 3726221Snate@binkert.org 3736221Snate@binkert.org // We should have drained prior to executing a switchOut, which 3746221Snate@binkert.org // means that the tick event shouldn't be scheduled and the CPU is 3751060SN/A // idle. 3761060SN/A assert(!tickEvent.scheduled()); 3774329Sktlim@umich.edu assert(_status == Idle); 3784329Sktlim@umich.edu assert(threadContexts.size() == 1); 3794329Sktlim@umich.edu 3804329Sktlim@umich.edu // Force an update of the KVM state here instead of flagging the 3812292SN/A // TC as dirty. This is not ideal from a performance point of 3821060SN/A // view, but it makes debugging easier as it allows meaningful KVM 3831060SN/A // state to be dumped before and after a takeover. 3841061SN/A updateKvmState(); 3859444SAndreas.Sandberg@ARM.com threadContextDirty = false; 3862843Sktlim@umich.edu} 3871060SN/A 3882843Sktlim@umich.eduvoid 3892316SN/ABaseKvmCPU::verifyMemoryMode() const 3902316SN/A{ 3912316SN/A if (!(system->isAtomicMode() && system->bypassCaches())) { 3922316SN/A fatal("The KVM-based CPUs requires the memory system to be in the " 3939444SAndreas.Sandberg@ARM.com "'atomic_noncaching' mode.\n"); 3942843Sktlim@umich.edu } 3952864Sktlim@umich.edu} 3962843Sktlim@umich.edu 3972843Sktlim@umich.eduvoid 3982843Sktlim@umich.eduBaseKvmCPU::wakeup() 3992843Sktlim@umich.edu{ 4009444SAndreas.Sandberg@ARM.com DPRINTF(Kvm, "wakeup()\n"); 4019444SAndreas.Sandberg@ARM.com 4029444SAndreas.Sandberg@ARM.com if (thread->status() != ThreadContext::Suspended) 4039444SAndreas.Sandberg@ARM.com return; 4049444SAndreas.Sandberg@ARM.com 4059444SAndreas.Sandberg@ARM.com thread->activate(); 4069444SAndreas.Sandberg@ARM.com} 4079444SAndreas.Sandberg@ARM.com 4089444SAndreas.Sandberg@ARM.comvoid 4099444SAndreas.Sandberg@ARM.comBaseKvmCPU::activateContext(ThreadID thread_num, Cycles delay) 4109444SAndreas.Sandberg@ARM.com{ 4119444SAndreas.Sandberg@ARM.com DPRINTF(Kvm, "ActivateContext %d (%d cycles)\n", thread_num, delay); 4129444SAndreas.Sandberg@ARM.com 4139444SAndreas.Sandberg@ARM.com assert(thread_num == 0); 4149444SAndreas.Sandberg@ARM.com assert(thread); 4159444SAndreas.Sandberg@ARM.com 4169444SAndreas.Sandberg@ARM.com assert(_status == Idle); 4179444SAndreas.Sandberg@ARM.com assert(!tickEvent.scheduled()); 4189444SAndreas.Sandberg@ARM.com 4199444SAndreas.Sandberg@ARM.com numCycles += ticksToCycles(thread->lastActivate - thread->lastSuspend); 4209444SAndreas.Sandberg@ARM.com 4219444SAndreas.Sandberg@ARM.com schedule(tickEvent, clockEdge(delay)); 4229444SAndreas.Sandberg@ARM.com _status = Running; 4239444SAndreas.Sandberg@ARM.com} 4249444SAndreas.Sandberg@ARM.com 4259444SAndreas.Sandberg@ARM.com 4269444SAndreas.Sandberg@ARM.comvoid 4279444SAndreas.Sandberg@ARM.comBaseKvmCPU::suspendContext(ThreadID thread_num) 4289444SAndreas.Sandberg@ARM.com{ 4299444SAndreas.Sandberg@ARM.com DPRINTF(Kvm, "SuspendContext %d\n", thread_num); 4309444SAndreas.Sandberg@ARM.com 4319444SAndreas.Sandberg@ARM.com assert(thread_num == 0); 4329444SAndreas.Sandberg@ARM.com assert(thread); 4339444SAndreas.Sandberg@ARM.com 4349444SAndreas.Sandberg@ARM.com if (_status == Idle) 4359444SAndreas.Sandberg@ARM.com return; 4362307SN/A 4372307SN/A assert(_status == Running); 4382307SN/A 4392307SN/A // The tick event may no be scheduled if the quest has requested 4406221Snate@binkert.org // the monitor to wait for interrupts. The normal CPU models can 4416221Snate@binkert.org // get their tick events descheduled by quiesce instructions, but 4426221Snate@binkert.org // that can't happen here. 4436221Snate@binkert.org if (tickEvent.scheduled()) 4446221Snate@binkert.org deschedule(tickEvent); 4459437SAndreas.Sandberg@ARM.com 4462307SN/A _status = Idle; 4472307SN/A} 4482307SN/A 4492307SN/Avoid 4502307SN/ABaseKvmCPU::deallocateContext(ThreadID thread_num) 4512307SN/A{ 4522307SN/A // for now, these are equivalent 4532292SN/A suspendContext(thread_num); 4542132SN/A} 4552316SN/A 4566221Snate@binkert.orgvoid 4576221Snate@binkert.orgBaseKvmCPU::haltContext(ThreadID thread_num) 4583867Sbinkertn@umich.edu{ 4593867Sbinkertn@umich.edu // for now, these are equivalent 4606221Snate@binkert.org suspendContext(thread_num); 4613867Sbinkertn@umich.edu} 4622316SN/A 4632316SN/AThreadContext * 4642316SN/ABaseKvmCPU::getContext(int tn) 4652316SN/A{ 4662316SN/A assert(tn == 0); 4672316SN/A syncThreadContext(); 4682316SN/A return tc; 4692292SN/A} 4702292SN/A 4712292SN/A 4722292SN/ACounter 4732733Sktlim@umich.eduBaseKvmCPU::totalInsts() const 4742292SN/A{ 4752292SN/A return ctrInsts; 4762733Sktlim@umich.edu} 4772292SN/A 4782292SN/ACounter 4792292SN/ABaseKvmCPU::totalOps() const 4802292SN/A{ 4812292SN/A hack_once("Pretending totalOps is equivalent to totalInsts()\n"); 4822292SN/A return ctrInsts; 4832292SN/A} 4842292SN/A 4852292SN/Avoid 4862292SN/ABaseKvmCPU::dump() 4872292SN/A{ 4886221Snate@binkert.org inform("State dumping not implemented."); 4896221Snate@binkert.org} 4902292SN/A 4913867Sbinkertn@umich.eduvoid 4926221Snate@binkert.orgBaseKvmCPU::tick() 4932292SN/A{ 4942292SN/A Tick delay(0); 4952292SN/A assert(_status != Idle); 4962292SN/A 4972292SN/A switch (_status) { 4982292SN/A case RunningService: 4992702Sktlim@umich.edu // handleKvmExit() will determine the next state of the CPU 5002292SN/A delay = handleKvmExit(); 5012292SN/A 5022292SN/A if (tryDrain()) 5032292SN/A _status = Idle; 5042292SN/A break; 5052292SN/A 5062292SN/A case RunningServiceCompletion: 5072292SN/A case Running: { 5082292SN/A EventQueue *q = curEventQueue(); 5092292SN/A Tick ticksToExecute(q->nextTick() - curTick()); 5102292SN/A 5112292SN/A // We might need to update the KVM state. 5126221Snate@binkert.org syncKvmState(); 5136221Snate@binkert.org 5142292SN/A // Setup any pending instruction count breakpoints using 5153867Sbinkertn@umich.edu // PerfEvent. 5166221Snate@binkert.org setupInstStop(); 5172292SN/A 5182292SN/A DPRINTF(KvmRun, "Entering KVM...\n"); 5192292SN/A if (drainManager) { 5202292SN/A // Force an immediate exit from KVM after completing 5212292SN/A // pending operations. The architecture-specific code 5222292SN/A // takes care to run until it is in a state where it can 5232292SN/A // safely be drained. 5242292SN/A delay = kvmRunDrain(); 5252292SN/A } else { 5262292SN/A delay = kvmRun(ticksToExecute); 5276221Snate@binkert.org } 5286221Snate@binkert.org 5292292SN/A // Entering into KVM implies that we'll have to reload the thread 5302292SN/A // context from KVM if we want to access it. Flag the KVM state as 5312292SN/A // dirty with respect to the cached thread context. 5322292SN/A kvmStateDirty = true; 5332292SN/A 5342292SN/A // Enter into the RunningService state unless the 5356221Snate@binkert.org // simulation was stopped by a timer. 5362292SN/A if (_kvmRun->exit_reason != KVM_EXIT_INTR) { 5372292SN/A _status = RunningService; 5382292SN/A } else { 5392292SN/A ++numExitSignal; 5402292SN/A _status = Running; 5419179Sandreas.hansson@arm.com } 5424035Sktlim@umich.edu 5438518Sgeoffrey.blake@arm.com // Service any pending instruction events. The vCPU should 5442292SN/A // have exited in time for the event using the instruction 5452292SN/A // counter configured by setupInstStop(). 5462292SN/A comInstEventQueue[0]->serviceEvents(ctrInsts); 5472292SN/A system->instEventQueue.serviceEvents(system->totalNumInsts); 5486221Snate@binkert.org 5492292SN/A if (tryDrain()) 5504035Sktlim@umich.edu _status = Idle; 5512680Sktlim@umich.edu } break; 5522292SN/A 5532680Sktlim@umich.edu default: 5542292SN/A panic("BaseKvmCPU entered tick() in an illegal state (%i)\n", 5552292SN/A _status); 5562292SN/A } 5572292SN/A 5586221Snate@binkert.org // Schedule a new tick if we are still running 5592292SN/A if (_status != Idle) 5602292SN/A schedule(tickEvent, clockEdge(ticksToCycles(delay))); 5612292SN/A} 5622292SN/A 5632292SN/ATick 5642292SN/ABaseKvmCPU::kvmRunDrain() 5657855SAli.Saidi@ARM.com{ 5662292SN/A // By default, the only thing we need to drain is a pending IO 5672292SN/A // operation which assumes that we are in the 5682292SN/A // RunningServiceCompletion state. 5692292SN/A assert(_status == RunningServiceCompletion); 5707855SAli.Saidi@ARM.com 5712292SN/A // Deliver the data from the pending IO operation and immediately 5722292SN/A // exit. 5732292SN/A return kvmRun(0); 5742292SN/A} 5752292SN/A 5762292SN/Auint64_t 5772292SN/ABaseKvmCPU::getHostCycles() const 5782292SN/A{ 5792292SN/A return hwCycles.read(); 5802292SN/A} 5812292SN/A 5822292SN/ATick 5832292SN/ABaseKvmCPU::kvmRun(Tick ticks) 5842292SN/A{ 5852292SN/A Tick ticksExecuted; 5867851SMatt.Horsnell@arm.com DPRINTF(KvmRun, "KVM: Executing for %i ticks\n", ticks); 5878137SAli.Saidi@ARM.com timerOverflowed = false; 5882292SN/A 5897720Sgblack@eecs.umich.edu if (ticks == 0) { 5902316SN/A // Settings ticks == 0 is a special case which causes an entry 5912292SN/A // into KVM that finishes pending operations (e.g., IO) and 5922316SN/A // then immediately exits. 5932316SN/A DPRINTF(KvmRun, "KVM: Delivering IO without full guest entry\n"); 5946221Snate@binkert.org 5952316SN/A ++numVMHalfEntries; 5962316SN/A 5972316SN/A // This signal is always masked while we are executing in gem5 5987720Sgblack@eecs.umich.edu // and gets unmasked temporarily as soon as we enter into 5992316SN/A // KVM. See setSignalMask() and setupSignalHandler(). 6002316SN/A raise(KVM_TIMER_SIGNAL); 6019382SAli.Saidi@ARM.com 6024035Sktlim@umich.edu // Enter into KVM. KVM will check for signals after completing 6032316SN/A // pending operations (IO). Since the KVM_TIMER_SIGNAL is 6042316SN/A // pending, this forces an immediate exit into gem5 again. We 6052316SN/A // don't bother to setup timers since this shouldn't actually 6062316SN/A // execute any code in the guest. 6072316SN/A ioctlRun(); 6082316SN/A 6092316SN/A // We always execute at least one cycle to prevent the 6102316SN/A // BaseKvmCPU::tick() to be rescheduled on the same tick 6112316SN/A // twice. 6126221Snate@binkert.org ticksExecuted = clockPeriod(); 6132316SN/A } else { 6142316SN/A if (ticks < runTimer->resolution()) { 6152292SN/A DPRINTF(KvmRun, "KVM: Adjusting tick count (%i -> %i)\n", 6167720Sgblack@eecs.umich.edu ticks, runTimer->resolution()); 6172292SN/A ticks = runTimer->resolution(); 6189382SAli.Saidi@ARM.com } 6192292SN/A 6202316SN/A // Get hardware statistics after synchronizing contexts. The KVM 6212292SN/A // state update might affect guest cycle counters. 6222292SN/A uint64_t baseCycles(getHostCycles()); 6232292SN/A uint64_t baseInstrs(hwInstructions.read()); 6242680Sktlim@umich.edu 6252292SN/A // Arm the run timer and start the cycle timer if it isn't 6262292SN/A // controlled by the overflow timer. Starting/stopping the cycle 6272292SN/A // timer automatically starts the other perf timers as they are in 6282292SN/A // the same counter group. 6299437SAndreas.Sandberg@ARM.com runTimer->arm(ticks); 6307784SAli.Saidi@ARM.com if (!perfControlledByTimer) 6319437SAndreas.Sandberg@ARM.com hwCycles.start(); 6329437SAndreas.Sandberg@ARM.com 6337784SAli.Saidi@ARM.com ioctlRun(); 6349437SAndreas.Sandberg@ARM.com 6359437SAndreas.Sandberg@ARM.com runTimer->disarm(); 6369437SAndreas.Sandberg@ARM.com if (!perfControlledByTimer) 6379437SAndreas.Sandberg@ARM.com hwCycles.stop(); 6389437SAndreas.Sandberg@ARM.com 6399437SAndreas.Sandberg@ARM.com // The timer signal may have been delivered after we exited 6407784SAli.Saidi@ARM.com // from KVM. It will be pending in that case since it is 6419437SAndreas.Sandberg@ARM.com // masked when we aren't executing in KVM. Discard it to make 6429437SAndreas.Sandberg@ARM.com // sure we don't deliver it immediately next time we try to 6439437SAndreas.Sandberg@ARM.com // enter into KVM. 6447784SAli.Saidi@ARM.com discardPendingSignal(KVM_TIMER_SIGNAL); 6459437SAndreas.Sandberg@ARM.com discardPendingSignal(KVM_INST_SIGNAL); 6469437SAndreas.Sandberg@ARM.com 6479437SAndreas.Sandberg@ARM.com const uint64_t hostCyclesExecuted(getHostCycles() - baseCycles); 6489437SAndreas.Sandberg@ARM.com const uint64_t simCyclesExecuted(hostCyclesExecuted * hostFactor); 6499437SAndreas.Sandberg@ARM.com const uint64_t instsExecuted(hwInstructions.read() - baseInstrs); 6509437SAndreas.Sandberg@ARM.com ticksExecuted = runTimer->ticksFromHostCycles(hostCyclesExecuted); 6517784SAli.Saidi@ARM.com 6529437SAndreas.Sandberg@ARM.com if (ticksExecuted < ticks && 6539437SAndreas.Sandberg@ARM.com timerOverflowed && 6549437SAndreas.Sandberg@ARM.com _kvmRun->exit_reason == KVM_EXIT_INTR) { 6557784SAli.Saidi@ARM.com // TODO: We should probably do something clever here... 6567784SAli.Saidi@ARM.com warn("KVM: Early timer event, requested %i ticks but got %i ticks.\n", 6577784SAli.Saidi@ARM.com ticks, ticksExecuted); 6587784SAli.Saidi@ARM.com } 6592292SN/A 6602292SN/A /* Update statistics */ 6612292SN/A numCycles += simCyclesExecuted;; 6622292SN/A numInsts += instsExecuted; 6632292SN/A ctrInsts += instsExecuted; 6643867Sbinkertn@umich.edu system->totalNumInsts += instsExecuted; 6652875Sksewell@umich.edu 6662875Sksewell@umich.edu DPRINTF(KvmRun, 6676221Snate@binkert.org "KVM: Executed %i instructions in %i cycles " 6686221Snate@binkert.org "(%i ticks, sim cycles: %i).\n", 6692292SN/A instsExecuted, hostCyclesExecuted, ticksExecuted, simCyclesExecuted); 6702316SN/A } 6712316SN/A 6723867Sbinkertn@umich.edu ++numVMExits; 6736221Snate@binkert.org 6742292SN/A return ticksExecuted + flushCoalescedMMIO(); 6754035Sktlim@umich.edu} 6764035Sktlim@umich.edu 6774035Sktlim@umich.eduvoid 6784035Sktlim@umich.eduBaseKvmCPU::kvmNonMaskableInterrupt() 6792292SN/A{ 6802292SN/A ++numInterrupts; 6812292SN/A if (ioctl(KVM_NMI) == -1) 6822292SN/A panic("KVM: Failed to deliver NMI to virtual CPU\n"); 6832292SN/A} 6842292SN/A 6852877Sksewell@umich.eduvoid 6862702Sktlim@umich.eduBaseKvmCPU::kvmInterrupt(const struct kvm_interrupt &interrupt) 6872702Sktlim@umich.edu{ 6882702Sktlim@umich.edu ++numInterrupts; 6892292SN/A if (ioctl(KVM_INTERRUPT, (void *)&interrupt) == -1) 6902292SN/A panic("KVM: Failed to deliver interrupt to virtual CPU\n"); 6912292SN/A} 6922292SN/A 6932292SN/Avoid 6942292SN/ABaseKvmCPU::getRegisters(struct kvm_regs ®s) const 6952292SN/A{ 6962292SN/A if (ioctl(KVM_GET_REGS, ®s) == -1) 6973867Sbinkertn@umich.edu panic("KVM: Failed to get guest registers\n"); 6982292SN/A} 6993867Sbinkertn@umich.edu 7006221Snate@binkert.orgvoid 7012292SN/ABaseKvmCPU::setRegisters(const struct kvm_regs ®s) 7022292SN/A{ 7032292SN/A if (ioctl(KVM_SET_REGS, (void *)®s) == -1) 7042292SN/A panic("KVM: Failed to set guest registers\n"); 7052292SN/A} 7062292SN/A 7072292SN/Avoid 7082292SN/ABaseKvmCPU::getSpecialRegisters(struct kvm_sregs ®s) const 7097720Sgblack@eecs.umich.edu{ 7102292SN/A if (ioctl(KVM_GET_SREGS, ®s) == -1) 7117720Sgblack@eecs.umich.edu panic("KVM: Failed to get guest special registers\n"); 7122292SN/A} 7132292SN/A 7142292SN/Avoid 7152292SN/ABaseKvmCPU::setSpecialRegisters(const struct kvm_sregs ®s) 71610023Smatt.horsnell@ARM.com{ 71710023Smatt.horsnell@ARM.com if (ioctl(KVM_SET_SREGS, (void *)®s) == -1) 7182292SN/A panic("KVM: Failed to set guest special registers\n"); 7197720Sgblack@eecs.umich.edu} 7207720Sgblack@eecs.umich.edu 7212292SN/Avoid 7222292SN/ABaseKvmCPU::getFPUState(struct kvm_fpu &state) const 7232292SN/A{ 7242292SN/A if (ioctl(KVM_GET_FPU, &state) == -1) 7252292SN/A panic("KVM: Failed to get guest FPU state\n"); 7262292SN/A} 7272292SN/A 7282292SN/Avoid 7292316SN/ABaseKvmCPU::setFPUState(const struct kvm_fpu &state) 7302292SN/A{ 7312292SN/A if (ioctl(KVM_SET_FPU, (void *)&state) == -1) 7322292SN/A panic("KVM: Failed to set guest FPU state\n"); 7332292SN/A} 7342292SN/A 7352292SN/A 7362292SN/Avoid 7372292SN/ABaseKvmCPU::setOneReg(uint64_t id, const void *addr) 7384035Sktlim@umich.edu{ 7392292SN/A#ifdef KVM_SET_ONE_REG 7407847Sminkyu.jeong@arm.com struct kvm_one_reg reg; 7417847Sminkyu.jeong@arm.com reg.id = id; 7427847Sminkyu.jeong@arm.com reg.addr = (uint64_t)addr; 7437847Sminkyu.jeong@arm.com 7447847Sminkyu.jeong@arm.com if (ioctl(KVM_SET_ONE_REG, ®) == -1) { 7457847Sminkyu.jeong@arm.com panic("KVM: Failed to set register (0x%x) value (errno: %i)\n", 7469513SAli.Saidi@ARM.com id, errno); 7477847Sminkyu.jeong@arm.com } 7487847Sminkyu.jeong@arm.com#else 7493633Sktlim@umich.edu panic("KVM_SET_ONE_REG is unsupported on this platform.\n"); 7508493Sgblack@eecs.umich.edu#endif 7518493Sgblack@eecs.umich.edu} 7528823Snilay@cs.wisc.edu 7537847Sminkyu.jeong@arm.comvoid 7547847Sminkyu.jeong@arm.comBaseKvmCPU::getOneReg(uint64_t id, void *addr) const 7557847Sminkyu.jeong@arm.com{ 7564035Sktlim@umich.edu#ifdef KVM_GET_ONE_REG 7577847Sminkyu.jeong@arm.com struct kvm_one_reg reg; 7587847Sminkyu.jeong@arm.com reg.id = id; 7592292SN/A reg.addr = (uint64_t)addr; 7609382SAli.Saidi@ARM.com 7619382SAli.Saidi@ARM.com if (ioctl(KVM_GET_ONE_REG, ®) == -1) { 7622292SN/A panic("KVM: Failed to get register (0x%x) value (errno: %i)\n", 7638733Sgeoffrey.blake@arm.com id, errno); 7648733Sgeoffrey.blake@arm.com } 7658733Sgeoffrey.blake@arm.com#else 7668733Sgeoffrey.blake@arm.com panic("KVM_GET_ONE_REG is unsupported on this platform.\n"); 7679624Snilay@cs.wisc.edu#endif 7689624Snilay@cs.wisc.edu} 7699624Snilay@cs.wisc.edu 7709624Snilay@cs.wisc.edustd::string 7713633Sktlim@umich.eduBaseKvmCPU::getAndFormatOneReg(uint64_t id) const 7729382SAli.Saidi@ARM.com{ 7732292SN/A#ifdef KVM_GET_ONE_REG 7747847Sminkyu.jeong@arm.com std::ostringstream ss; 7752292SN/A 7767847Sminkyu.jeong@arm.com ss.setf(std::ios::hex, std::ios::basefield); 7777847Sminkyu.jeong@arm.com ss.setf(std::ios::showbase); 7783640Sktlim@umich.edu#define HANDLE_INTTYPE(len) \ 7797847Sminkyu.jeong@arm.com case KVM_REG_SIZE_U ## len: { \ 7809513SAli.Saidi@ARM.com uint ## len ## _t value; \ 7817847Sminkyu.jeong@arm.com getOneReg(id, &value); \ 7828823Snilay@cs.wisc.edu ss << value; \ 7838823Snilay@cs.wisc.edu } break 7848823Snilay@cs.wisc.edu 7858823Snilay@cs.wisc.edu#define HANDLE_ARRAY(len) \ 7861060SN/A case KVM_REG_SIZE_U ## len: { \ 7874035Sktlim@umich.edu uint8_t value[len / 8]; \ 7887847Sminkyu.jeong@arm.com getOneReg(id, value); \ 7897847Sminkyu.jeong@arm.com ss << "[" << value[0]; \ 7907847Sminkyu.jeong@arm.com for (int i = 1; i < len / 8; ++i) \ 7917847Sminkyu.jeong@arm.com ss << ", " << value[i]; \ 7927847Sminkyu.jeong@arm.com ss << "]"; \ 7937847Sminkyu.jeong@arm.com } break 7947847Sminkyu.jeong@arm.com 7957847Sminkyu.jeong@arm.com switch (id & KVM_REG_SIZE_MASK) { 7967847Sminkyu.jeong@arm.com HANDLE_INTTYPE(8); 7977847Sminkyu.jeong@arm.com HANDLE_INTTYPE(16); 7987847Sminkyu.jeong@arm.com HANDLE_INTTYPE(32); 7997847Sminkyu.jeong@arm.com HANDLE_INTTYPE(64); 8007847Sminkyu.jeong@arm.com HANDLE_ARRAY(128); 8017847Sminkyu.jeong@arm.com HANDLE_ARRAY(256); 8027847Sminkyu.jeong@arm.com HANDLE_ARRAY(512); 8037847Sminkyu.jeong@arm.com HANDLE_ARRAY(1024); 8047847Sminkyu.jeong@arm.com default: 8057847Sminkyu.jeong@arm.com ss << "??"; 8067847Sminkyu.jeong@arm.com } 8077847Sminkyu.jeong@arm.com 8087847Sminkyu.jeong@arm.com#undef HANDLE_INTTYPE 8097847Sminkyu.jeong@arm.com#undef HANDLE_ARRAY 8107847Sminkyu.jeong@arm.com 8117847Sminkyu.jeong@arm.com return ss.str(); 8124035Sktlim@umich.edu#else 8134035Sktlim@umich.edu panic("KVM_GET_ONE_REG is unsupported on this platform.\n"); 8144035Sktlim@umich.edu#endif 8154035Sktlim@umich.edu} 8168793Sgblack@eecs.umich.edu 8178793Sgblack@eecs.umich.eduvoid 8188793Sgblack@eecs.umich.eduBaseKvmCPU::syncThreadContext() 8198793Sgblack@eecs.umich.edu{ 8208793Sgblack@eecs.umich.edu if (!kvmStateDirty) 8211060SN/A return; 8221060SN/A 8232316SN/A assert(!threadContextDirty); 8241060SN/A 8256221Snate@binkert.org updateThreadContext(); 8266221Snate@binkert.org kvmStateDirty = false; 8271060SN/A} 8283867Sbinkertn@umich.edu 8296221Snate@binkert.orgvoid 8301060SN/ABaseKvmCPU::syncKvmState() 8312292SN/A{ 8322292SN/A if (!threadContextDirty) 8332292SN/A return; 8342680Sktlim@umich.edu 8352292SN/A assert(!kvmStateDirty); 8362680Sktlim@umich.edu 8374035Sktlim@umich.edu updateKvmState(); 8382680Sktlim@umich.edu threadContextDirty = false; 8399437SAndreas.Sandberg@ARM.com} 8409437SAndreas.Sandberg@ARM.com 8419437SAndreas.Sandberg@ARM.comTick 8429437SAndreas.Sandberg@ARM.comBaseKvmCPU::handleKvmExit() 8439437SAndreas.Sandberg@ARM.com{ 8442292SN/A DPRINTF(KvmRun, "handleKvmExit (exit_reason: %i)\n", _kvmRun->exit_reason); 8451061SN/A assert(_status == RunningService); 8462292SN/A 8472292SN/A // Switch into the running state by default. Individual handlers 8482292SN/A // can override this. 8492292SN/A _status = Running; 8502292SN/A switch (_kvmRun->exit_reason) { 8512292SN/A case KVM_EXIT_UNKNOWN: 8521061SN/A return handleKvmExitUnknown(); 8538137SAli.Saidi@ARM.com 8548137SAli.Saidi@ARM.com case KVM_EXIT_EXCEPTION: 8558137SAli.Saidi@ARM.com return handleKvmExitException(); 8562292SN/A 8578137SAli.Saidi@ARM.com case KVM_EXIT_IO: 8582292SN/A _status = RunningServiceCompletion; 8598137SAli.Saidi@ARM.com ++numIO; 8608137SAli.Saidi@ARM.com return handleKvmExitIO(); 8618137SAli.Saidi@ARM.com 8628137SAli.Saidi@ARM.com case KVM_EXIT_HYPERCALL: 8638137SAli.Saidi@ARM.com ++numHypercalls; 8641061SN/A return handleKvmExitHypercall(); 8652292SN/A 8662292SN/A case KVM_EXIT_HLT: 8677720Sgblack@eecs.umich.edu /* The guest has halted and is waiting for interrupts */ 8681061SN/A DPRINTF(Kvm, "handleKvmExitHalt\n"); 8692292SN/A ++numHalt; 8701061SN/A 8712292SN/A // Suspend the thread until the next interrupt arrives 8722292SN/A thread->suspend(); 8732292SN/A 8741062SN/A // This is actually ignored since the thread is suspended. 8752935Sksewell@umich.edu return 0; 8762292SN/A 8772935Sksewell@umich.edu case KVM_EXIT_MMIO: 8784035Sktlim@umich.edu _status = RunningServiceCompletion; 8792292SN/A /* Service memory mapped IO requests */ 8802292SN/A DPRINTF(KvmIO, "KVM: Handling MMIO (w: %u, addr: 0x%x, len: %u)\n", 8812292SN/A _kvmRun->mmio.is_write, 8822292SN/A _kvmRun->mmio.phys_addr, _kvmRun->mmio.len); 8833093Sksewell@umich.edu 8842292SN/A ++numMMIO; 8852292SN/A return doMMIOAccess(_kvmRun->mmio.phys_addr, _kvmRun->mmio.data, 8862292SN/A _kvmRun->mmio.len, _kvmRun->mmio.is_write); 8872292SN/A 8882292SN/A case KVM_EXIT_IRQ_WINDOW_OPEN: 8892292SN/A return handleKvmExitIRQWindowOpen(); 8902292SN/A 8912292SN/A case KVM_EXIT_FAIL_ENTRY: 8922292SN/A return handleKvmExitFailEntry(); 8932292SN/A 8947851SMatt.Horsnell@arm.com case KVM_EXIT_INTR: 8957851SMatt.Horsnell@arm.com /* KVM was interrupted by a signal, restart it in the next 8962292SN/A * tick. */ 8972292SN/A return 0; 8988822Snilay@cs.wisc.edu 8998822Snilay@cs.wisc.edu case KVM_EXIT_INTERNAL_ERROR: 9008842Smrinmoy.ghosh@arm.com panic("KVM: Internal error (suberror: %u)\n", 9018842Smrinmoy.ghosh@arm.com _kvmRun->internal.suberror); 9028842Smrinmoy.ghosh@arm.com 9038842Smrinmoy.ghosh@arm.com default: 9048842Smrinmoy.ghosh@arm.com dump(); 9052292SN/A panic("KVM: Unexpected exit (exit_reason: %u)\n", _kvmRun->exit_reason); 9067720Sgblack@eecs.umich.edu } 9072292SN/A} 9088137SAli.Saidi@ARM.com 9092292SN/ATick 9102292SN/ABaseKvmCPU::handleKvmExitIO() 9111062SN/A{ 9122292SN/A panic("KVM: Unhandled guest IO (dir: %i, size: %i, port: 0x%x, count: %i)\n", 9131060SN/A _kvmRun->io.direction, _kvmRun->io.size, 9141060SN/A _kvmRun->io.port, _kvmRun->io.count); 9152292SN/A} 9162292SN/A 9172292SN/ATick 9181061SN/ABaseKvmCPU::handleKvmExitHypercall() 9191060SN/A{ 9201060SN/A panic("KVM: Unhandled hypercall\n"); 9211061SN/A} 9221060SN/A 9231060SN/ATick 9241060SN/ABaseKvmCPU::handleKvmExitIRQWindowOpen() 9252292SN/A{ 9263867Sbinkertn@umich.edu warn("KVM: Unhandled IRQ window.\n"); 9272292SN/A return 0; 9283867Sbinkertn@umich.edu} 9296221Snate@binkert.org 9302292SN/A 9312292SN/ATick 9322292SN/ABaseKvmCPU::handleKvmExitUnknown() 9332292SN/A{ 9342292SN/A dump(); 9352292SN/A panic("KVM: Unknown error when starting vCPU (hw reason: 0x%llx)\n", 9362292SN/A _kvmRun->hw.hardware_exit_reason); 9374035Sktlim@umich.edu} 9384035Sktlim@umich.edu 9392292SN/ATick 9404035Sktlim@umich.eduBaseKvmCPU::handleKvmExitException() 9414035Sktlim@umich.edu{ 9424035Sktlim@umich.edu dump(); 9434035Sktlim@umich.edu panic("KVM: Got exception when starting vCPU " 9444035Sktlim@umich.edu "(exception: %u, error_code: %u)\n", 9454035Sktlim@umich.edu _kvmRun->ex.exception, _kvmRun->ex.error_code); 9464035Sktlim@umich.edu} 9474035Sktlim@umich.edu 9484035Sktlim@umich.eduTick 9494035Sktlim@umich.eduBaseKvmCPU::handleKvmExitFailEntry() 9505557Sktlim@umich.edu{ 9514035Sktlim@umich.edu dump(); 9524035Sktlim@umich.edu panic("KVM: Failed to enter virtualized mode (hw reason: 0x%llx)\n", 9534035Sktlim@umich.edu _kvmRun->fail_entry.hardware_entry_failure_reason); 9544035Sktlim@umich.edu} 9554035Sktlim@umich.edu 9564035Sktlim@umich.eduTick 9574035Sktlim@umich.eduBaseKvmCPU::doMMIOAccess(Addr paddr, void *data, int size, bool write) 9581060SN/A{ 9591060SN/A ThreadContext *tc(thread->getTC()); 9601060SN/A syncThreadContext(); 9611061SN/A 9621060SN/A mmio_req.setPhys(paddr, size, Request::UNCACHEABLE, dataMasterId()); 9632292SN/A // Some architectures do need to massage physical addresses a bit 9641060SN/A // before they are inserted into the memory system. This enables 9651060SN/A // APIC accesses on x86 and m5ops where supported through a MMIO 9661060SN/A // interface. 9672316SN/A BaseTLB::Mode tlb_mode(write ? BaseTLB::Write : BaseTLB::Read); 9682316SN/A Fault fault(tc->getDTBPtr()->finalizePhysical(&mmio_req, tc, tlb_mode)); 9692316SN/A if (fault != NoFault) 9702316SN/A warn("Finalization of MMIO address failed: %s\n", fault->name()); 9712316SN/A 9721060SN/A 9731060SN/A const MemCmd cmd(write ? MemCmd::WriteReq : MemCmd::ReadReq); 9742292SN/A Packet pkt(&mmio_req, cmd); 9751060SN/A pkt.dataStatic(data); 9761060SN/A 9771060SN/A if (mmio_req.isMmappedIpr()) { 9782292SN/A const Cycles ipr_delay(write ? 9792316SN/A TheISA::handleIprWrite(tc, &pkt) : 9801060SN/A TheISA::handleIprRead(tc, &pkt)); 9811060SN/A return clockPeriod() * ipr_delay; 9822292SN/A } else { 9838823Snilay@cs.wisc.edu return dataPort.sendAtomic(&pkt); 9848823Snilay@cs.wisc.edu } 9858823Snilay@cs.wisc.edu} 9868823Snilay@cs.wisc.edu 9878823Snilay@cs.wisc.eduvoid 9882292SN/ABaseKvmCPU::setSignalMask(const sigset_t *mask) 9891060SN/A{ 9902292SN/A std::unique_ptr<struct kvm_signal_mask> kvm_mask; 9912292SN/A 9922292SN/A if (mask) { 9932292SN/A kvm_mask.reset((struct kvm_signal_mask *)operator new( 9942292SN/A sizeof(struct kvm_signal_mask) + sizeof(*mask))); 9956221Snate@binkert.org // The kernel and the user-space headers have different ideas 9962292SN/A // about the size of sigset_t. This seems like a massive hack, 9972292SN/A // but is actually what qemu does. 9982292SN/A assert(sizeof(*mask) >= 8); 9992292SN/A kvm_mask->len = 8; 10002292SN/A memcpy(kvm_mask->sigset, mask, kvm_mask->len); 10012132SN/A } 10022316SN/A 10032316SN/A if (ioctl(KVM_SET_SIGNAL_MASK, (void *)kvm_mask.get()) == -1) 10041060SN/A panic("KVM: Failed to set vCPU signal mask (errno: %i)\n", 10051060SN/A errno); 10062292SN/A} 10071060SN/A 10081060SN/Aint 10092292SN/ABaseKvmCPU::ioctl(int request, long p1) const 10101060SN/A{ 10111062SN/A if (vcpuFD == -1) 10121062SN/A panic("KVM: CPU ioctl called before initialization\n"); 10132292SN/A 10142292SN/A return ::ioctl(vcpuFD, request, p1); 10151060SN/A} 10167720Sgblack@eecs.umich.edu 10172292SN/ATick 10181060SN/ABaseKvmCPU::flushCoalescedMMIO() 10191060SN/A{ 10201060SN/A if (!mmioRing) 10211061SN/A return 0; 10221061SN/A 10232292SN/A DPRINTF(KvmIO, "KVM: Flushing the coalesced MMIO ring buffer\n"); 10241060SN/A 10251060SN/A // TODO: We might need to do synchronization when we start to 10261060SN/A // support multiple CPUs 10271060SN/A Tick ticks(0); 10281062SN/A while (mmioRing->first != mmioRing->last) { 10291060SN/A struct kvm_coalesced_mmio &ent( 103010023Smatt.horsnell@ARM.com mmioRing->coalesced_mmio[mmioRing->first]); 10311060SN/A 10322292SN/A DPRINTF(KvmIO, "KVM: Handling coalesced MMIO (addr: 0x%x, len: %u)\n", 10332292SN/A ent.phys_addr, ent.len); 10342292SN/A 10352292SN/A ++numCoalescedMMIO; 10361060SN/A ticks += doMMIOAccess(ent.phys_addr, ent.data, ent.len, true); 10378823Snilay@cs.wisc.edu 10388823Snilay@cs.wisc.edu mmioRing->first = (mmioRing->first + 1) % KVM_COALESCED_MMIO_MAX; 10398823Snilay@cs.wisc.edu } 10408823Snilay@cs.wisc.edu 10418823Snilay@cs.wisc.edu return ticks; 10428823Snilay@cs.wisc.edu} 10437783SGiacomo.Gabrielli@arm.com 10447783SGiacomo.Gabrielli@arm.com/** 10457783SGiacomo.Gabrielli@arm.com * Cycle timer overflow when running in KVM. Forces the KVM syscall to 104610034SGeoffrey.Blake@arm.com * exit with EINTR and allows us to run the event queue. 104710034SGeoffrey.Blake@arm.com */ 104810034SGeoffrey.Blake@arm.comstatic void 104910034SGeoffrey.Blake@arm.comonTimerOverflow(int signo, siginfo_t *si, void *data) 105010034SGeoffrey.Blake@arm.com{ 105110034SGeoffrey.Blake@arm.com timerOverflowed = true; 10528662SAli.Saidi@ARM.com} 10538662SAli.Saidi@ARM.com 10547720Sgblack@eecs.umich.edu/** 10552935Sksewell@umich.edu * Instruction counter overflow when running in KVM. Forces the KVM 10567855SAli.Saidi@ARM.com * syscall to exit with EINTR and allows us to handle instruction 10577855SAli.Saidi@ARM.com * count events. 10587855SAli.Saidi@ARM.com */ 10597784SAli.Saidi@ARM.comstatic void 10607784SAli.Saidi@ARM.comonInstEvent(int signo, siginfo_t *si, void *data) 10617784SAli.Saidi@ARM.com{ 10629437SAndreas.Sandberg@ARM.com} 10637784SAli.Saidi@ARM.com 10649444SAndreas.Sandberg@ARM.comvoid 10659444SAndreas.Sandberg@ARM.comBaseKvmCPU::setupSignalHandler() 10669444SAndreas.Sandberg@ARM.com{ 10679444SAndreas.Sandberg@ARM.com struct sigaction sa; 10689444SAndreas.Sandberg@ARM.com 10699444SAndreas.Sandberg@ARM.com memset(&sa, 0, sizeof(sa)); 10709444SAndreas.Sandberg@ARM.com sa.sa_sigaction = onTimerOverflow; 10719444SAndreas.Sandberg@ARM.com sa.sa_flags = SA_SIGINFO | SA_RESTART; 10722292SN/A if (sigaction(KVM_TIMER_SIGNAL, &sa, NULL) == -1) 10732292SN/A panic("KVM: Failed to setup vCPU timer signal handler\n"); 10745108Sgblack@eecs.umich.edu 10755108Sgblack@eecs.umich.edu memset(&sa, 0, sizeof(sa)); 10769382SAli.Saidi@ARM.com sa.sa_sigaction = onInstEvent; 10772292SN/A sa.sa_flags = SA_SIGINFO | SA_RESTART; 10787720Sgblack@eecs.umich.edu if (sigaction(KVM_INST_SIGNAL, &sa, NULL) == -1) 10795108Sgblack@eecs.umich.edu panic("KVM: Failed to setup vCPU instruction signal handler\n"); 10802292SN/A 10817720Sgblack@eecs.umich.edu sigset_t sigset; 10822292SN/A if (sigprocmask(SIG_BLOCK, NULL, &sigset) == -1) 10835108Sgblack@eecs.umich.edu panic("KVM: Failed get signal mask\n"); 10845108Sgblack@eecs.umich.edu 10852292SN/A // Request KVM to setup the same signal mask as we're currently 10862292SN/A // running with. We'll sometimes need to mask the KVM_TIMER_SIGNAL 10879513SAli.Saidi@ARM.com // to cause immediate exits from KVM after servicing IO 10889513SAli.Saidi@ARM.com // requests. See kvmRun(). 10899513SAli.Saidi@ARM.com setSignalMask(&sigset); 10909513SAli.Saidi@ARM.com 10919513SAli.Saidi@ARM.com // Mask our control signals so they aren't delivered unless we're 10929513SAli.Saidi@ARM.com // actually executing inside KVM. 10939513SAli.Saidi@ARM.com sigaddset(&sigset, KVM_TIMER_SIGNAL); 10949513SAli.Saidi@ARM.com sigaddset(&sigset, KVM_INST_SIGNAL); 10959513SAli.Saidi@ARM.com if (sigprocmask(SIG_SETMASK, &sigset, NULL) == -1) 10969513SAli.Saidi@ARM.com panic("KVM: Failed mask the KVM control signals\n"); 10979513SAli.Saidi@ARM.com} 10989513SAli.Saidi@ARM.com 10991060SN/Abool 11007720Sgblack@eecs.umich.eduBaseKvmCPU::discardPendingSignal(int signum) const 11012292SN/A{ 11027720Sgblack@eecs.umich.edu int discardedSignal; 11031060SN/A 11041060SN/A // Setting the timeout to zero causes sigtimedwait to return 11051060SN/A // immediately. 11061060SN/A struct timespec timeout; 11071062SN/A timeout.tv_sec = 0; 11081063SN/A timeout.tv_nsec = 0; 11092292SN/A 11102307SN/A sigset_t sigset; 11112307SN/A sigemptyset(&sigset); 11122349SN/A sigaddset(&sigset, signum); 11132307SN/A 11141060SN/A do { 11151060SN/A discardedSignal = sigtimedwait(&sigset, NULL, &timeout); 11161061SN/A } while (discardedSignal == -1 && errno == EINTR); 11171060SN/A 11182292SN/A if (discardedSignal == signum) 11191060SN/A return true; 11201060SN/A else if (discardedSignal == -1 && errno == EAGAIN) 11211060SN/A return false; 11226221Snate@binkert.org else 11232292SN/A panic("Unexpected return value from sigtimedwait: %i (errno: %i)\n", 11242316SN/A discardedSignal, errno); 11252316SN/A} 11261061SN/A 11271061SN/Avoid 11281061SN/ABaseKvmCPU::setupCounters() 11292292SN/A{ 11301062SN/A DPRINTF(Kvm, "Attaching cycle counter...\n"); 11319948SAli.Saidi@ARM.com PerfKvmCounterConfig cfgCycles(PERF_TYPE_HARDWARE, 11329948SAli.Saidi@ARM.com PERF_COUNT_HW_CPU_CYCLES); 11339948SAli.Saidi@ARM.com cfgCycles.disabled(true) 11349948SAli.Saidi@ARM.com .pinned(true); 11359948SAli.Saidi@ARM.com 11362316SN/A if (perfControlledByTimer) { 11379948SAli.Saidi@ARM.com // We need to configure the cycles counter to send overflows 11389948SAli.Saidi@ARM.com // since we are going to use it to trigger timer signals that 11399948SAli.Saidi@ARM.com // trap back into m5 from KVM. In practice, this means that we 11402316SN/A // need to set some non-zero sample period that gets 11419948SAli.Saidi@ARM.com // overridden when the timer is armed. 11429948SAli.Saidi@ARM.com cfgCycles.wakeupEvents(1) 11439948SAli.Saidi@ARM.com .samplePeriod(42); 11449948SAli.Saidi@ARM.com } 11452292SN/A 11469948SAli.Saidi@ARM.com hwCycles.attach(cfgCycles, 11471061SN/A 0); // TID (0 => currentThread) 11489948SAli.Saidi@ARM.com 11499948SAli.Saidi@ARM.com setupInstCounter(); 11509948SAli.Saidi@ARM.com} 11511061SN/A 11529948SAli.Saidi@ARM.combool 11537720Sgblack@eecs.umich.eduBaseKvmCPU::tryDrain() 11547720Sgblack@eecs.umich.edu{ 11552292SN/A if (!drainManager) 11562292SN/A return false; 11579948SAli.Saidi@ARM.com 11589948SAli.Saidi@ARM.com if (!archIsDrained()) { 11599948SAli.Saidi@ARM.com DPRINTF(Drain, "tryDrain: Architecture code is not ready.\n"); 11602292SN/A return false; 11619948SAli.Saidi@ARM.com } 11621060SN/A 11631060SN/A if (_status == Idle || _status == Running) { 11642316SN/A DPRINTF(Drain, 11652292SN/A "tryDrain: CPU transitioned into the Idle state, drain done\n"); 11662316SN/A drainManager->signalDrainDone(); 11672132SN/A drainManager = NULL; 11682132SN/A return true; 11694035Sktlim@umich.edu } else { 11704035Sktlim@umich.edu DPRINTF(Drain, "tryDrain: CPU not ready.\n"); 11714035Sktlim@umich.edu return false; 11722316SN/A } 11734035Sktlim@umich.edu} 11742310SN/A 11752310SN/Avoid 11762310SN/ABaseKvmCPU::ioctlRun() 11772112SN/A{ 11787720Sgblack@eecs.umich.edu if (ioctl(KVM_RUN) == -1) { 11797720Sgblack@eecs.umich.edu if (errno != EINTR) 11802292SN/A panic("KVM: Failed to start virtual CPU (errno: %i)\n", 11815557Sktlim@umich.edu errno); 11822316SN/A } 11832316SN/A} 11842316SN/A 11852310SN/Avoid 11864035Sktlim@umich.eduBaseKvmCPU::setupInstStop() 11874035Sktlim@umich.edu{ 118810034SGeoffrey.Blake@arm.com if (comInstEventQueue[0]->empty()) { 118910034SGeoffrey.Blake@arm.com setupInstCounter(0); 11908733Sgeoffrey.blake@arm.com } else { 11918733Sgeoffrey.blake@arm.com const uint64_t next(comInstEventQueue[0]->nextTick()); 11922732Sktlim@umich.edu 11932316SN/A assert(next > ctrInsts); 11942292SN/A setupInstCounter(next - ctrInsts); 11959382SAli.Saidi@ARM.com } 11962292SN/A} 11972316SN/A 11982316SN/Avoid 11999382SAli.Saidi@ARM.comBaseKvmCPU::setupInstCounter(uint64_t period) 12002292SN/A{ 12012316SN/A // No need to do anything if we aren't attaching for the first 12022316SN/A // time or the period isn't changing. 12032316SN/A if (period == activeInstPeriod && hwInstructions.attached()) 12042316SN/A return; 12052316SN/A 12062316SN/A PerfKvmCounterConfig cfgInstructions(PERF_TYPE_HARDWARE, 12077684Sgblack@eecs.umich.edu PERF_COUNT_HW_INSTRUCTIONS); 12082292SN/A 12092316SN/A if (period) { 12109382SAli.Saidi@ARM.com // Setup a sampling counter if that has been requested. 12112292SN/A cfgInstructions.wakeupEvents(1) 12122316SN/A .samplePeriod(period); 12132292SN/A } 12148067SAli.Saidi@ARM.com 12158067SAli.Saidi@ARM.com // We need to detach and re-attach the counter to reliably change 12164035Sktlim@umich.edu // sampling settings. See PerfKvmCounter::period() for details. 12176667Ssteve.reinhardt@amd.com if (hwInstructions.attached()) 12186667Ssteve.reinhardt@amd.com hwInstructions.detach(); 12198834Satgutier@umich.edu assert(hwCycles.attached()); 12206667Ssteve.reinhardt@amd.com hwInstructions.attach(cfgInstructions, 12216667Ssteve.reinhardt@amd.com 0, // TID (0 => currentThread) 12224288Sktlim@umich.edu hwCycles); 12234035Sktlim@umich.edu 12244035Sktlim@umich.edu if (period) 12254035Sktlim@umich.edu hwInstructions.enableSignals(KVM_INST_SIGNAL); 12262316SN/A 12272316SN/A activeInstPeriod = period; 12282316SN/A} 12291060SN/A