PCem
view src/x86_ops_call.h @ 142:bd46c39a78e8
Implemented selector limits on some instructions - fixes LBA2.
GPFs in real mode now work.
Selectors correctly zeroed on far return to lower privilege.
| author | TomW |
|---|---|
| date | Wed Aug 13 20:33:56 2014 +0100 |
| parents | b61adb8876e6 |
| children |
line source
1 #define CALL_FAR_w(new_seg, new_pc) \
2 old_cs = CS; \
3 old_pc = pc; \
4 oxpc = pc; \
5 pc = new_pc; \
6 optype = CALL; \
7 cgate16 = cgate32 = 0; \
8 if (msw & 1) loadcscall(new_seg); \
9 else loadcs(new_seg); \
10 optype = 0; \
11 if (abrt) { cgate16 = cgate32 = 0; return 0; } \
12 oldss = ss; \
13 if (cgate32) \
14 { \
15 uint32_t old_esp = ESP; \
16 PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \
17 PUSH_L(old_pc); if (abrt) ESP = old_esp; \
18 } \
19 else \
20 { \
21 uint32_t old_esp = ESP; \
22 PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \
23 PUSH_W(old_pc); if (abrt) ESP = old_esp; \
24 }
26 #define CALL_FAR_l(new_seg, new_pc) \
27 old_cs = CS; \
28 old_pc = pc; \
29 oxpc = pc; \
30 pc = new_pc; \
31 optype = CALL; \
32 cgate16 = cgate32 = 0; \
33 if (msw & 1) loadcscall(new_seg); \
34 else loadcs(new_seg); \
35 optype = 0; \
36 if (abrt) { cgate16 = cgate32 = 0; return 0; } \
37 oldss = ss; \
38 if (cgate16) \
39 { \
40 uint32_t old_esp = ESP; \
41 PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \
42 PUSH_W(old_pc); if (abrt) ESP = old_esp; \
43 } \
44 else \
45 { \
46 uint32_t old_esp = ESP; \
47 PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 0; } \
48 PUSH_L(old_pc); if (abrt) ESP = old_esp; \
49 }
52 #define CALL_FAR_nr(new_seg, new_pc) \
53 old_cs = CS; \
54 old_pc = pc; \
55 oxpc = pc; \
56 pc = new_pc; \
57 optype = CALL; \
58 cgate16 = cgate32 = 0; \
59 if (msw & 1) loadcscall(new_seg); \
60 else loadcs(new_seg); \
61 optype = 0; \
62 if (abrt) { cgate16 = cgate32 = 0; break; } \
63 oldss = ss; \
64 if (cgate32) \
65 { \
66 uint32_t old_esp = ESP; \
67 PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; break; } \
68 PUSH_L(old_pc); if (abrt) ESP = old_esp; \
69 } \
70 else \
71 { \
72 uint32_t old_esp = ESP; \
73 PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; break; } \
74 PUSH_W(old_pc); if (abrt) ESP = old_esp; \
75 } \
77 static int opCALL_far_w(uint32_t fetchdat)
78 {
79 uint32_t old_cs, old_pc;
80 uint16_t new_cs, new_pc;
82 new_pc = getwordf();
83 new_cs = getword(); if (abrt) return 0;
85 CALL_FAR_w(new_cs, new_pc);
87 cycles -= is486 ? 18 : 17;
88 return 0;
89 }
90 static int opCALL_far_l(uint32_t fetchdat)
91 {
92 uint32_t old_cs, old_pc;
93 uint32_t new_cs, new_pc;
95 new_pc = getlong();
96 new_cs = getword(); if (abrt) return 0;
98 CALL_FAR_l(new_cs, new_pc);
100 cycles -= is486 ? 18 : 17;
101 return 0;
102 }
105 static int opFF_w_a16(uint32_t fetchdat)
106 {
107 uint16_t old_cs, new_cs;
108 uint32_t old_pc, new_pc;
110 uint16_t temp;
112 fetch_ea_16(fetchdat);
114 switch (rmdat & 0x38)
115 {
116 case 0x00: /*INC w*/
117 temp = geteaw(); if (abrt) return 0;
118 seteaw(temp + 1); if (abrt) return 0;
119 setadd16nc(temp, 1);
120 cycles -= (mod == 3) ? timing_rr : timing_mm;
121 break;
122 case 0x08: /*DEC w*/
123 temp = geteaw(); if (abrt) return 0;
124 seteaw(temp - 1); if (abrt) return 0;
125 setsub16nc(temp, 1);
126 cycles -= (mod == 3) ? timing_rr : timing_mm;
127 break;
128 case 0x10: /*CALL*/
129 new_pc = geteaw(); if (abrt) return 0;
130 PUSH_W(pc);
131 pc = new_pc;
132 if (is486) cycles -= 5;
133 else cycles -= ((mod == 3) ? 7 : 10);
134 break;
135 case 0x18: /*CALL far*/
136 new_pc = readmemw(easeg, eaaddr);
137 new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 0;
139 CALL_FAR_w(new_cs, new_pc);
141 cycles -= is486 ? 17 : 22;
142 break;
143 case 0x20: /*JMP*/
144 new_pc = geteaw(); if (abrt) return 0;
145 pc = new_pc;
146 if (is486) cycles -= 5;
147 else cycles -= ((mod == 3) ? 7 : 10);
148 break;
149 case 0x28: /*JMP far*/
150 oxpc = pc;
151 new_pc = readmemw(easeg, eaaddr);
152 new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
153 pc = new_pc;
154 loadcsjmp(new_cs, oxpc); if (abrt) return 0;
155 cycles -= is486 ? 13 : 12;
156 break;
157 case 0x30: /*PUSH w*/
158 temp = geteaw(); if (abrt) return 0;
159 PUSH_W(temp);
160 cycles -= ((mod == 3) ? 2 : 5);
161 break;
163 default:
164 // fatal("Bad FF opcode %02X\n",rmdat&0x38);
165 x86illegal();
166 }
167 return 0;
168 }
169 static int opFF_w_a32(uint32_t fetchdat)
170 {
171 uint16_t old_cs, new_cs;
172 uint32_t old_pc, new_pc;
174 uint16_t temp;
176 fetch_ea_32(fetchdat);
178 switch (rmdat & 0x38)
179 {
180 case 0x00: /*INC w*/
181 temp = geteaw(); if (abrt) return 0;
182 seteaw(temp + 1); if (abrt) return 0;
183 setadd16nc(temp, 1);
184 cycles -= (mod == 3) ? timing_rr : timing_mm;
185 break;
186 case 0x08: /*DEC w*/
187 temp = geteaw(); if (abrt) return 0;
188 seteaw(temp - 1); if (abrt) return 0;
189 setsub16nc(temp, 1);
190 cycles -= (mod == 3) ? timing_rr : timing_mm;
191 break;
192 case 0x10: /*CALL*/
193 new_pc = geteaw(); if (abrt) return 0;
194 PUSH_W(pc);
195 pc = new_pc;
196 if (is486) cycles -= 5;
197 else cycles -= ((mod == 3) ? 7 : 10);
198 break;
199 case 0x18: /*CALL far*/
200 new_pc = readmemw(easeg, eaaddr);
201 new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 0;
203 CALL_FAR_w(new_cs, new_pc);
205 cycles -= is486 ? 17 : 22;
206 break;
207 case 0x20: /*JMP*/
208 new_pc = geteaw(); if (abrt) return 0;
209 pc = new_pc;
210 if (is486) cycles -= 5;
211 else cycles -= ((mod == 3) ? 7 : 10);
212 break;
213 case 0x28: /*JMP far*/
214 oxpc = pc;
215 new_pc = readmemw(easeg, eaaddr);
216 new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 0;
217 pc = new_pc;
218 loadcsjmp(new_cs, oxpc); if (abrt) return 0;
219 cycles -= is486 ? 13 : 12;
220 break;
221 case 0x30: /*PUSH w*/
222 temp = geteaw(); if (abrt) return 0;
223 PUSH_W(temp);
224 cycles -= ((mod == 3) ? 2 : 5);
225 break;
227 default:
228 // fatal("Bad FF opcode %02X\n",rmdat&0x38);
229 x86illegal();
230 }
231 return 0;
232 }
234 static int opFF_l_a16(uint32_t fetchdat)
235 {
236 uint16_t old_cs, new_cs;
237 uint32_t old_pc, new_pc;
239 uint32_t temp;
241 fetch_ea_16(fetchdat);
243 switch (rmdat & 0x38)
244 {
245 case 0x00: /*INC l*/
246 temp = geteal(); if (abrt) return 0;
247 seteal(temp + 1); if (abrt) return 0;
248 setadd32nc(temp, 1);
249 cycles -= (mod == 3) ? timing_rr : timing_mm;
250 break;
251 case 0x08: /*DEC l*/
252 temp = geteal(); if (abrt) return 0;
253 seteal(temp - 1); if (abrt) return 0;
254 setsub32nc(temp, 1);
255 cycles -= (mod == 3) ? timing_rr : timing_mm;
256 break;
257 case 0x10: /*CALL*/
258 new_pc = geteal(); if (abrt) return 0;
259 PUSH_L(pc);
260 pc = new_pc;
261 if (is486) cycles -= 5;
262 else cycles -= ((mod == 3) ? 7 : 10);
263 break;
264 case 0x18: /*CALL far*/
265 new_pc = readmeml(easeg, eaaddr);
266 new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 0;
268 CALL_FAR_l(new_cs, new_pc);
270 cycles -= is486 ? 17 : 22;
271 break;
272 case 0x20: /*JMP*/
273 new_pc = geteal(); if (abrt) return 0;
274 pc = new_pc;
275 if (is486) cycles -= 5;
276 else cycles -= ((mod == 3) ? 7 : 10);
277 break;
278 case 0x28: /*JMP far*/
279 oxpc = pc;
280 new_pc = readmeml(easeg, eaaddr);
281 new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 0;
282 pc = new_pc;
283 loadcsjmp(new_cs, oxpc); if (abrt) return 0;
284 cycles -= is486 ? 13 : 12;
285 break;
286 case 0x30: /*PUSH l*/
287 temp = geteal(); if (abrt) return 0;
288 PUSH_L(temp);
289 cycles -= ((mod == 3) ? 2 : 5);
290 break;
292 default:
293 // fatal("Bad FF opcode %02X\n",rmdat&0x38);
294 x86illegal();
295 }
296 return 0;
297 }
298 static int opFF_l_a32(uint32_t fetchdat)
299 {
300 uint16_t old_cs, new_cs;
301 uint32_t old_pc, new_pc;
303 uint32_t temp;
305 fetch_ea_32(fetchdat);
307 switch (rmdat & 0x38)
308 {
309 case 0x00: /*INC l*/
310 temp = geteal(); if (abrt) return 0;
311 seteal(temp + 1); if (abrt) return 0;
312 setadd32nc(temp, 1);
313 cycles -= (mod == 3) ? timing_rr : timing_mm;
314 break;
315 case 0x08: /*DEC l*/
316 temp = geteal(); if (abrt) return 0;
317 seteal(temp - 1); if (abrt) return 0;
318 setsub32nc(temp, 1);
319 cycles -= (mod == 3) ? timing_rr : timing_mm;
320 break;
321 case 0x10: /*CALL*/
322 new_pc = geteal(); if (abrt) return 0;
323 PUSH_L(pc); if (abrt) return 0;
324 pc = new_pc;
325 if (is486) cycles -= 5;
326 else cycles -= ((mod == 3) ? 7 : 10);
327 break;
328 case 0x18: /*CALL far*/
329 new_pc = readmeml(easeg, eaaddr);
330 new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 0;
332 CALL_FAR_l(new_cs, new_pc);
334 cycles -= is486 ? 17 : 22;
335 break;
336 case 0x20: /*JMP*/
337 new_pc = geteal(); if (abrt) return 0;
338 pc = new_pc;
339 if (is486) cycles -= 5;
340 else cycles -= ((mod == 3) ? 7 : 10);
341 break;
342 case 0x28: /*JMP far*/
343 oxpc = pc;
344 new_pc = readmeml(easeg, eaaddr);
345 new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 0;
346 pc = new_pc;
347 loadcsjmp(new_cs, oxpc); if (abrt) return 0;
348 cycles -= is486 ? 13 : 12;
349 break;
350 case 0x30: /*PUSH l*/
351 temp = geteal(); if (abrt) return 0;
352 PUSH_L(temp);
353 cycles -= ((mod == 3) ? 2 : 5);
354 break;
356 default:
357 // fatal("Bad FF opcode %02X\n",rmdat&0x38);
358 x86illegal();
359 }
360 return 0;
361 }
