target/i386/mshv: use the register page to get registers
Change the mshv_load_regs to use the register page when it is mmapped and is valid. Otherwise use the existing logic that uses ioctls to fetch registers. When retrieving the special registers, there are some registers that are not present in the register page: TR, LDTR, GDTR, IDTR, CR2, APIC_BASE. For this ones we still need to use ioctls to correctly fetch. Signed-off-by: Doru Blânzeanu <dblanzeanu@linux.microsoft.com> Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr> Link: https://lore.kernel.org/r/20260428135053.251200-6-dblanzeanu@linux.microsoft.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Doru Blânzeanu committed
Apr 28, 2026 at 16:50 UTC
40072a7391eb9016f71009db223f9e93d084de5e
1 file changed
+117
target/i386/mshv/mshv-cpu.c
+117
@@ -270,6 +270,15 @@ static int get_xc_reg(CPUState *cpu)
270
return 0;
271
}
272
273
+static enum hv_register_name NON_VP_PAGE_REGISTER_NAMES[6] = {
274
+ HV_X64_REGISTER_TR,
275
+ HV_X64_REGISTER_LDTR,
276
+ HV_X64_REGISTER_GDTR,
277
+ HV_X64_REGISTER_IDTR,
278
+ HV_X64_REGISTER_CR2,
279
+ HV_X64_REGISTER_APIC_BASE,
280
+};
281
+
282
static int translate_gva(const CPUState *cpu, uint64_t gva, uint64_t *gpa,
283
uint64_t flags)
284
{
@@ -570,6 +579,106 @@ static void populate_special_regs(const hv_register_assoc *assocs,
579
cpu_set_apic_base(x86cpu->apic_state, assocs[16].value.reg64);
580
}
581
582
+static void mshv_get_standard_regs_vp_page(CPUState *cpu)
583
+{
584
+ X86CPU *x86cpu = X86_CPU(cpu);
585
+ CPUX86State *env = &x86cpu->env;
586
+
587
+ /* General Purpose Registers */
588
+ env->regs[R_EAX] = env->regs_page->rax;
589
+ env->regs[R_EBX] = env->regs_page->rbx;
590
+ env->regs[R_ECX] = env->regs_page->rcx;
591
+ env->regs[R_EDX] = env->regs_page->rdx;
592
+ env->regs[R_ESI] = env->regs_page->rsi;
593
+ env->regs[R_EDI] = env->regs_page->rdi;
594
+ env->regs[R_ESP] = env->regs_page->rsp;
595
+ env->regs[R_EBP] = env->regs_page->rbp;
596
+ env->regs[R_R8] = env->regs_page->r8;
597
+ env->regs[R_R9] = env->regs_page->r9;
598
+ env->regs[R_R10] = env->regs_page->r10;
599
+ env->regs[R_R11] = env->regs_page->r11;
600
+ env->regs[R_R12] = env->regs_page->r12;
601
+ env->regs[R_R13] = env->regs_page->r13;
602
+ env->regs[R_R14] = env->regs_page->r14;
603
+ env->regs[R_R15] = env->regs_page->r15;
604
+
605
+ env->eip = env->regs_page->rip;
606
+ env->eflags = env->regs_page->rflags;
607
+ rflags_to_lflags(env);
608
+}
609
+
610
+static int mshv_get_special_regs_vp_page(CPUState *cpu)
611
+{
612
+ X86CPU *x86cpu = X86_CPU(cpu);
613
+ CPUX86State *env = &x86cpu->env;
614
+ struct hv_register_assoc assocs[ARRAY_SIZE(NON_VP_PAGE_REGISTER_NAMES)];
615
+ int ret;
616
+ size_t n_regs = ARRAY_SIZE(NON_VP_PAGE_REGISTER_NAMES);
617
+ hv_x64_segment_register seg;
618
+
619
+ /* Populate special registers that are in the VP register page */
620
+ env->cr[0] = env->regs_page->cr0;
621
+ env->cr[3] = env->regs_page->cr3;
622
+ env->cr[4] = env->regs_page->cr4;
623
+ env->efer = env->regs_page->efer;
624
+ cpu_set_apic_tpr(x86cpu->apic_state, env->regs_page->cr8);
625
+
626
+ /* Segment Registers - copy from packed struct to avoid unaligned access */
627
+ memcpy(&seg, &env->regs_page->es, sizeof(hv_x64_segment_register));
628
+ populate_segment_reg(&seg, &env->segs[R_ES]);
629
+ memcpy(&seg, &env->regs_page->cs, sizeof(hv_x64_segment_register));
630
+ populate_segment_reg(&seg, &env->segs[R_CS]);
631
+ memcpy(&seg, &env->regs_page->ss, sizeof(hv_x64_segment_register));
632
+ populate_segment_reg(&seg, &env->segs[R_SS]);
633
+ memcpy(&seg, &env->regs_page->ds, sizeof(hv_x64_segment_register));
634
+ populate_segment_reg(&seg, &env->segs[R_DS]);
635
+ memcpy(&seg, &env->regs_page->fs, sizeof(hv_x64_segment_register));
636
+ populate_segment_reg(&seg, &env->segs[R_FS]);
637
+ memcpy(&seg, &env->regs_page->gs, sizeof(hv_x64_segment_register));
638
+ populate_segment_reg(&seg, &env->segs[R_GS]);
639
+
640
+ /* The rest of the special registers that are not in the VP register page */
641
+ for (size_t i = 0; i < n_regs; i++) {
642
+ assocs[i].name = NON_VP_PAGE_REGISTER_NAMES[i];
643
+ }
644
+
645
+ ret = mshv_get_generic_regs(cpu, assocs, n_regs);
646
+ if (ret < 0) {
647
+ error_report("failed to get non-vp-page special registers");
648
+ return -1;
649
+ }
650
+
651
+ /* Non-VP page registers - TR, LDTR, GDTR, IDTR, CR2, APIC_BASE */
652
+ populate_segment_reg(&assocs[0].value.segment, &env->tr);
653
+ populate_segment_reg(&assocs[1].value.segment, &env->ldt);
654
+
655
+ populate_table_reg(&assocs[2].value.table, &env->gdt);
656
+ populate_table_reg(&assocs[3].value.table, &env->idt);
657
+ env->cr[2] = assocs[4].value.reg64;
658
+
659
+ cpu_set_apic_base(x86cpu->apic_state, assocs[5].value.reg64);
660
+
661
+ return ret;
662
+}
663
+
664
+static int mshv_get_registers_vp_page(CPUState *cpu)
665
+{
666
+ int ret;
667
+
668
+ /* General Purpose Registers */
669
+ mshv_get_standard_regs_vp_page(cpu);
670
+
671
+ /* Special Registers - makes a hypercall */
672
+ ret = mshv_get_special_regs_vp_page(cpu);
673
+ if (ret < 0) {
674
+ error_report("failed to get special registers for vp page");
675
+ return -1;
676
+ }
677
+
678
+ return 0;
679
+}
680
+
681
+
682
static int get_special_regs(CPUState *cpu)
683
{
684
struct hv_register_assoc assocs[ARRAY_SIZE(SPECIAL_REGISTER_NAMES)];
@@ -592,8 +701,16 @@ static int get_special_regs(CPUState *cpu)
701
702
static int load_regs(CPUState *cpu)
703
{
704
+ X86CPU *x86_cpu = X86_CPU(cpu);
705
+ CPUX86State *env = &x86_cpu->env;
706
int ret;
707
708
+ /* Use register vp page to optimize registers access */
709
+ if (env->regs_page && env->regs_page->isvalid != 0) {
710
+ ret = mshv_get_registers_vp_page(cpu);
711
+ return ret;
712
+ }
713
+
714
ret = get_standard_regs(cpu);
715
if (ret < 0) {
716
return ret;