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 &section,
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 &regs) const
6952292SN/A{
6962292SN/A    if (ioctl(KVM_GET_REGS, &regs) == -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 &regs)
7022292SN/A{
7032292SN/A    if (ioctl(KVM_SET_REGS, (void *)&regs) == -1)
7042292SN/A        panic("KVM: Failed to set guest registers\n");
7052292SN/A}
7062292SN/A
7072292SN/Avoid
7082292SN/ABaseKvmCPU::getSpecialRegisters(struct kvm_sregs &regs) const
7097720Sgblack@eecs.umich.edu{
7102292SN/A    if (ioctl(KVM_GET_SREGS, &regs) == -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 &regs)
71610023Smatt.horsnell@ARM.com{
71710023Smatt.horsnell@ARM.com    if (ioctl(KVM_SET_SREGS, (void *)&regs) == -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, &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, &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