summaryrefslogtreecommitdiff
path: root/src/cpu/kvm/x86_cpu.cc
diff options
context:
space:
mode:
authorAndreas Sandberg <andreas@sandberg.pp.se>2014-03-16 17:28:23 +0100
committerAndreas Sandberg <andreas@sandberg.pp.se>2014-03-16 17:28:23 +0100
commitf791e7b313c6f5c2b30f96c35f675d523def8a3a (patch)
tree495096f78ab0ab8ddc0a5a3c0cd2c2768e0e31e7 /src/cpu/kvm/x86_cpu.cc
parent32bf74cb8ee4c9293636041c05d93fbfd01087da (diff)
downloadgem5-f791e7b313c6f5c2b30f96c35f675d523def8a3a.tar.xz
kvm: x86: Add support for x86 INIT and STARTUP handling
This changeset adds support for INIT and STARTUP IPI handling. We currently handle both of these interrupts in gem5 and transfer the state to KVM. Since we do not have a BIOS loaded, we pretend that the INIT interrupt suspends the CPU after reset. --HG-- extra : rebase_source : 7f3b25f3801d68f668b6cd91eaf50d6f48ee2a6a
Diffstat (limited to 'src/cpu/kvm/x86_cpu.cc')
-rw-r--r--src/cpu/kvm/x86_cpu.cc39
1 files changed, 33 insertions, 6 deletions
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