whpx: Fixed incorrect CR8/TPR synchronization
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> Message-Id: <010b01d82874$bb4ef160$31ecd420$@sysprogs.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
e561890841
commit
5ad93fd351
@ -256,6 +256,21 @@ static int whpx_set_tsc(CPUState *cpu)
|
|||||||
return 0;
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr)
|
||||||
|
{
|
||||||
|
return tpr >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
static void whpx_set_registers(CPUState *cpu, int level)
|
static void whpx_set_registers(CPUState *cpu, int level)
|
||||||
{
|
{
|
||||||
struct whpx_state *whpx = &whpx_global;
|
struct whpx_state *whpx = &whpx_global;
|
||||||
@ -284,7 +299,7 @@ static void whpx_set_registers(CPUState *cpu, int level)
|
|||||||
v86 = (env->eflags & VM_MASK);
|
v86 = (env->eflags & VM_MASK);
|
||||||
r86 = !(env->cr[0] & CR0_PE_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);
|
vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state);
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
@ -475,6 +490,17 @@ static void whpx_get_registers(CPUState *cpu)
|
|||||||
hr);
|
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;
|
idx = 0;
|
||||||
|
|
||||||
/* Indexes for first 16 registers match between HV and QEMU definitions */
|
/* Indexes for first 16 registers match between HV and QEMU definitions */
|
||||||
|
Loading…
Reference in New Issue
Block a user