From: "Ivan Shcherbakov" <ivan@sysprogs.com>
To: <qemu-devel@nongnu.org>
Cc: armbru@redhat.com, mst@redhat.com
Subject: [PATCH 2/3] whpx: Fixed incorrect CR8/TPR synchronization
Date: Tue, 22 Feb 2022 21:18:00 -0800 [thread overview]
Message-ID: <010b01d82874$bb4ef160$31ecd420$@sysprogs.com> (raw)
This fixes the following error triggered when stopping and resuming a 64-bit
Linux kernel via gdb:
qemu-system-x86_64.exe: WHPX: Failed to set virtual processor context,
hr=c0350005
The previous logic for synchronizing the values did not take into account
that the lower 4 bits of
the CR8 register, containing the priority level, mapped to bits 7:4 of the
APIC.TPR register
(see section 10.8.6.1 of Volume 3 of Intel 64 and IA-32 Architectures
Software Developer's Manual).
The caused WHvSetVirtualProcessorRegisters() to fail with an error,
effectively preventing GDB from
changing the guest context.
Signed-off-by: Ivan Shcherbakov <ivan@sysprogs.com>
---
target/i386/whpx/whpx-all.c | 49 +++++++++++++++++++++++++++++++------
1 file changed, 41 insertions(+), 8 deletions(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index edd4fafbdf..8a8b5d55d1 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -256,6 +256,28 @@ static int whpx_set_tsc(CPUState *cpu)
return 0;
}
+/*
+ * The CR8 register in the CPU is mapped to the TPR register of the APIC,
+ * however, they use a slightly different encoding. Specifically:
+ *
+ * APIC.TPR[bits 7:4] = CR8[bits 3:0]
+ *
+ * This mechanism is described in section 10.8.6.1 of Volume 3 of Intel 64
+ * and IA-32 Architectures Software Developer's Manual.
+ *
+ * The functions below translate the value of CR8 to TPR and vice versa.
+ */
+
+static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr)
+{
+ return tpr >> 4;
+}
+
+static uint64_t whpx_cr8_to_apic_tpr(uint64_t cr8)
+{
+ return cr8 << 4;
+}
+
static void whpx_set_registers(CPUState *cpu, int level)
{
struct whpx_state *whpx = &whpx_global;
@@ -284,7 +306,7 @@ static void whpx_set_registers(CPUState *cpu, int level)
v86 = (env->eflags & VM_MASK);
r86 = !(env->cr[0] & CR0_PE_MASK);
- vcpu->tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
+ vcpu->tpr =
whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state));
vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state);
idx = 0;
@@ -475,6 +497,17 @@ static void whpx_get_registers(CPUState *cpu)
hr);
}
+ if (whpx_apic_in_platform()) {
+ /*
+ * Fetch the TPR value from the emulated APIC. It may get
overwritten
+ * below with the value from CR8 returned by
+ * WHvGetVirtualProcessorRegisters().
+ */
+ whpx_apic_get(x86_cpu->apic_state);
+ vcpu->tpr = whpx_apic_tpr_to_cr8(
+ cpu_get_apic_tpr(x86_cpu->apic_state));
+ }
+
idx = 0;
/* Indexes for first 16 registers match between HV and QEMU definitions
*/
@@ -521,8 +554,12 @@ static void whpx_get_registers(CPUState *cpu)
assert(whpx_register_names[idx] == WHvX64RegisterCr8);
tpr = vcxt.values[idx++].Reg64;
if (tpr != vcpu->tpr) {
+ /*
+ * TPR value stored in the CR8 register doesn't match the one
fetched
+ * from the emulated APIC. Override the latter with the former.
+ */
vcpu->tpr = tpr;
- cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
+ cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr));
}
/* 8 Debug Registers - Skipped */
@@ -600,10 +637,6 @@ static void whpx_get_registers(CPUState *cpu)
assert(idx == RTL_NUMBER_OF(whpx_register_names));
- if (whpx_apic_in_platform()) {
- whpx_apic_get(x86_cpu->apic_state);
- }
-
x86_update_hflags(env);
return;
@@ -865,7 +898,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
}
/* Sync the TPR to the CR8 if was modified during the intercept */
- tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
+ tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state));
if (tpr != vcpu->tpr) {
vcpu->tpr = tpr;
reg_values[reg_count].Reg64 = tpr;
@@ -914,7 +947,7 @@ static void whpx_vcpu_post_run(CPUState *cpu)
if (vcpu->tpr != tpr) {
vcpu->tpr = tpr;
qemu_mutex_lock_iothread();
- cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr);
+ cpu_set_apic_tpr(x86_cpu->apic_state,
whpx_cr8_to_apic_tpr(vcpu->tpr));
qemu_mutex_unlock_iothread();
}
--
2.29.2.windows.3
reply other threads:[~2022-02-23 5:19 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='010b01d82874$bb4ef160$31ecd420$@sysprogs.com' \
--to=ivan@sysprogs.com \
--cc=armbru@redhat.com \
--cc=mst@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.