Implement APIC IRR interrupt priorities.
Even with kernel-irqchip=off, Hyper-V is aware of interrupt priorities
and implements CR8/TPR, with the InterruptPriority field being followed.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 7a31dc6427..8cd81fffee 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -1588,6 +1588,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
UINT32 reg_count = 0;
WHV_REGISTER_VALUE reg_values[3];
WHV_REGISTER_NAME reg_names[3];
+ int irr = apic_get_highest_priority_irr(x86_cpu->apic_state);
memset(&new_int, 0, sizeof(new_int));
memset(reg_values, 0, sizeof(reg_values));
@@ -1623,10 +1624,20 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
}
}
+ if (irr == -1) {
+ if (pic_get_output(isa_pic)) {
+ /* In case it's a PIC interrupt */
+ irr = 0;
+ } else if (cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD)) {
+ abort();
+ }
+ }
+
/* Get pending hard interruption or replay one that was overwritten */
if (!whpx_irqchip_in_kernel()) {
if (!vcpu->interruption_pending &&
- vcpu->interruptable && (env->eflags & IF_MASK)) {
+ vcpu->interruptable && (env->eflags & IF_MASK)
+ && (vcpu->tpr < irr || irr == 0)) {
assert(!new_int.InterruptionPending);
if (cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD)) {
cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
@@ -1683,13 +1694,17 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
}
/* Update the state of the interrupt delivery notification */
- if (!vcpu->window_registered &&
+ if ((!vcpu->window_registered ||
+ (vcpu->window_priority < irr && vcpu->window_priority != 0) ||
+ (irr == 0 && vcpu->window_priority != 0)) &&
cpu_test_interrupt(cpu, CPU_INTERRUPT_HARD)) {
reg_values[reg_count].DeliverabilityNotifications =
(WHV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER) {
- .InterruptNotification = 1
+ .InterruptNotification = 1,
+ .InterruptPriority = irr >> 4
};
vcpu->window_registered = 1;
+ vcpu->window_priority = irr;
reg_names[reg_count] = WHvX64RegisterDeliverabilityNotifications;
reg_count += 1;
}
@@ -1703,7 +1718,7 @@ static void whpx_vcpu_pre_run(CPUState *cpu)
reg_names, reg_count, reg_values);
if (FAILED(hr)) {
error_report("WHPX: Failed to set interrupt state registers,"
- " hr=%08lx", hr);
+ " hr=%08lx, InterruptPriority=%i", hr, irr >> 4);
}
}
}
@@ -1919,6 +1934,7 @@ int whpx_vcpu_run(CPUState *cpu)
case WHvRunVpExitReasonX64InterruptWindow:
vcpu->ready_for_pic_interrupt = 1;
vcpu->window_registered = 0;
+ vcpu->window_priority = 0;
ret = 0;
break;
--
2.50.1 (Apple Git-155)