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