From 1e718809f3985eede58df3e5bc8735342424bdc8 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Thu, 7 Jul 2011 21:12:45 +0300 Subject: [PATCH] kvm tools: Fix guest single-stepping setup "K. Watts" writes: When the singlestep is enabled the ioctl to sent out when the kvm_cpu is initialized (kvm-cpu.c in the for loop that gets each vcpu built). When the ioct goes out the CPU is sitting at the initialization vector of 0xf000:0xfff0 on CPU #0 and 0x000000 on the other SMP CPUs. The new host kernel code that handles setting the TF was changed in 2.6.32 and again at 2.6.38. 2.6.32 seems just flat broken, but 2.6.38 checks that the linear address of the RIP matches what it was when the KVM_GUESTDBG_SINGLESTEP flag was set. Because the kvm-tool doesn't start the CPU at the initialization vector (0xfff0) (0x7c00 for the MBR and where ever you guys map the linux kernel to) they don't match and the host kernel won't set the trap flag. Basically the debug and singlestep ioclts need to happen after the CPU has been initialized. I moved kvm_cpu__enable_singlestep to happen in kvm_cpu__reset_vcpu after the registers are set (EIP points to boot address) and the TRAP flags get set and all is good with the world. Singlestepping is disabled when the guest issues a CLI because the Linux host doesn't support features in new Intel and AMD CPUs. We can sort of "shadow" the interrupt mask and still get the CPU to trap out at ever instruction even when the guest has disabled interrupts on the CPU. I have to get the bios disk handler working completely first, but that may be my next task so that we can trace all the CPU instructions. My current hack is to just re-enable the trap flag every time a VMEXIT occurs. I get enough instructions to get me by. This patch fixes the problem by moving the kvm_cpu__enable_singlestep() into kvm_cpu__start(). Suggested-by: K. Watts Cc: Sasha Levin Signed-off-by: Pekka Enberg --- tools/kvm/include/kvm/kvm.h | 2 ++ tools/kvm/kvm-cpu.c | 3 +++ tools/kvm/kvm-run.c | 5 ++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index 5cfb0d8e9b0b..8792af21f7da 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/include/kvm/kvm.h @@ -35,6 +35,8 @@ struct kvm { bool nmi_disabled; + bool single_step; + u16 boot_selector; u16 boot_ip; u16 boot_sp; diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c index f57d42e05452..2f5d23c70ab6 100644 --- a/tools/kvm/kvm-cpu.c +++ b/tools/kvm/kvm-cpu.c @@ -439,6 +439,9 @@ int kvm_cpu__start(struct kvm_cpu *cpu) kvm_cpu__setup_cpuid(cpu); kvm_cpu__reset_vcpu(cpu); + if (cpu->kvm->single_step) + kvm_cpu__enable_singlestep(cpu); + for (;;) { if (cpu->paused) { kvm__notify_paused(); diff --git a/tools/kvm/kvm-run.c b/tools/kvm/kvm-run.c index 57791f5d43bc..048b6a29bb23 100644 --- a/tools/kvm/kvm-run.c +++ b/tools/kvm/kvm-run.c @@ -559,6 +559,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) kvm = kvm__init(kvm_dev, ram_size, guest_name); + kvm->single_step = single_step; + ioeventfd__init(); max_cpus = kvm__max_cpus(kvm); @@ -672,9 +674,6 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix) kvm_cpus[i] = kvm_cpu__init(kvm, i); if (!kvm_cpus[i]) die("unable to initialize KVM VCPU"); - - if (single_step) - kvm_cpu__enable_singlestep(kvm_cpus[i]); } kvm__init_ram(kvm); -- 2.39.5