Deleted Added
sdiff udiff text old ( 9752:a152d7f114b8 ) new ( 9753:b9a742cdd75a )
full compact
1/*
2 * Copyright (c) 2012 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software

--- 35 unchanged lines hidden (view full) ---

44
45#include <cerrno>
46#include <csignal>
47#include <ostream>
48
49#include "arch/utility.hh"
50#include "cpu/kvm/base.hh"
51#include "debug/Checkpoint.hh"
52#include "debug/Kvm.hh"
53#include "debug/KvmIO.hh"
54#include "debug/KvmRun.hh"
55#include "params/BaseKvmCPU.hh"
56#include "sim/process.hh"
57#include "sim/system.hh"
58
59/* Used by some KVM macros */
60#define PAGE_SIZE pageSize
61
62volatile bool timerOverflowed = false;
63
64static void
65onTimerOverflow(int signo, siginfo_t *si, void *data)
66{

--- 9 unchanged lines hidden (view full) ---

76 threadContextDirty(true),
77 kvmStateDirty(false),
78 vcpuID(vm.allocVCPUID()), vcpuFD(-1), vcpuMMapSize(0),
79 _kvmRun(NULL), mmioRing(NULL),
80 pageSize(sysconf(_SC_PAGE_SIZE)),
81 tickEvent(*this),
82 perfControlledByTimer(params->usePerfOverflow),
83 hostFactor(params->hostFactor),
84 ctrInsts(0)
85{
86 if (pageSize == -1)
87 panic("KVM: Failed to determine host page size (%i)\n",
88 errno);
89
90 thread = new SimpleThread(this, 0, params->system,
91 params->itb, params->dtb, params->isa[0]);
92 thread->setStatus(ThreadContext::Halted);
93 tc = thread->getTC();
94 threadContexts.push_back(tc);
95
96 setupCounters();
97 setupSignalHandler();
98
99 if (params->usePerfOverflow)
100 runTimer.reset(new PerfKvmTimer(hwCycles,
101 KVM_TIMER_SIGNAL,
102 params->hostFactor,
103 params->clock));
104 else
105 runTimer.reset(new PosixKvmTimer(KVM_TIMER_SIGNAL, CLOCK_MONOTONIC,

--- 40 unchanged lines hidden (view full) ---

146 // Tell the VM that a CPU is about to start.
147 vm.cpuStartup();
148
149 // We can't initialize KVM CPUs in BaseKvmCPU::init() since we are
150 // not guaranteed that the parent KVM VM has initialized at that
151 // point. Initialize virtual CPUs here instead.
152 vcpuFD = vm.createVCPU(vcpuID);
153
154 // Map the KVM run structure */
155 vcpuMMapSize = kvm.getVCPUMMapSize();
156 _kvmRun = (struct kvm_run *)mmap(0, vcpuMMapSize,
157 PROT_READ | PROT_WRITE, MAP_SHARED,
158 vcpuFD, 0);
159 if (_kvmRun == MAP_FAILED)
160 panic("KVM: Failed to map run data structure\n");
161

--- 65 unchanged lines hidden (view full) ---

227void
228BaseKvmCPU::serializeThread(std::ostream &os, ThreadID tid)
229{
230 if (DTRACE(Checkpoint)) {
231 DPRINTF(Checkpoint, "KVM: Serializing thread %i:\n", tid);
232 dump();
233 }
234
235 // Update the thread context so we have something to serialize.
236 syncThreadContext();
237
238 assert(tid == 0);
239 assert(_status == Idle);
240 thread->serialize(os);
241}
242
243void
244BaseKvmCPU::unserializeThread(Checkpoint *cp, const std::string &section,
245 ThreadID tid)

--- 7 unchanged lines hidden (view full) ---

253}
254
255unsigned int
256BaseKvmCPU::drain(DrainManager *dm)
257{
258 if (switchedOut())
259 return 0;
260
261 DPRINTF(Kvm, "drain\n");
262
263 // De-schedule the tick event so we don't insert any more MMIOs
264 // into the system while it is draining.
265 if (tickEvent.scheduled())
266 deschedule(tickEvent);
267
268 _status = Idle;
269 return 0;
270}
271
272void
273BaseKvmCPU::drainResume()
274{
275 assert(!tickEvent.scheduled());
276
277 // We might have been switched out. In that case, we don't need to

--- 14 unchanged lines hidden (view full) ---

292 }
293}
294
295void
296BaseKvmCPU::switchOut()
297{
298 DPRINTF(Kvm, "switchOut\n");
299
300 // Make sure to update the thread context in case, the new CPU
301 // will need to access it.
302 syncThreadContext();
303
304 BaseCPU::switchOut();
305
306 // We should have drained prior to executing a switchOut, which
307 // means that the tick event shouldn't be scheduled and the CPU is
308 // idle.
309 assert(!tickEvent.scheduled());
310 assert(_status == Idle);
311}

--- 7 unchanged lines hidden (view full) ---

319
320 // We should have drained prior to executing a switchOut, which
321 // means that the tick event shouldn't be scheduled and the CPU is
322 // idle.
323 assert(!tickEvent.scheduled());
324 assert(_status == Idle);
325 assert(threadContexts.size() == 1);
326
327 // The BaseCPU updated the thread context, make sure that we
328 // synchronize next time we enter start the CPU.
329 threadContextDirty = true;
330}
331
332void
333BaseKvmCPU::verifyMemoryMode() const
334{
335 if (!(system->isAtomicMode() && system->bypassCaches())) {
336 fatal("The KVM-based CPUs requires the memory system to be in the "
337 "'atomic_noncaching' mode.\n");

--- 93 unchanged lines hidden (view full) ---

431BaseKvmCPU::dump()
432{
433 inform("State dumping not implemented.");
434}
435
436void
437BaseKvmCPU::tick()
438{
439 assert(_status == Running);
440
441 DPRINTF(KvmRun, "Entering KVM...\n");
442
443 Tick ticksToExecute(mainEventQueue.nextTick() - curTick());
444 Tick ticksExecuted(kvmRun(ticksToExecute));
445
446 Tick delay(ticksExecuted + handleKvmExit());
447
448 switch (_status) {
449 case Running:
450 schedule(tickEvent, clockEdge(ticksToCycles(delay)));
451 break;
452
453 default:
454 /* The CPU is halted or waiting for an interrupt from a
455 * device. Don't start it. */
456 break;
457 }
458}
459
460uint64_t
461BaseKvmCPU::getHostCycles() const
462{
463 return hwCycles.read();
464}
465
466Tick
467BaseKvmCPU::kvmRun(Tick ticks)
468{
469 // We might need to update the KVM state.
470 syncKvmState();
471 // Entering into KVM implies that we'll have to reload the thread
472 // context from KVM if we want to access it. Flag the KVM state as
473 // dirty with respect to the cached thread context.
474 kvmStateDirty = true;
475
476 if (ticks < runTimer->resolution()) {
477 DPRINTF(KvmRun, "KVM: Adjusting tick count (%i -> %i)\n",
478 ticks, runTimer->resolution());
479 ticks = runTimer->resolution();
480 }
481
482 DPRINTF(KvmRun, "KVM: Executing for %i ticks\n", ticks);
483 timerOverflowed = false;
484
485 // Get hardware statistics after synchronizing contexts. The KVM
486 // state update might affect guest cycle counters.
487 uint64_t baseCycles(getHostCycles());
488 uint64_t baseInstrs(hwInstructions.read());
489
490 // Arm the run timer and start the cycle timer if it isn't
491 // controlled by the overflow timer. Starting/stopping the cycle
492 // timer automatically starts the other perf timers as they are in
493 // the same counter group.
494 runTimer->arm(ticks);
495 if (!perfControlledByTimer)
496 hwCycles.start();
497
498 if (ioctl(KVM_RUN) == -1) {
499 if (errno != EINTR)
500 panic("KVM: Failed to start virtual CPU (errno: %i)\n",
501 errno);
502 }
503
504 runTimer->disarm();
505 if (!perfControlledByTimer)
506 hwCycles.stop();
507
508
509 const uint64_t hostCyclesExecuted(getHostCycles() - baseCycles);
510 const uint64_t simCyclesExecuted(hostCyclesExecuted * hostFactor);
511 const uint64_t instsExecuted(hwInstructions.read() - baseInstrs);
512 const Tick ticksExecuted(runTimer->ticksFromHostCycles(hostCyclesExecuted));
513
514 if (ticksExecuted < ticks &&
515 timerOverflowed &&
516 _kvmRun->exit_reason == KVM_EXIT_INTR) {
517 // TODO: We should probably do something clever here...
518 warn("KVM: Early timer event, requested %i ticks but got %i ticks.\n",
519 ticks, ticksExecuted);
520 }
521
522 /* Update statistics */
523 numCycles += simCyclesExecuted;;
524 ++numVMExits;
525 numInsts += instsExecuted;
526 ctrInsts += instsExecuted;
527 system->totalNumInsts += instsExecuted;
528
529 DPRINTF(KvmRun, "KVM: Executed %i instructions in %i cycles (%i ticks, sim cycles: %i).\n",
530 instsExecuted, hostCyclesExecuted, ticksExecuted, simCyclesExecuted);
531
532 return ticksExecuted + flushCoalescedMMIO();
533}
534
535void
536BaseKvmCPU::kvmNonMaskableInterrupt()
537{
538 ++numInterrupts;
539 if (ioctl(KVM_NMI) == -1)

--- 155 unchanged lines hidden (view full) ---

695 updateKvmState();
696 threadContextDirty = false;
697}
698
699Tick
700BaseKvmCPU::handleKvmExit()
701{
702 DPRINTF(KvmRun, "handleKvmExit (exit_reason: %i)\n", _kvmRun->exit_reason);
703
704 switch (_kvmRun->exit_reason) {
705 case KVM_EXIT_UNKNOWN:
706 return handleKvmExitUnknown();
707
708 case KVM_EXIT_EXCEPTION:
709 return handleKvmExitException();
710
711 case KVM_EXIT_IO:
712 ++numIO;
713 return handleKvmExitIO();
714
715 case KVM_EXIT_HYPERCALL:
716 ++numHypercalls;
717 return handleKvmExitHypercall();
718
719 case KVM_EXIT_HLT:
720 /* The guest has halted and is waiting for interrupts */
721 DPRINTF(Kvm, "handleKvmExitHalt\n");
722 ++numHalt;
723
724 // Suspend the thread until the next interrupt arrives
725 thread->suspend();
726
727 // This is actually ignored since the thread is suspended.
728 return 0;
729
730 case KVM_EXIT_MMIO:
731 /* Service memory mapped IO requests */
732 DPRINTF(KvmIO, "KVM: Handling MMIO (w: %u, addr: 0x%x, len: %u)\n",
733 _kvmRun->mmio.is_write,
734 _kvmRun->mmio.phys_addr, _kvmRun->mmio.len);
735
736 ++numMMIO;
737 return doMMIOAccess(_kvmRun->mmio.phys_addr, _kvmRun->mmio.data,
738 _kvmRun->mmio.len, _kvmRun->mmio.is_write);

--- 72 unchanged lines hidden (view full) ---

811 mmio_req.setPhys(paddr, size, Request::UNCACHEABLE, dataMasterId());
812
813 const MemCmd cmd(write ? MemCmd::WriteReq : MemCmd::ReadReq);
814 Packet pkt(&mmio_req, cmd);
815 pkt.dataStatic(data);
816 return dataPort.sendAtomic(&pkt);
817}
818
819int
820BaseKvmCPU::ioctl(int request, long p1) const
821{
822 if (vcpuFD == -1)
823 panic("KVM: CPU ioctl called before initialization\n");
824
825 return ::ioctl(vcpuFD, request, p1);
826}

--- 30 unchanged lines hidden (view full) ---

857{
858 struct sigaction sa;
859
860 memset(&sa, 0, sizeof(sa));
861 sa.sa_sigaction = onTimerOverflow;
862 sa.sa_flags = SA_SIGINFO | SA_RESTART;
863 if (sigaction(KVM_TIMER_SIGNAL, &sa, NULL) == -1)
864 panic("KVM: Failed to setup vCPU signal handler\n");
865}
866
867void
868BaseKvmCPU::setupCounters()
869{
870 DPRINTF(Kvm, "Attaching cycle counter...\n");
871 PerfKvmCounterConfig cfgCycles(PERF_TYPE_HARDWARE,
872 PERF_COUNT_HW_CPU_CYCLES);
873 cfgCycles.disabled(true)
874 .pinned(true);

--- 13 unchanged lines hidden (view full) ---

888
889 DPRINTF(Kvm, "Attaching instruction counter...\n");
890 PerfKvmCounterConfig cfgInstructions(PERF_TYPE_HARDWARE,
891 PERF_COUNT_HW_INSTRUCTIONS);
892 hwInstructions.attach(cfgInstructions,
893 0, // TID (0 => currentThread)
894 hwCycles);
895}