@samitouri / QOSamiQemu / commits / 69dfc078a6

hw: i386: vapic: enable on WHPX with user-mode irqchip

Alleviate a performance bottleneck on legacy Windows guests. In my test setup, this makes Windows XP boot times be 20x faster than they're otherwise. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Link: https://lore.kernel.org/r/20260226181930.53170-4-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Mohamed Mediouni committed Feb 26, 2026 at 19:19 UTC 69dfc078a6f03ce643e050de6360887df6c3406c
1 file changed +18 -6
hw/i386/vapic.c
+18 -6
@@ -16,6 +16,7 @@
16 #include "system/cpus.h"
17 #include "system/hw_accel.h"
18 #include "system/kvm.h"
19 +#include "system/whpx.h"
20 #include "system/runstate.h"
21 #include "system/address-spaces.h"
22 #include "hw/i386/apic_internal.h"
@@ -229,7 +230,8 @@ static int evaluate_tpr_instruction(VAPICROMState *s, X86CPU *cpu,
230 return -1;
231 }
232
232 - if (kvm_enabled() && !kvm_irqchip_in_kernel()) {
233 + if ((kvm_enabled() && !kvm_irqchip_in_kernel())
234 + || (whpx_enabled() && !whpx_irqchip_in_kernel())) {
235 /*
236 * KVM without kernel-based TPR access reporting will pass an IP that
237 * points after the accessing instruction. So we need to look backward
@@ -549,7 +551,7 @@ static int patch_hypercalls(VAPICROMState *s)
551 cpu_physical_memory_read(rom_paddr, rom, s->rom_size);
552
553 for (pos = 0; pos < s->rom_size - sizeof(vmcall_pattern); pos++) {
552 - if (kvm_irqchip_in_kernel()) {
554 + if (kvm_enabled() && kvm_irqchip_in_kernel()) {
555 pattern = outl_pattern;
556 alternates[0] = outl_pattern[7];
557 alternates[1] = outl_pattern[7];
@@ -679,16 +681,25 @@ static void vapic_write(void *opaque, hwaddr addr, uint64_t data,
681 }
682 break;
683 case 1:
682 - if (kvm_enabled()) {
684 + if (kvm_enabled() || (whpx_enabled() && !whpx_irqchip_in_kernel())) {
685 /*
686 * Disable triggering instruction in ROM by writing a NOP.
687 *
688 * We cannot do this in TCG mode as the reported IP is not
689 * accurate.
690 + *
691 + * Oddly enough, KVM increments EIP _before_ the execution
692 + * of the instruction is finished.
693 */
694 pause_all_vcpus();
690 - patch_byte(cpu, env->eip - 2, 0x66);
691 - patch_byte(cpu, env->eip - 1, 0x90);
695 + if (!kvm_enabled()) {
696 + patch_byte(cpu, env->eip, 0x66);
697 + patch_byte(cpu, env->eip + 1, 0x90);
698 + }
699 + else {
700 + patch_byte(cpu, env->eip - 2, 0x66);
701 + patch_byte(cpu, env->eip - 1, 0x90);
702 + }
703 resume_all_vcpus();
704 }
705
@@ -705,7 +716,8 @@ static void vapic_write(void *opaque, hwaddr addr, uint64_t data,
716 break;
717 default:
718 case 4:
708 - if (!kvm_irqchip_in_kernel()) {
719 + if ((kvm_enabled() && !kvm_irqchip_in_kernel())
720 + || (whpx_enabled() && !whpx_irqchip_in_kernel())) {
721 apic_poll_irq(cpu->apic_state);
722 }
723 break;