base.hh revision 10112:1a2f64842044
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 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andreas Sandberg 38 */ 39 40#ifndef __CPU_KVM_BASE_HH__ 41#define __CPU_KVM_BASE_HH__ 42 43#include <memory> 44#include <csignal> 45 46#include "base/statistics.hh" 47#include "cpu/kvm/perfevent.hh" 48#include "cpu/kvm/timer.hh" 49#include "cpu/kvm/vm.hh" 50#include "cpu/base.hh" 51#include "cpu/simple_thread.hh" 52 53/** Signal to use to trigger time-based exits from KVM */ 54#define KVM_TIMER_SIGNAL SIGRTMIN 55 56/** Signal to use to trigger instruction-based exits from KVM */ 57#define KVM_INST_SIGNAL (SIGRTMIN+1) 58 59// forward declarations 60class ThreadContext; 61struct BaseKvmCPUParams; 62 63/** 64 * Base class for KVM based CPU models 65 * 66 * All architecture specific KVM implementation should inherit from 67 * this class. The most basic CPU models only need to override the 68 * updateKvmState() and updateThreadContext() methods to implement 69 * state synchronization between gem5 and KVM. 70 * 71 * The architecture specific implementation is also responsible for 72 * delivering interrupts into the VM. This is typically done by 73 * overriding tick() and checking the thread context before entering 74 * into the VM. In order to deliver an interrupt, the implementation 75 * then calls KvmVM::setIRQLine() or BaseKvmCPU::kvmInterrupt() 76 * depending on the specifics of the underlying hardware/drivers. 77 */ 78class BaseKvmCPU : public BaseCPU 79{ 80 public: 81 BaseKvmCPU(BaseKvmCPUParams *params); 82 virtual ~BaseKvmCPU(); 83 84 void init(); 85 void startup(); 86 void regStats(); 87 88 void serializeThread(std::ostream &os, ThreadID tid); 89 void unserializeThread(Checkpoint *cp, const std::string §ion, 90 ThreadID tid); 91 92 unsigned int drain(DrainManager *dm); 93 void drainResume(); 94 95 void switchOut(); 96 void takeOverFrom(BaseCPU *cpu); 97 98 void verifyMemoryMode() const; 99 100 MasterPort &getDataPort() { return dataPort; } 101 MasterPort &getInstPort() { return instPort; } 102 103 void wakeup(); 104 void activateContext(ThreadID thread_num, Cycles delay); 105 void suspendContext(ThreadID thread_num); 106 void deallocateContext(ThreadID thread_num); 107 void haltContext(ThreadID thread_num); 108 109 ThreadContext *getContext(int tn); 110 111 Counter totalInsts() const; 112 Counter totalOps() const; 113 114 /** Dump the internal state to the terminal. */ 115 virtual void dump(); 116 117 /** 118 * A cached copy of a thread's state in the form of a SimpleThread 119 * object. 120 * 121 * Normally the actual thread state is stored in the KVM vCPU. If KVM has 122 * been running this copy is will be out of date. If we recently handled 123 * some events within gem5 that required state to be updated this could be 124 * the most up-to-date copy. When getContext() or updateThreadContext() is 125 * called this copy gets updated. The method syncThreadContext can 126 * be used within a KVM CPU to update the thread context if the 127 * KVM state is dirty (i.e., the vCPU has been run since the last 128 * update). 129 */ 130 SimpleThread *thread; 131 132 /** ThreadContext object, provides an interface for external 133 * objects to modify this thread's state. 134 */ 135 ThreadContext *tc; 136 137 KvmVM &vm; 138 139 protected: 140 /** 141 * 142 * @dot 143 * digraph { 144 * Idle; 145 * Running; 146 * RunningService; 147 * RunningServiceCompletion; 148 * 149 * Idle -> Idle; 150 * Idle -> Running [label="activateContext()", URL="\ref activateContext"]; 151 * Running -> Running [label="tick()", URL="\ref tick"]; 152 * Running -> RunningService [label="tick()", URL="\ref tick"]; 153 * Running -> Idle [label="suspendContext()", URL="\ref suspendContext"]; 154 * Running -> Idle [label="drain()", URL="\ref drain"]; 155 * Idle -> Running [label="drainResume()", URL="\ref drainResume"]; 156 * RunningService -> RunningServiceCompletion [label="handleKvmExit()", URL="\ref handleKvmExit"]; 157 * RunningServiceCompletion -> Running [label="tick()", URL="\ref tick"]; 158 * RunningServiceCompletion -> RunningService [label="tick()", URL="\ref tick"]; 159 * } 160 * @enddot 161 */ 162 enum Status { 163 /** Context not scheduled in KVM. 164 * 165 * The CPU generally enters this state when the guest execute 166 * an instruction that halts the CPU (e.g., WFI on ARM or HLT 167 * on X86) if KVM traps this instruction. Ticks are not 168 * scheduled in this state. 169 * 170 * @see suspendContext() 171 */ 172 Idle, 173 /** Running normally. 174 * 175 * This is the normal run state of the CPU. KVM will be 176 * entered next time tick() is called. 177 */ 178 Running, 179 /** Requiring service at the beginning of the next cycle. 180 * 181 * The virtual machine has exited and requires service, tick() 182 * will call handleKvmExit() on the next cycle. The next state 183 * after running service is determined in handleKvmExit() and 184 * depends on what kind of service the guest requested: 185 * <ul> 186 * <li>IO/MMIO: RunningServiceCompletion 187 * <li>Halt: Idle 188 * <li>Others: Running 189 * </ul> 190 */ 191 RunningService, 192 /** Service completion in progress. 193 * 194 * The VM has requested service that requires KVM to be 195 * entered once in order to get to a consistent state. This 196 * happens in handleKvmExit() or one of its friends after IO 197 * exits. After executing tick(), the CPU will transition into 198 * the Running or RunningService state. 199 */ 200 RunningServiceCompletion, 201 }; 202 203 /** CPU run state */ 204 Status _status; 205 206 /** 207 * Execute the CPU until the next event in the main event queue or 208 * until the guest needs service from gem5. 209 */ 210 void tick(); 211 212 /** 213 * Get the value of the hardware cycle counter in the guest. 214 * 215 * This method is supposed to return the total number of cycles 216 * executed in hardware mode relative to some arbitrary point in 217 * the past. It's mainly used when estimating the number of cycles 218 * actually executed by the CPU in kvmRun(). The default behavior 219 * of this method is to use the cycles performance counter, but 220 * some architectures may want to use internal registers instead. 221 * 222 * @return Number of host cycles executed relative to an undefined 223 * point in the past. 224 */ 225 virtual uint64_t getHostCycles() const; 226 227 /** 228 * Request KVM to run the guest for a given number of ticks. The 229 * method returns the approximate number of ticks executed. 230 * 231 * @note The returned number of ticks can be both larger or 232 * smaller than the requested number of ticks. A smaller number 233 * can, for example, occur when the guest executes MMIO. A larger 234 * number is typically due to performance counter inaccuracies. 235 * 236 * @note This method is virtual in order to allow implementations 237 * to check for architecture specific events (e.g., interrupts) 238 * before entering the VM. 239 * 240 * @note It is the response of the caller (normally tick()) to 241 * make sure that the KVM state is synchronized and that the TC is 242 * invalidated after entering KVM. 243 * 244 * @note This method does not normally cause any state 245 * transitions. However, if it may suspend the CPU by suspending 246 * the thread, which leads to a transition to the Idle state. In 247 * such a case, kvm <i>must not</i> be entered. 248 * 249 * @param ticks Number of ticks to execute, set to 0 to exit 250 * immediately after finishing pending operations. 251 * @return Number of ticks executed (see note) 252 */ 253 virtual Tick kvmRun(Tick ticks); 254 255 /** 256 * Request the CPU to run until draining completes. 257 * 258 * This function normally calls kvmRun(0) to make KVM finish 259 * pending MMIO operations. Architecures implementing 260 * archIsDrained() must override this method. 261 * 262 * @see BaseKvmCPU::archIsDrained() 263 * 264 * @return Number of ticks executed 265 */ 266 virtual Tick kvmRunDrain(); 267 268 /** 269 * Get a pointer to the kvm_run structure containing all the input 270 * and output parameters from kvmRun(). 271 */ 272 struct kvm_run *getKvmRunState() { return _kvmRun; }; 273 274 /** 275 * Retrieve a pointer to guest data stored at the end of the 276 * kvm_run structure. This is mainly used for PIO operations 277 * (KVM_EXIT_IO). 278 * 279 * @param offset Offset as specified by the kvm_run structure 280 * @return Pointer to guest data 281 */ 282 uint8_t *getGuestData(uint64_t offset) const { 283 return (uint8_t *)_kvmRun + offset; 284 }; 285 286 /** 287 * @addtogroup KvmInterrupts 288 * @{ 289 */ 290 /** 291 * Send a non-maskable interrupt to the guest 292 * 293 * @note The presence of this call depends on Kvm::capUserNMI(). 294 */ 295 void kvmNonMaskableInterrupt(); 296 297 /** 298 * Send a normal interrupt to the guest 299 * 300 * @note Make sure that ready_for_interrupt_injection in kvm_run 301 * is set prior to calling this function. If not, an interrupt 302 * window must be requested by setting request_interrupt_window in 303 * kvm_run to 1 and restarting the guest. 304 * 305 * @param interrupt Structure describing the interrupt to send 306 */ 307 void kvmInterrupt(const struct kvm_interrupt &interrupt); 308 309 /** @} */ 310 311 /** @{ */ 312 /** 313 * Get/Set the register state of the guest vCPU 314 * 315 * KVM has two different interfaces for accessing the state of the 316 * guest CPU. One interface updates 'normal' registers and one 317 * updates 'special' registers. The distinction between special 318 * and normal registers isn't very clear and is architecture 319 * dependent. 320 */ 321 void getRegisters(struct kvm_regs ®s) const; 322 void setRegisters(const struct kvm_regs ®s); 323 void getSpecialRegisters(struct kvm_sregs ®s) const; 324 void setSpecialRegisters(const struct kvm_sregs ®s); 325 /** @} */ 326 327 /** @{ */ 328 /** 329 * Get/Set the guest FPU/vector state 330 */ 331 void getFPUState(struct kvm_fpu &state) const; 332 void setFPUState(const struct kvm_fpu &state); 333 /** @} */ 334 335 /** @{ */ 336 /** 337 * Get/Set single register using the KVM_(SET|GET)_ONE_REG API. 338 * 339 * @note The presence of this call depends on Kvm::capOneReg(). 340 */ 341 void setOneReg(uint64_t id, const void *addr); 342 void setOneReg(uint64_t id, uint64_t value) { setOneReg(id, &value); } 343 void setOneReg(uint64_t id, uint32_t value) { setOneReg(id, &value); } 344 void getOneReg(uint64_t id, void *addr) const; 345 uint64_t getOneRegU64(uint64_t id) const { 346 uint64_t value; 347 getOneReg(id, &value); 348 return value; 349 } 350 uint32_t getOneRegU32(uint64_t id) const { 351 uint32_t value; 352 getOneReg(id, &value); 353 return value; 354 } 355 /** @} */ 356 357 /** 358 * Get and format one register for printout. 359 * 360 * This function call getOneReg() to retrieve the contents of one 361 * register and automatically formats it for printing. 362 * 363 * @note The presence of this call depends on Kvm::capOneReg(). 364 */ 365 std::string getAndFormatOneReg(uint64_t id) const; 366 367 /** @{ */ 368 /** 369 * Update the KVM state from the current thread context 370 * 371 * The base CPU calls this method before starting the guest CPU 372 * when the contextDirty flag is set. The architecture dependent 373 * CPU implementation is expected to update all guest state 374 * (registers, special registers, and FPU state). 375 */ 376 virtual void updateKvmState() = 0; 377 378 /** 379 * Update the current thread context with the KVM state 380 * 381 * The base CPU after the guest updates any of the KVM state. In 382 * practice, this happens after kvmRun is called. The architecture 383 * dependent code is expected to read the state of the guest CPU 384 * and update gem5's thread state. 385 */ 386 virtual void updateThreadContext() = 0; 387 388 /** 389 * Update a thread context if the KVM state is dirty with respect 390 * to the cached thread context. 391 */ 392 void syncThreadContext(); 393 394 /** 395 * Update the KVM if the thread context is dirty. 396 */ 397 void syncKvmState(); 398 /** @} */ 399 400 /** @{ */ 401 /** 402 * Main kvmRun exit handler, calls the relevant handleKvmExit* 403 * depending on exit type. 404 * 405 * @return Number of ticks spent servicing the exit request 406 */ 407 virtual Tick handleKvmExit(); 408 409 /** 410 * The guest performed a legacy IO request (out/inp on x86) 411 * 412 * @return Number of ticks spent servicing the IO request 413 */ 414 virtual Tick handleKvmExitIO(); 415 416 /** 417 * The guest requested a monitor service using a hypercall 418 * 419 * @return Number of ticks spent servicing the hypercall 420 */ 421 virtual Tick handleKvmExitHypercall(); 422 423 /** 424 * The guest exited because an interrupt window was requested 425 * 426 * The guest exited because an interrupt window was requested 427 * (request_interrupt_window in the kvm_run structure was set to 1 428 * before calling kvmRun) and it is now ready to receive 429 * 430 * @return Number of ticks spent servicing the IRQ 431 */ 432 virtual Tick handleKvmExitIRQWindowOpen(); 433 434 /** 435 * An unknown architecture dependent error occurred when starting 436 * the vCPU 437 * 438 * The kvm_run data structure contains the hardware error 439 * code. The defaults behavior of this method just prints the HW 440 * error code and panics. Architecture dependent implementations 441 * may want to override this method to provide better, 442 * hardware-aware, error messages. 443 * 444 * @return Number of ticks delay the next CPU tick 445 */ 446 virtual Tick handleKvmExitUnknown(); 447 448 /** 449 * An unhandled virtualization exception occured 450 * 451 * Some KVM virtualization drivers return unhandled exceptions to 452 * the user-space monitor. This interface is currently only used 453 * by the Intel VMX KVM driver. 454 * 455 * @return Number of ticks delay the next CPU tick 456 */ 457 virtual Tick handleKvmExitException(); 458 459 /** 460 * KVM failed to start the virtualized CPU 461 * 462 * The kvm_run data structure contains the hardware-specific error 463 * code. 464 * 465 * @return Number of ticks delay the next CPU tick 466 */ 467 virtual Tick handleKvmExitFailEntry(); 468 /** @} */ 469 470 /** 471 * Is the architecture specific code in a state that prevents 472 * draining? 473 * 474 * This method should return false if there are any pending events 475 * in the guest vCPU that won't be carried over to the gem5 state 476 * and thus will prevent correct checkpointing or CPU handover. It 477 * might, for example, check for pending interrupts that have been 478 * passed to the vCPU but not acknowledged by the OS. Architecures 479 * implementing this method <i>must</i> override 480 * kvmRunDrain(). 481 * 482 * @see BaseKvmCPU::kvmRunDrain() 483 * 484 * @return true if the vCPU is drained, false otherwise. 485 */ 486 virtual bool archIsDrained() const { return true; } 487 488 /** 489 * Inject a memory mapped IO request into gem5 490 * 491 * @param paddr Physical address 492 * @param data Pointer to the source/destination buffer 493 * @param size Memory access size 494 * @param write True if write, False if read 495 * @return Number of ticks spent servicing the memory access 496 */ 497 Tick doMMIOAccess(Addr paddr, void *data, int size, bool write); 498 499 /** @{ */ 500 /** 501 * Set the signal mask used in kvmRun() 502 * 503 * This method allows the signal mask of the thread executing 504 * kvmRun() to be overridden inside the actual system call. This 505 * allows us to mask timer signals used to force KVM exits while 506 * in gem5. 507 * 508 * The signal mask can be disabled by setting it to NULL. 509 * 510 * @param mask Signals to mask 511 */ 512 void setSignalMask(const sigset_t *mask); 513 /** @} */ 514 515 /** 516 * @addtogroup KvmIoctl 517 * @{ 518 */ 519 /** 520 * vCPU ioctl interface. 521 * 522 * @param request KVM vCPU request 523 * @param p1 Optional request parameter 524 * 525 * @return -1 on error (error number in errno), ioctl dependent 526 * value otherwise. 527 */ 528 int ioctl(int request, long p1) const; 529 int ioctl(int request, void *p1) const { 530 return ioctl(request, (long)p1); 531 } 532 int ioctl(int request) const { 533 return ioctl(request, 0L); 534 } 535 /** @} */ 536 537 538 /** 539 * KVM memory port. Uses the default MasterPort behavior, but 540 * panics on timing accesses. 541 */ 542 class KVMCpuPort : public MasterPort 543 { 544 545 public: 546 KVMCpuPort(const std::string &_name, BaseKvmCPU *_cpu) 547 : MasterPort(_name, _cpu) 548 { } 549 550 protected: 551 bool recvTimingResp(PacketPtr pkt) 552 { 553 panic("The KVM CPU doesn't expect recvTimingResp!\n"); 554 return true; 555 } 556 557 void recvRetry() 558 { 559 panic("The KVM CPU doesn't expect recvRetry!\n"); 560 } 561 562 }; 563 564 /** Port for data requests */ 565 KVMCpuPort dataPort; 566 567 /** Unused dummy port for the instruction interface */ 568 KVMCpuPort instPort; 569 570 /** Pre-allocated MMIO memory request */ 571 Request mmio_req; 572 573 /** 574 * Is the gem5 context dirty? Set to true to force an update of 575 * the KVM vCPU state upon the next call to kvmRun(). 576 */ 577 bool threadContextDirty; 578 579 /** 580 * Is the KVM state dirty? Set to true to force an update of 581 * the KVM vCPU state upon the next call to kvmRun(). 582 */ 583 bool kvmStateDirty; 584 585 /** KVM internal ID of the vCPU */ 586 const long vcpuID; 587 588 private: 589 struct TickEvent : public Event 590 { 591 BaseKvmCPU &cpu; 592 593 TickEvent(BaseKvmCPU &c) 594 : Event(CPU_Tick_Pri), cpu(c) {} 595 596 void process() { cpu.tick(); } 597 598 const char *description() const { 599 return "BaseKvmCPU tick"; 600 } 601 }; 602 603 /** 604 * Service MMIO requests in the mmioRing. 605 * 606 * 607 * @return Number of ticks spent servicing the MMIO requests in 608 * the MMIO ring buffer 609 */ 610 Tick flushCoalescedMMIO(); 611 612 /** 613 * Setup a signal handler to catch the timer signal used to 614 * switch back to the monitor. 615 */ 616 void setupSignalHandler(); 617 618 /** 619 * Discard a (potentially) pending signal. 620 * 621 * @param signum Signal to discard 622 * @return true if the signal was pending, false otherwise. 623 */ 624 bool discardPendingSignal(int signum) const; 625 626 /** 627 * Thread-specific initialization. 628 * 629 * Some KVM-related initialization requires us to know the TID of 630 * the thread that is going to execute our event queue. For 631 * example, when setting up timers, we need to know the TID of the 632 * thread executing in KVM in order to deliver the timer signal to 633 * that thread. This method is called as the first event in this 634 * SimObject's event queue. 635 * 636 * @see startup 637 */ 638 void startupThread(); 639 640 /** Try to drain the CPU if a drain is pending */ 641 bool tryDrain(); 642 643 /** Execute the KVM_RUN ioctl */ 644 void ioctlRun(); 645 646 /** KVM vCPU file descriptor */ 647 int vcpuFD; 648 /** Size of MMAPed kvm_run area */ 649 int vcpuMMapSize; 650 /** 651 * Pointer to the kvm_run structure used to communicate parameters 652 * with KVM. 653 * 654 * @note This is the base pointer of the MMAPed KVM region. The 655 * first page contains the kvm_run structure. Subsequent pages may 656 * contain other data such as the MMIO ring buffer. 657 */ 658 struct kvm_run *_kvmRun; 659 /** 660 * Coalesced MMIO ring buffer. NULL if coalesced MMIO is not 661 * supported. 662 */ 663 struct kvm_coalesced_mmio_ring *mmioRing; 664 /** Cached page size of the host */ 665 const long pageSize; 666 667 TickEvent tickEvent; 668 669 /** 670 * Setup an instruction break if there is one pending. 671 * 672 * Check if there are pending instruction breaks in the CPU's 673 * instruction event queue and schedule an instruction break using 674 * PerfEvent. 675 * 676 * @note This method doesn't currently handle the main system 677 * instruction event queue. 678 */ 679 void setupInstStop(); 680 681 /** @{ */ 682 /** Setup hardware performance counters */ 683 void setupCounters(); 684 685 /** 686 * Setup the guest instruction counter. 687 * 688 * Setup the guest instruction counter and optionally request a 689 * signal every N instructions executed by the guest. This method 690 * will re-attach the counter if the counter has already been 691 * attached and its sampling settings have changed. 692 * 693 * @param period Signal period, set to 0 to disable signaling. 694 */ 695 void setupInstCounter(uint64_t period = 0); 696 697 /** Currently active instruction count breakpoint */ 698 uint64_t activeInstPeriod; 699 700 /** 701 * Guest cycle counter. 702 * 703 * This is the group leader of all performance counters measuring 704 * the guest system. It can be used in conjunction with the 705 * PerfKvmTimer (see perfControlledByTimer) to trigger exits from 706 * KVM. 707 */ 708 PerfKvmCounter hwCycles; 709 710 /** 711 * Guest instruction counter. 712 * 713 * This counter is typically only used to measure the number of 714 * instructions executed by the guest. However, it can also be 715 * used to trigger exits from KVM if the configuration script 716 * requests an exit after a certain number of instructions. 717 * 718 * @see setupInstBreak 719 * @see scheduleInstStop 720 */ 721 PerfKvmCounter hwInstructions; 722 723 /** 724 * Does the runTimer control the performance counters? 725 * 726 * The run timer will automatically enable and disable performance 727 * counters if a PerfEvent-based timer is used to control KVM 728 * exits. 729 */ 730 bool perfControlledByTimer; 731 /** @} */ 732 733 /** 734 * Timer used to force execution into the monitor after a 735 * specified number of simulation tick equivalents have executed 736 * in the guest. This counter generates the signal specified by 737 * KVM_TIMER_SIGNAL. 738 */ 739 std::unique_ptr<BaseKvmTimer> runTimer; 740 741 /** Host factor as specified in the configuration */ 742 float hostFactor; 743 744 /** 745 * Drain manager to use when signaling drain completion 746 * 747 * This pointer is non-NULL when draining and NULL otherwise. 748 */ 749 DrainManager *drainManager; 750 751 public: 752 /* @{ */ 753 Stats::Scalar numInsts; 754 Stats::Scalar numVMExits; 755 Stats::Scalar numVMHalfEntries; 756 Stats::Scalar numExitSignal; 757 Stats::Scalar numMMIO; 758 Stats::Scalar numCoalescedMMIO; 759 Stats::Scalar numIO; 760 Stats::Scalar numHalt; 761 Stats::Scalar numInterrupts; 762 Stats::Scalar numHypercalls; 763 /* @} */ 764 765 /** Number of instructions executed by the CPU */ 766 Counter ctrInsts; 767}; 768 769#endif 770