whpx: i386: fetch segments on-demand
Instead of save/restore, fetch segments dynamically. Rely on the fetched state instead of loading from memory. Or, if available, on the VM exit context. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Link: https://lore.kernel.org/r/20260324151323.74473-12-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Mohamed Mediouni committed
Mar 24, 2026 at 16:13 UTC
9489224382b43893069899a2b543bcc22b6d7b4f
1 file changed
+60
-11
target/i386/whpx/whpx-all.c
+60
-11
@@ -868,21 +868,70 @@ static int whpx_handle_portio(CPUState *cpu,
868
return 0;
869
}
870
871
+static void whpx_segment_to_x86_descriptor(CPUState *cpu, WHV_X64_SEGMENT_REGISTER* reg,
872
+ struct x86_segment_descriptor *desc)
873
+{
874
+ uint32_t limit;
875
+ desc->g = reg->Granularity;
876
+
877
+ /*
878
+ * Hyper-V can return reg->Granularity == 0
879
+ * with a higher limit than 0xfffff.
880
+ *
881
+ * Detect that case and set desc->g
882
+ * with shifting the limit properly.
883
+ */
884
+ if (!desc->g && reg->Limit <= 0xfffff) {
885
+ limit = reg->Limit;
886
+ } else {
887
+ limit = (reg->Limit >> 12);
888
+ desc->g = 1;
889
+ }
890
+
891
+ x86_set_segment_limit(desc, limit);
892
+ x86_set_segment_base(desc, reg->Base);
893
+
894
+ desc->type = reg->SegmentType;
895
+ desc->s = reg->NonSystemSegment;
896
+ desc->dpl = reg->DescriptorPrivilegeLevel;
897
+ desc->p = reg->Present;
898
+ desc->avl = reg->Available;
899
+ desc->l = reg->Long;
900
+ desc->db = reg->Default;
901
+}
902
+
903
+static void whpx_read_segment_descriptor(CPUState *cpu, WHV_X64_SEGMENT_REGISTER* reg,
904
+ X86Seg seg)
905
+{
906
+ AccelCPUState *vcpu = cpu->accel;
907
+ WHV_REGISTER_NAME reg_name = WHvX64RegisterEs + seg;
908
+ WHV_REGISTER_VALUE val;
909
+
910
+ if (seg == R_CS) {
911
+ *reg = vcpu->exit_ctx.VpContext.Cs;
912
+ return;
913
+ }
914
+ if (vcpu->exit_ctx.ExitReason == WHvRunVpExitReasonX64IoPortAccess) {
915
+ if (seg == R_DS) {
916
+ *reg = vcpu->exit_ctx.IoPortAccess.Ds;
917
+ return;
918
+ } else if (seg == R_ES) {
919
+ *reg = vcpu->exit_ctx.IoPortAccess.Es;
920
+ return;
921
+ }
922
+ }
923
+
924
+ whpx_get_reg(cpu, reg_name, &val);
925
+ *reg = val.Segment;
926
+}
927
+
928
static void read_segment_descriptor(CPUState *cpu,
929
struct x86_segment_descriptor *desc,
930
enum X86Seg seg_idx)
931
{
875
- bool ret;
876
- X86CPU *x86_cpu = X86_CPU(cpu);
877
- CPUX86State *env = &x86_cpu->env;
878
- SegmentCache *seg = &env->segs[seg_idx];
879
- x86_segment_selector sel = { .sel = seg->selector & 0xFFFF };
880
-
881
- ret = x86_read_segment_descriptor(cpu, desc, sel);
882
- if (ret == false) {
883
- error_report("failed to read segment descriptor");
884
- abort();
885
- }
932
+ WHV_X64_SEGMENT_REGISTER reg;
933
+ whpx_read_segment_descriptor(cpu, ®, seg_idx);
934
+ whpx_segment_to_x86_descriptor(cpu, ®, desc);
935
}
936
937
static bool is_protected_mode(CPUState *cpu)