PCem
view src/x86_ops_pmode.h @ 155:6b3e1b9d0220
Fixed SGDT/SIDT on 286, Windows 3.0 detects CPU correctly again.
| author | TomW |
|---|---|
| date | Fri Sep 05 21:40:21 2014 +0100 |
| parents | 9c201151bb4b |
| children |
line source
1 static int opARPL_a16(uint32_t fetchdat)
2 {
3 uint16_t temp_seg;
5 NOTRM
6 fetch_ea_16(fetchdat);
8 temp_seg = geteaw(); if (abrt) return 0;
10 flags_rebuild();
11 if ((temp_seg & 3) < (regs[reg].w & 3))
12 {
13 temp_seg = (temp_seg & 0xfffc) | (regs[reg].w & 3);
14 seteaw(temp_seg); if (abrt) return 0;
15 flags |= Z_FLAG;
16 }
17 else
18 flags &= ~Z_FLAG;
20 cycles -= is486 ? 9 : 20;
21 return 0;
22 }
23 static int opARPL_a32(uint32_t fetchdat)
24 {
25 uint16_t temp_seg;
27 NOTRM
28 fetch_ea_32(fetchdat);
30 temp_seg = geteaw(); if (abrt) return 0;
32 flags_rebuild();
33 if ((temp_seg & 3) < (regs[reg].w & 3))
34 {
35 temp_seg = (temp_seg & 0xfffc) | (regs[reg].w & 3);
36 seteaw(temp_seg); if (abrt) return 0;
37 flags |= Z_FLAG;
38 }
39 else
40 flags &= ~Z_FLAG;
42 cycles -= is486 ? 9 : 20;
43 return 0;
44 }
46 #define opLAR(name, fetch_ea, is32) \
47 static int opLAR_ ## name(uint32_t fetchdat) \
48 { \
49 int valid; \
50 uint16_t sel, desc; \
51 \
52 NOTRM \
53 fetch_ea(fetchdat); \
54 \
55 sel = geteaw(); if (abrt) return 0; \
56 \
57 flags_rebuild(); \
58 if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/ \
59 valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \
60 if (valid) \
61 { \
62 cpl_override = 1; \
63 desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \
64 cpl_override = 0; if (abrt) return 0; \
65 } \
66 flags &= ~Z_FLAG; \
67 if ((desc & 0x1f00) == 0x000) valid = 0; \
68 if ((desc & 0x1f00) == 0x800) valid = 0; \
69 if ((desc & 0x1f00) == 0xa00) valid = 0; \
70 if ((desc & 0x1f00) == 0xd00) valid = 0; \
71 if ((desc & 0x1c00) < 0x1c00) /*Exclude conforming code segments*/ \
72 { \
73 int dpl = (desc >> 13) & 3; \
74 if (dpl < CPL || dpl < (sel & 3)) valid = 0; \
75 } \
76 if (valid) \
77 { \
78 flags |= Z_FLAG; \
79 cpl_override = 1; \
80 if (is32) \
81 regs[reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \
82 else \
83 regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xff00; \
84 cpl_override = 0; \
85 } \
86 cycles -= 11; \
87 return 0; \
88 }
90 opLAR(w_a16, fetch_ea_16, 0)
91 opLAR(w_a32, fetch_ea_32, 0)
92 opLAR(l_a16, fetch_ea_16, 1)
93 opLAR(l_a32, fetch_ea_32, 1)
95 #define opLSL(name, fetch_ea, is32) \
96 static int opLSL_ ## name(uint32_t fetchdat) \
97 { \
98 int valid; \
99 uint16_t sel, desc; \
100 \
101 NOTRM \
102 fetch_ea(fetchdat); \
103 \
104 sel = geteaw(); if (abrt) return 0; \
105 flags_rebuild(); \
106 flags &= ~Z_FLAG; \
107 if (!(sel & 0xfffc)) return 0; /*Null selector*/ \
108 valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \
109 if (valid) \
110 { \
111 cpl_override = 1; \
112 desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \
113 cpl_override = 0; if (abrt) return 0; \
114 } \
115 if ((desc & 0x1400) == 0x400) valid = 0; /*Interrupt or trap or call gate*/ \
116 if ((desc & 0x1f00) == 0x000) valid = 0; /*Invalid*/ \
117 if ((desc & 0x1f00) == 0xa00) valid = 0; /*Invalid*/ \
118 if ((desc & 0x1c00) != 0x1c00) /*Exclude conforming code segments*/ \
119 { \
120 int rpl = (desc >> 13) & 3; \
121 if (rpl < CPL || rpl < (sel & 3)) valid = 0; \
122 } \
123 if (valid) \
124 { \
125 flags |= Z_FLAG; \
126 cpl_override = 1; \
127 if (is32) \
128 { \
129 regs[reg].l = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \
130 regs[reg].l |= (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0xF) << 16; \
131 if (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0x80) \
132 { \
133 regs[reg].l <<= 12; \
134 regs[reg].l |= 0xFFF; \
135 } \
136 } \
137 else \
138 regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \
139 cpl_override = 0; \
140 } \
141 cycles -= 10; \
142 return 0; \
143 }
145 opLSL(w_a16, fetch_ea_16, 0)
146 opLSL(w_a32, fetch_ea_32, 0)
147 opLSL(l_a16, fetch_ea_16, 1)
148 opLSL(l_a32, fetch_ea_32, 1)
151 static inline int op0F00_common(uint32_t fetchdat)
152 {
153 int dpl, valid, granularity;
154 uint32_t addr, base, limit;
155 uint16_t desc, sel;
156 uint8_t access;
158 // pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc);
159 switch (rmdat & 0x38)
160 {
161 case 0x00: /*SLDT*/
162 seteaw(ldt.seg);
163 cycles -= 4;
164 break;
165 case 0x08: /*STR*/
166 seteaw(tr.seg);
167 cycles -= 4;
168 break;
169 case 0x10: /*LLDT*/
170 if ((CPL || eflags&VM_FLAG) && (cr0&1))
171 {
172 pclog("Invalid LLDT!\n");
173 x86gpf(NULL,0);
174 return 0;
175 }
176 sel = geteaw(); if (abrt) return 0;
177 addr = (sel & ~7) + gdt.base;
178 limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16);
179 base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24);
180 access = readmemb(0, addr + 5);
181 granularity = readmemb(0, addr + 6) & 0x80;
182 if (abrt) return 0;
183 ldt.limit = limit;
184 ldt.access = access;
185 if (granularity)
186 {
187 ldt.limit <<= 12;
188 ldt.limit |= 0xfff;
189 }
190 ldt.base = base;
191 ldt.seg = sel;
192 cycles -= 20;
193 break;
194 case 0x18: /*LTR*/
195 if ((CPL || eflags&VM_FLAG) && (cr0&1))
196 {
197 pclog("Invalid LTR!\n");
198 x86gpf(NULL,0);
199 break;
200 }
201 sel = geteaw(); if (abrt) return 0;
202 addr = (sel & ~7) + gdt.base;
203 limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16);
204 base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24);
205 access = readmemb(0, addr + 5);
206 granularity = readmemb(0, addr + 6) & 0x80;
207 if (abrt) return 0;
208 tr.seg = sel;
209 tr.limit = limit;
210 tr.access = access;
211 if (granularity)
212 {
213 tr.limit <<= 12;
214 tr.limit |= 0xFFF;
215 }
216 tr.base = base;
217 cycles -= 20;
218 break;
219 case 0x20: /*VERR*/
220 sel = geteaw(); if (abrt) return 0;
221 flags_rebuild();
222 flags &= ~Z_FLAG;
223 if (!(sel & 0xfffc)) return 0; /*Null selector*/
224 cpl_override = 1;
225 valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit);
226 desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4);
227 cpl_override = 0; if (abrt) return 0;
228 if (!(desc & 0x1000)) valid = 0;
229 if ((desc & 0xC00) != 0xC00) /*Exclude conforming code segments*/
230 {
231 dpl = (desc >> 13) & 3; /*Check permissions*/
232 if (dpl < CPL || dpl < (sel & 3)) valid = 0;
233 }
234 if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/
235 if (valid) flags |= Z_FLAG;
236 cycles -= 20;
237 break;
238 case 0x28: /*VERW*/
239 sel = geteaw(); if (abrt) return 0;
240 flags_rebuild();
241 flags &= ~Z_FLAG;
242 if (!(sel & 0xfffc)) return 0; /*Null selector*/
243 cpl_override = 1;
244 valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit);
245 desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4);
246 cpl_override = 0; if (abrt) return 0;
247 if (!(desc & 0x1000)) valid = 0;
248 dpl = (desc >> 13) & 3; /*Check permissions*/
249 if (dpl < CPL || dpl < (sel & 3)) valid = 0;
250 if (desc & 0x0800) valid = 0; /*Code*/
251 if (!(desc & 0x0200)) valid = 0; /*Read-only data*/
252 if (valid) flags |= Z_FLAG;
253 cycles -= 20;
254 break;
256 default:
257 pclog("Bad 0F 00 opcode %02X\n", rmdat & 0x38);
258 pc -= 3;
259 x86illegal();
260 break;
261 }
262 return 0;
263 }
265 static inline op0F00_a16(uint32_t fetchdat)
266 {
267 NOTRM
269 fetch_ea_16(fetchdat);
271 op0F00_common(fetchdat);
272 return 0;
273 }
274 static inline op0F00_a32(uint32_t fetchdat)
275 {
276 NOTRM
278 fetch_ea_32(fetchdat);
280 op0F00_common(fetchdat);
281 return 0;
282 }
284 static inline op0F01_common(uint32_t fetchdat, int is32, int is286)
285 {
286 uint32_t base;
287 uint16_t limit, tempw;
288 // pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc);
289 switch (rmdat & 0x38)
290 {
291 case 0x00: /*SGDT*/
292 seteaw(gdt.limit);
293 base = is32 ? gdt.base : (gdt.base & 0xffffff);
294 if (is286)
295 base |= 0xff000000;
296 writememl(easeg, eaaddr + 2, base);
297 cycles -= 7;
298 break;
299 case 0x08: /*SIDT*/
300 seteaw(idt.limit);
301 base = is32 ? idt.base : (idt.base & 0xffffff);
302 if (is286)
303 base |= 0xff000000;
304 writememl(easeg, eaaddr + 2, base);
305 cycles -= 7;
306 break;
307 case 0x10: /*LGDT*/
308 if ((CPL || eflags&VM_FLAG) && (cr0&1))
309 {
310 pclog("Invalid LGDT!\n");
311 x86gpf(NULL,0);
312 break;
313 }
314 // pclog("LGDT %08X:%08X\n", easeg, eaaddr);
315 limit = geteaw();
316 base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 0;
317 // pclog(" %08X %04X\n", base, limit);
318 gdt.limit = limit;
319 gdt.base = base;
320 if (!is32) gdt.base &= 0xffffff;
321 cycles -= 11;
322 break;
323 case 0x18: /*LIDT*/
324 if ((CPL || eflags&VM_FLAG) && (cr0&1))
325 {
326 pclog("Invalid LIDT!\n");
327 x86gpf(NULL,0);
328 break;
329 }
330 // pclog("LIDT %08X:%08X\n", easeg, eaaddr);
331 limit = geteaw();
332 base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 0;
333 // pclog(" %08X %04X\n", base, limit);
334 idt.limit = limit;
335 idt.base = base;
336 if (!is32) idt.base &= 0xffffff;
337 cycles -= 11;
338 break;
340 case 0x20: /*SMSW*/
341 if (is486) seteaw(msw);
342 else seteaw(msw | 0xFF00);
343 cycles -= 2;
344 break;
345 case 0x30: /*LMSW*/
346 if ((CPL || eflags&VM_FLAG) && (msw&1))
347 {
348 pclog("LMSW - ring not zero!\n");
349 x86gpf(NULL, 0);
350 break;
351 }
352 tempw = geteaw(); if (abrt) return 0;
353 if (msw & 1) tempw |= 1;
354 msw = tempw;
355 break;
357 case 0x38: /*INVLPG*/
358 if (is486)
359 {
360 if ((CPL || eflags&VM_FLAG) && (cr0&1))
361 {
362 pclog("Invalid INVLPG!\n");
363 x86gpf(NULL, 0);
364 break;
365 }
366 mmu_invalidate(ds + eaaddr);
367 cycles -= 12;
368 break;
369 }
371 default:
372 pclog("Bad 0F 01 opcode %02X\n", rmdat & 0x38);
373 pc -= 3;
374 x86illegal();
375 break;
376 }
377 return 0;
378 }
380 static inline op0F01_w_a16(uint32_t fetchdat)
381 {
382 fetch_ea_16(fetchdat);
384 op0F01_common(fetchdat, 0, 0);
385 return 0;
386 }
387 static inline op0F01_w_a32(uint32_t fetchdat)
388 {
389 fetch_ea_32(fetchdat);
391 op0F01_common(fetchdat, 0, 0);
392 return 0;
393 }
394 static inline op0F01_l_a16(uint32_t fetchdat)
395 {
396 fetch_ea_16(fetchdat);
398 op0F01_common(fetchdat, 1, 0);
399 return 0;
400 }
401 static inline op0F01_l_a32(uint32_t fetchdat)
402 {
403 fetch_ea_32(fetchdat);
405 op0F01_common(fetchdat, 1, 0);
406 return 0;
407 }
409 static inline op0F01_286(uint32_t fetchdat)
410 {
411 fetch_ea_16(fetchdat);
413 op0F01_common(fetchdat, 0, 1);
414 return 0;
415 }
