target/i386: emulate: segmentation rework
Make accesses to segments all go through read_segment_descriptor to be able to fetch segment state on-demand. Switch away from SegmentCache to the x86_segment_descriptor that is already used by read_segment_descriptor. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Link: https://lore.kernel.org/r/20260324151323.74473-11-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Mohamed Mediouni committed
Mar 24, 2026 at 16:13 UTC
09442d98abd1bf2ae85bdf0e3f578904311dc31f
1 file changed
+19
-31
target/i386/emulate/x86_helpers.c
+19
-31
@@ -43,49 +43,37 @@ static CpuMode cpu_mode(CPUState *cpu)
43
return m;
44
}
45
46
-static bool segment_type_ro(const SegmentCache *seg)
46
+static bool segment_type_ro(const x86_segment_descriptor desc)
47
{
48
- uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
48
+ uint32_t type_ = desc.type;
49
return (type_ & (~RWRX_SEGMENT_TYPE)) == 0;
50
}
51
52
-static bool segment_type_code(const SegmentCache *seg)
52
+static bool segment_type_code(const x86_segment_descriptor desc)
53
{
54
- uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
54
+ uint32_t type_ = desc.type;
55
return (type_ & CODE_SEGMENT_TYPE) != 0;
56
}
57
58
-static bool segment_expands_down(const SegmentCache *seg)
58
+static bool segment_expands_down(const x86_segment_descriptor desc)
59
{
60
- uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
60
+ uint32_t type_ = desc.type;
61
62
- if (segment_type_code(seg)) {
62
+ if (segment_type_code(desc)) {
63
return false;
64
}
65
66
return (type_ & EXPAND_DOWN_SEGMENT_TYPE) != 0;
67
}
68
69
-static uint32_t segment_limit(const SegmentCache *seg)
69
+static uint8_t segment_db(const x86_segment_descriptor desc)
70
{
71
- uint32_t limit = seg->limit;
72
- uint32_t granularity = (seg->flags & DESC_G_MASK) != 0;
73
-
74
- if (granularity != 0) {
75
- limit = (limit << 12) | 0xFFF;
76
- }
77
-
78
- return limit;
71
+ return desc.db;
72
}
73
81
-static uint8_t segment_db(const SegmentCache *seg)
74
+static uint32_t segment_max_limit(const x86_segment_descriptor desc)
75
{
83
- return (seg->flags >> DESC_B_SHIFT) & 1;
84
-}
85
-
86
-static uint32_t segment_max_limit(const SegmentCache *seg)
87
-{
88
- if (segment_db(seg) != 0) {
76
+ if (segment_db(desc) != 0) {
77
return 0xFFFFFFFF;
78
}
79
return 0xFFFF;
@@ -96,15 +84,15 @@ static int linearize(CPUState *cpu,
84
X86Seg seg_idx)
85
{
86
enum CpuMode mode;
99
- X86CPU *x86_cpu = X86_CPU(cpu);
100
- CPUX86State *env = &x86_cpu->env;
101
- SegmentCache *seg = &env->segs[seg_idx];
102
- target_ulong base = seg->base;
87
+ struct x86_segment_descriptor desc;
88
+ target_ulong base;
89
target_ulong logical_addr_32b;
90
uint32_t limit;
91
/* TODO: the emulator will not pass us "write" indicator yet */
92
bool write = false;
93
94
+ emul_ops->read_segment_descriptor(cpu, &desc, seg_idx);
95
+ base = x86_segment_base(&desc);
96
mode = cpu_mode(cpu);
97
98
switch (mode) {
@@ -116,21 +104,21 @@ static int linearize(CPUState *cpu,
104
break;
105
case PROTECTED_MODE:
106
case REAL_MODE:
119
- if (segment_type_ro(seg) && write) {
107
+ if (segment_type_ro(desc) && write) {
108
error_report("Cannot write to read-only segment");
109
return -1;
110
}
111
112
logical_addr_32b = logical_addr & 0xFFFFFFFF;
125
- limit = segment_limit(seg);
113
+ limit = x86_segment_limit(&desc);
114
127
- if (segment_expands_down(seg)) {
115
+ if (segment_expands_down(desc)) {
116
if (logical_addr_32b >= limit) {
117
error_report("Address exceeds limit (expands down)");
118
return -1;
119
}
120
133
- limit = segment_max_limit(seg);
121
+ limit = segment_max_limit(desc);
122
}
123
124
if (logical_addr_32b > limit) {