diff -r 99f1e74d38f3 -r 4560fb29509f src/cpu/base.hh --- a/src/cpu/base.hh Fri Mar 08 09:18:09 2013 -0500 +++ b/src/cpu/base.hh Fri Mar 08 09:19:56 2013 -0500 @@ -284,7 +284,7 @@ int findContext(ThreadContext *tc); /// Given a thread num get tho thread context for it - ThreadContext *getContext(int tn) { return threadContexts[tn]; } + virtual ThreadContext *getContext(int tn) { return threadContexts[tn]; } public: typedef BaseCPUParams Params; diff -r 99f1e74d38f3 -r 4560fb29509f src/cpu/kvm/base.hh --- a/src/cpu/kvm/base.hh Fri Mar 08 09:18:09 2013 -0500 +++ b/src/cpu/kvm/base.hh Fri Mar 08 09:19:56 2013 -0500 @@ -102,13 +102,26 @@ void deallocateContext(ThreadID thread_num); void haltContext(ThreadID thread_num); + ThreadContext *getContext(int tn); + Counter totalInsts() const; Counter totalOps() const; /** Dump the internal state to the terminal. */ virtual void dumpState(); - /** SimpleThread object, provides all the architectural state. */ + /** + * A cached copy of a thread's state in the form of a SimpleThread + * object. + * + * The actual thread state is stored in the KVM vCPU, this is only + * a cached copy that gets updated when the context is accesses + * using the getContext() method or a call + * updateThreadContext(). The method condUpdateThreadContext can + * be used within a KVM CPU to update the thread context if the + * KVM state is dirty (i.e., the vCPU has been run since the last + * update). + */ SimpleThread *thread; /** ThreadContext object, provides an interface for external @@ -272,6 +285,17 @@ * and update gem5's thread state. */ virtual void updateThreadContext() = 0; + + /** + * Update a thread context if the KVM state is dirty with respect + * to the cached thread context. + */ + void condUpdateThreadContext(); + + /** + * Update the KVM if the thread context is dirty. + */ + void condUpdateKvmState(); /** @} */ /** @{ */ @@ -391,7 +415,13 @@ * Is the gem5 context dirty? Set to true to force an update of * the KVM vCPU state upon the next call to kvmRun(). */ - bool contextDirty; + bool m5ContextDirty; + + /** + * Is the KVM state dirty? Set to true to force an update of + * the KVM vCPU state upon the next call to kvmRun(). + */ + bool kvmStateDirty; /** KVM internal ID of the vCPU */ const long vcpuID; diff -r 99f1e74d38f3 -r 4560fb29509f src/cpu/kvm/base.cc --- a/src/cpu/kvm/base.cc Fri Mar 08 09:18:09 2013 -0500 +++ b/src/cpu/kvm/base.cc Fri Mar 08 09:19:56 2013 -0500 @@ -72,7 +72,8 @@ _status(Idle), dataPort(name() + ".dcache_port", this), instPort(name() + ".icache_port", this), - contextDirty(true), + m5ContextDirty(true), + kvmStateDirty(false), vcpuID(vm.allocVCPUID()), vcpuFD(-1), vcpuMMapSize(0), _kvmRun(NULL), mmioRing(NULL), pageSize(sysconf(_SC_PAGE_SIZE)), @@ -205,6 +206,9 @@ void BaseKvmCPU::serializeThread(std::ostream &os, ThreadID tid) { + // Update the thread context so we have something to serialize. + condUpdateThreadContext(); + assert(tid == 0); assert(_status == Idle); thread->serialize(os); @@ -217,7 +221,7 @@ assert(tid == 0); assert(_status == Idle); thread->unserialize(cp, section); - contextDirty = true; + m5ContextDirty = true; } unsigned int @@ -263,10 +267,14 @@ void BaseKvmCPU::switchOut() { + DPRINTF(Kvm, "switchOut\n"); + + // Make sure to update the thread context in case, the new CPU + // will need to access it. + condUpdateThreadContext(); + BaseCPU::switchOut(); - DPRINTF(Kvm, "switchOut\n"); - // We should have drained prior to executing a switchOut, which // means that the tick event shouldn't be scheduled and the CPU is // idle. @@ -288,8 +296,9 @@ assert(_status == Idle); assert(threadContexts.size() == 1); - // Force a gem5 -> KVM context synchronization - contextDirty = true; + // The BaseCPU updated the thread context, make sure that we + // synchronize next time we enter start the CPU. + m5ContextDirty = true; } void @@ -368,6 +377,15 @@ suspendContext(thread_num); } +ThreadContext * +BaseKvmCPU::getContext(int tn) +{ + assert(tn == 0); + condUpdateThreadContext(); + return tc; +} + + Counter BaseKvmCPU::totalInsts() const { @@ -394,14 +412,8 @@ DPRINTF(KvmRun, "Entering KVM...\n"); - if (contextDirty) { - contextDirty = false; - updateKvmState(); - } - Tick ticksToExecute(mainEventQueue.nextTick() - curTick()); Tick ticksExecuted(kvmRun(ticksToExecute)); - updateThreadContext(); Tick delay(ticksExecuted + onKvmExit()); @@ -423,6 +435,13 @@ uint64_t baseCycles(hwCycles.read()); uint64_t baseInstrs(hwInstructions.read()); + // We might need to update the KVM state. + condUpdateKvmState(); + // Entering into KVM implies that we'll have to reload the thread + // context from KVM if we want to access it. Flag the KVM state as + // dirty with respect to the cached thread context. + kvmStateDirty = true; + if (ticks < runTimer->resolution()) { DPRINTF(KvmRun, "KVM: Adjusting tick count (%i -> %i)\n", ticks, runTimer->resolution()); @@ -604,6 +623,26 @@ #endif } +void +BaseKvmCPU::condUpdateThreadContext() +{ + if (!kvmStateDirty) + return; + + updateThreadContext(); + kvmStateDirty = false; +} + +void +BaseKvmCPU::condUpdateKvmState() +{ + if (!m5ContextDirty) + return; + + updateKvmState(); + m5ContextDirty = false; +} + Tick BaseKvmCPU::onKvmExit() {