diff options
Diffstat (limited to 'src/cpu/kvm')
-rw-r--r-- | src/cpu/kvm/base.cc | 6 | ||||
-rw-r--r-- | src/cpu/kvm/base.hh | 5 | ||||
-rw-r--r-- | src/cpu/kvm/x86_cpu.cc | 39 |
3 files changed, 44 insertions, 6 deletions
diff --git a/src/cpu/kvm/base.cc b/src/cpu/kvm/base.cc index 26ffe37a5..1149a3704 100644 --- a/src/cpu/kvm/base.cc +++ b/src/cpu/kvm/base.cc @@ -543,6 +543,12 @@ BaseKvmCPU::tick() delay = kvmRun(ticksToExecute); } + // The CPU might have been suspended before entering into + // KVM. Assume that the CPU was suspended /before/ entering + // into KVM and skip the exit handling. + if (_status == Idle) + break; + // 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. diff --git a/src/cpu/kvm/base.hh b/src/cpu/kvm/base.hh index 5a0b80b15..8191d9d92 100644 --- a/src/cpu/kvm/base.hh +++ b/src/cpu/kvm/base.hh @@ -241,6 +241,11 @@ class BaseKvmCPU : public BaseCPU * make sure that the KVM state is synchronized and that the TC is * invalidated after entering KVM. * + * @note This method does not normally cause any state + * transitions. However, if it may suspend the CPU by suspending + * the thread, which leads to a transition to the Idle state. In + * such a case, kvm <i>must not</i> be entered. + * * @param ticks Number of ticks to execute, set to 0 to exit * immediately after finishing pending operations. * @return Number of ticks executed (see note) diff --git a/src/cpu/kvm/x86_cpu.cc b/src/cpu/kvm/x86_cpu.cc index b79207fab..3313c8db0 100644 --- a/src/cpu/kvm/x86_cpu.cc +++ b/src/cpu/kvm/x86_cpu.cc @@ -1137,7 +1137,27 @@ X86KvmCPU::deliverInterrupts() interrupts->updateIntrInfo(tc); X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get())); - if (x86int) { + if (dynamic_cast<NonMaskableInterrupt *>(fault.get())) { + DPRINTF(KvmInt, "Delivering NMI\n"); + kvmNonMaskableInterrupt(); + } else if (dynamic_cast<InitInterrupt *>(fault.get())) { + DPRINTF(KvmInt, "INIT interrupt\n"); + fault.get()->invoke(tc); + // Delay the kvm state update since we won't enter KVM on this + // tick. + threadContextDirty = true; + // HACK: gem5 doesn't actually have any BIOS code, which means + // that we need to halt the thread and wait for a startup + // interrupt before restarting the thread. The simulated CPUs + // use the same kind of hack using a microcode routine. + thread->suspend(); + } else if (dynamic_cast<StartupInterrupt *>(fault.get())) { + DPRINTF(KvmInt, "STARTUP interrupt\n"); + fault.get()->invoke(tc); + // The kvm state is assumed to have been updated when entering + // kvmRun(), so we need to update manually it here. + updateKvmState(); + } else if (x86int) { struct kvm_interrupt kvm_int; kvm_int.irq = x86int->getVector(); @@ -1145,9 +1165,6 @@ X86KvmCPU::deliverInterrupts() fault->name(), kvm_int.irq); kvmInterrupt(kvm_int); - } else if (dynamic_cast<NonMaskableInterrupt *>(fault.get())) { - DPRINTF(KvmInt, "Delivering NMI\n"); - kvmNonMaskableInterrupt(); } else { panic("KVM: Unknown interrupt type\n"); } @@ -1160,7 +1177,12 @@ X86KvmCPU::kvmRun(Tick ticks) struct kvm_run &kvm_run(*getKvmRunState()); if (interrupts->checkInterruptsRaw()) { - if (kvm_run.ready_for_interrupt_injection) { + if (interrupts->hasPendingUnmaskable()) { + DPRINTF(KvmInt, + "Delivering unmaskable interrupt.\n"); + syncThreadContext(); + deliverInterrupts(); + } else if (kvm_run.ready_for_interrupt_injection) { // KVM claims that it is ready for an interrupt. It might // be lying if we just updated rflags and disabled // interrupts (e.g., by doing a CPU handover). Let's sync @@ -1187,7 +1209,12 @@ X86KvmCPU::kvmRun(Tick ticks) kvm_run.request_interrupt_window = 0; } - return kvmRunWrapper(ticks); + // The CPU might have been suspended as a result of the INIT + // interrupt delivery hack. In that case, don't enter into KVM. + if (_status == Idle) + return 0; + else + return kvmRunWrapper(ticks); } Tick |