@samitouri / QOSamiQemu / commits / 7d6231dfb5

target/i386/mshv: Fix segment regression in MMIO emu

When the segmentation code has been reworked, there is now an unconditional call to emul_ops->read_segment_descriptor(). The MSHV impl was delegating this to x86_read_segement_descriptor(), which read from the GDT in guest memory. This fails for selector.idx == 0 and when no GDT is set up (which is the case in real mode). In the fix we change the MSHV impl to fill segment descriptor from SegmentCache, that was populated from the hypervisor by mshv_load_regs() before instruction emulation. Fixes: 09442d98ab (target/i386: emulate: segmentation rework) Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com> Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr> Link: https://lore.kernel.org/r/20260410142652.367541-1-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Magnus Kulke committed Apr 10, 2026 at 16:26 UTC 7d6231dfb5eaba55b7cf266b0993adaccf0381d0
1 file changed +32 -7
target/i386/mshv/mshv-cpu.c
+32 -7
@@ -1552,17 +1552,42 @@ static void read_segment_descriptor(CPUState *cpu,
1552 struct x86_segment_descriptor *desc,
1553 enum X86Seg seg_idx)
1554 {
1555 - bool ret;
1555 X86CPU *x86_cpu = X86_CPU(cpu);
1556 CPUX86State *env = &x86_cpu->env;
1557 SegmentCache *seg = &env->segs[seg_idx];
1559 - x86_segment_selector sel = { .sel = seg->selector & 0xFFFF };
1560 -
1561 - ret = x86_read_segment_descriptor(cpu, desc, sel);
1562 - if (ret == false) {
1563 - error_report("failed to read segment descriptor");
1564 - abort();
1558 + uint32_t limit;
1559 +
1560 + memset(desc, 0, sizeof(struct x86_segment_descriptor));
1561 +
1562 + desc->type = (seg->flags & DESC_TYPE_MASK) >> DESC_TYPE_SHIFT;
1563 + desc->s = (seg->flags & DESC_S_MASK) >> DESC_S_SHIFT;
1564 + desc->dpl = (seg->flags & DESC_DPL_MASK) >> DESC_DPL_SHIFT;
1565 + desc->p = (seg->flags & DESC_P_MASK) >> DESC_P_SHIFT;
1566 + desc->avl = (seg->flags & DESC_AVL_MASK) >> DESC_AVL_SHIFT;
1567 + desc->l = (seg->flags & DESC_L_MASK) >> DESC_L_SHIFT;
1568 + desc->db = (seg->flags & DESC_B_MASK) >> DESC_B_SHIFT;
1569 + desc->g = (seg->flags & DESC_G_MASK) >> DESC_G_SHIFT;
1570 +
1571 + /*
1572 + * SegmentCache stores the hypervisor-provided value verbatim (populated by
1573 + * mshv_load_regs). We need to convert it to format expected by the
1574 + * instruction emulator. We can have a limit value > 0xfffff with
1575 + * granularity of 0 (byte granularity), which is not representable
1576 + * in real x86_segment_descriptor. In this case we set granularity to 1
1577 + * (4k granularity) and shift the limit accordingly.
1578 + *
1579 + * This quirk has been adopted from "whpx_segment_to_x86_description()"
1580 + */
1581 +
1582 + if (!desc->g && seg->limit <= 0xfffff) {
1583 + limit = seg->limit;
1584 + } else {
1585 + limit = seg->limit >> 12;
1586 + desc->g = 1;
1587 }
1588 +
1589 + x86_set_segment_limit(desc, limit);
1590 + x86_set_segment_base(desc, seg->base);
1591 }
1592
1593 static const struct x86_emul_ops mshv_x86_emul_ops = {