summaryrefslogtreecommitdiff
path: root/src/cpu/kvm/base.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/kvm/base.hh')
-rw-r--r--src/cpu/kvm/base.hh147
1 files changed, 138 insertions, 9 deletions
diff --git a/src/cpu/kvm/base.hh b/src/cpu/kvm/base.hh
index 81b24a378..42a7eca2b 100644
--- a/src/cpu/kvm/base.hh
+++ b/src/cpu/kvm/base.hh
@@ -41,6 +41,7 @@
#define __CPU_KVM_BASE_HH__
#include <memory>
+#include <csignal>
#include "base/statistics.hh"
#include "cpu/kvm/perfevent.hh"
@@ -133,11 +134,67 @@ class BaseKvmCPU : public BaseCPU
KvmVM &vm;
protected:
+ /**
+ *
+ * @dot
+ * digraph {
+ * Idle;
+ * Running;
+ * RunningService;
+ * RunningServiceCompletion;
+ *
+ * Idle -> Idle;
+ * Idle -> Running [label="activateContext()", URL="\ref activateContext"];
+ * Running -> Running [label="tick()", URL="\ref tick"];
+ * Running -> RunningService [label="tick()", URL="\ref tick"];
+ * Running -> Idle [label="suspendContext()", URL="\ref suspendContext"];
+ * Running -> Idle [label="drain()", URL="\ref drain"];
+ * Idle -> Running [label="drainResume()", URL="\ref drainResume"];
+ * RunningService -> RunningServiceCompletion [label="handleKvmExit()", URL="\ref handleKvmExit"];
+ * RunningServiceCompletion -> Running [label="tick()", URL="\ref tick"];
+ * RunningServiceCompletion -> RunningService [label="tick()", URL="\ref tick"];
+ * }
+ * @enddot
+ */
enum Status {
- /** Context not scheduled in KVM */
+ /** Context not scheduled in KVM.
+ *
+ * The CPU generally enters this state when the guest execute
+ * an instruction that halts the CPU (e.g., WFI on ARM or HLT
+ * on X86) if KVM traps this instruction. Ticks are not
+ * scheduled in this state.
+ *
+ * @see suspendContext()
+ */
Idle,
- /** Running normally */
+ /** Running normally.
+ *
+ * This is the normal run state of the CPU. KVM will be
+ * entered next time tick() is called.
+ */
Running,
+ /** Requiring service at the beginning of the next cycle.
+ *
+ * The virtual machine has exited and requires service, tick()
+ * will call handleKvmExit() on the next cycle. The next state
+ * after running service is determined in handleKvmExit() and
+ * depends on what kind of service the guest requested:
+ * <ul>
+ * <li>IO/MMIO: RunningServiceCompletion
+ * <li>Halt: Idle
+ * <li>Others: Running
+ * </ul>
+ */
+ RunningService,
+ /** Service completion in progress.
+ *
+ * The VM has requested service that requires KVM to be
+ * entered once in order to get to a consistent state. This
+ * happens in handleKvmExit() or one of its friends after IO
+ * exits. After executing tick(), the CPU will transition into
+ * the Running or RunningService state.
+ */
+ RunningServiceCompletion,
};
/** CPU run state */
@@ -146,12 +203,8 @@ class BaseKvmCPU : public BaseCPU
/**
* Execute the CPU until the next event in the main event queue or
* until the guest needs service from gem5.
- *
- * @note This method is virtual in order to allow implementations
- * to check for architecture specific events (e.g., interrupts)
- * before entering the VM.
*/
- virtual void tick();
+ void tick();
/**
* Get the value of the hardware cycle counter in the guest.
@@ -177,10 +230,32 @@ class BaseKvmCPU : public BaseCPU
* can, for example, occur when the guest executes MMIO. A larger
* number is typically due to performance counter inaccuracies.
*
- * @param ticks Number of ticks to execute
+ * @note This method is virtual in order to allow implementations
+ * to check for architecture specific events (e.g., interrupts)
+ * before entering the VM.
+ *
+ * @note It is the response of the caller (normally tick()) to
+ * make sure that the KVM state is synchronized and that the TC is
+ * invalidated after entering KVM.
+ *
+ * @param ticks Number of ticks to execute, set to 0 to exit
+ * immediately after finishing pending operations.
* @return Number of ticks executed (see note)
*/
- Tick kvmRun(Tick ticks);
+ virtual Tick kvmRun(Tick ticks);
+
+ /**
+ * Request the CPU to run until draining completes.
+ *
+ * This function normally calls kvmRun(0) to make KVM finish
+ * pending MMIO operations. Architecures implementing
+ * archIsDrained() must override this method.
+ *
+ * @see BaseKvmCPU::archIsDrained()
+ *
+ * @return Number of ticks executed
+ */
+ virtual Tick kvmRunDrain();
/**
* Get a pointer to the kvm_run structure containing all the input
@@ -385,6 +460,24 @@ class BaseKvmCPU : public BaseCPU
/** @} */
/**
+ * Is the architecture specific code in a state that prevents
+ * draining?
+ *
+ * This method should return false if there are any pending events
+ * in the guest vCPU that won't be carried over to the gem5 state
+ * and thus will prevent correct checkpointing or CPU handover. It
+ * might, for example, check for pending interrupts that have been
+ * passed to the vCPU but not acknowledged by the OS. Architecures
+ * implementing this method <i>must</i> override
+ * kvmRunDrain().
+ *
+ * @see BaseKvmCPU::kvmRunDrain()
+ *
+ * @return true if the vCPU is drained, false otherwise.
+ */
+ virtual bool archIsDrained() const { return true; }
+
+ /**
* Inject a memory mapped IO request into gem5
*
* @param paddr Physical address
@@ -395,6 +488,21 @@ class BaseKvmCPU : public BaseCPU
*/
Tick doMMIOAccess(Addr paddr, void *data, int size, bool write);
+ /** @{ */
+ /**
+ * Set the signal mask used in kvmRun()
+ *
+ * This method allows the signal mask of the thread executing
+ * kvmRun() to be overridden inside the actual system call. This
+ * allows us to mask timer signals used to force KVM exits while
+ * in gem5.
+ *
+ * The signal mask can be disabled by setting it to NULL.
+ *
+ * @param mask Signals to mask
+ */
+ void setSignalMask(const sigset_t *mask);
+ /** @} */
/**
* @addtogroup KvmIoctl
@@ -499,9 +607,23 @@ class BaseKvmCPU : public BaseCPU
*/
void setupSignalHandler();
+ /**
+ * Discard a (potentially) pending signal.
+ *
+ * @param signum Signal to discard
+ * @return true if the signal was pending, false otherwise.
+ */
+ bool discardPendingSignal(int signum) const;
+
/** Setup hardware performance counters */
void setupCounters();
+ /** Try to drain the CPU if a drain is pending */
+ bool tryDrain();
+
+ /** Execute the KVM_RUN ioctl */
+ void ioctlRun();
+
/** KVM vCPU file descriptor */
int vcpuFD;
/** Size of MMAPed kvm_run area */
@@ -550,6 +672,13 @@ class BaseKvmCPU : public BaseCPU
float hostFactor;
+ /**
+ * Drain manager to use when signaling drain completion
+ *
+ * This pointer is non-NULL when draining and NULL otherwise.
+ */
+ DrainManager *drainManager;
+
public:
/* @{ */
Stats::Scalar numInsts;