126 |
longjmp(env->jmp_env, 1); |
longjmp(env->jmp_env, 1); |
127 |
} |
} |
128 |
|
|
129 |
|
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, |
130 |
|
uint32_t *esp_ptr, int dpl) |
131 |
|
{ |
132 |
|
int type, index, shift; |
133 |
|
|
134 |
#if 0 |
#if 0 |
135 |
/* full interrupt support (only useful for real CPU emulation, not |
{ |
136 |
finished) - I won't do it any time soon, finish it if you want ! */ |
int i; |
137 |
void raise_interrupt(int intno, int is_int, int error_code, |
printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); |
138 |
unsigned int next_eip) |
for(i=0;i<env->tr.limit;i++) { |
139 |
|
printf("%02x ", env->tr.base[i]); |
140 |
|
if ((i & 7) == 7) printf("\n"); |
141 |
|
} |
142 |
|
printf("\n"); |
143 |
|
} |
144 |
|
#endif |
145 |
|
|
146 |
|
if (!(env->tr.flags & DESC_P_MASK)) |
147 |
|
cpu_abort(env, "invalid tss"); |
148 |
|
type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; |
149 |
|
if ((type & 7) != 1) |
150 |
|
cpu_abort(env, "invalid tss type"); |
151 |
|
shift = type >> 3; |
152 |
|
index = (dpl * 4 + 2) << shift; |
153 |
|
if (index + (4 << shift) - 1 > env->tr.limit) |
154 |
|
raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); |
155 |
|
if (shift == 0) { |
156 |
|
*esp_ptr = lduw(env->tr.base + index); |
157 |
|
*ss_ptr = lduw(env->tr.base + index + 2); |
158 |
|
} else { |
159 |
|
*esp_ptr = ldl(env->tr.base + index); |
160 |
|
*ss_ptr = lduw(env->tr.base + index + 4); |
161 |
|
} |
162 |
|
} |
163 |
|
|
164 |
|
/* return non zero if error */ |
165 |
|
static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, |
166 |
|
int selector) |
167 |
{ |
{ |
168 |
SegmentDescriptorTable *dt; |
SegmentCache *dt; |
169 |
|
int index; |
170 |
uint8_t *ptr; |
uint8_t *ptr; |
171 |
int type, dpl, cpl; |
|
172 |
uint32_t e1, e2; |
if (selector & 0x4) |
173 |
|
dt = &env->ldt; |
174 |
|
else |
175 |
|
dt = &env->gdt; |
176 |
|
index = selector & ~7; |
177 |
|
if ((index + 7) > dt->limit) |
178 |
|
return -1; |
179 |
|
ptr = dt->base + index; |
180 |
|
*e1_ptr = ldl(ptr); |
181 |
|
*e2_ptr = ldl(ptr + 4); |
182 |
|
return 0; |
183 |
|
} |
184 |
|
|
185 |
|
|
186 |
|
/* protected mode interrupt */ |
187 |
|
static void do_interrupt_protected(int intno, int is_int, int error_code, |
188 |
|
unsigned int next_eip) |
189 |
|
{ |
190 |
|
SegmentCache *dt; |
191 |
|
uint8_t *ptr, *ssp; |
192 |
|
int type, dpl, cpl, selector, ss_dpl; |
193 |
|
int has_error_code, new_stack, shift; |
194 |
|
uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; |
195 |
|
uint32_t old_cs, old_ss, old_esp, old_eip; |
196 |
|
|
197 |
dt = &env->idt; |
dt = &env->idt; |
198 |
if (intno * 8 + 7 > dt->limit) |
if (intno * 8 + 7 > dt->limit) |
199 |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
204 |
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
205 |
switch(type) { |
switch(type) { |
206 |
case 5: /* task gate */ |
case 5: /* task gate */ |
207 |
|
cpu_abort(env, "task gate not supported"); |
208 |
|
break; |
209 |
case 6: /* 286 interrupt gate */ |
case 6: /* 286 interrupt gate */ |
210 |
case 7: /* 286 trap gate */ |
case 7: /* 286 trap gate */ |
211 |
case 14: /* 386 interrupt gate */ |
case 14: /* 386 interrupt gate */ |
223 |
/* check valid bit */ |
/* check valid bit */ |
224 |
if (!(e2 & DESC_P_MASK)) |
if (!(e2 & DESC_P_MASK)) |
225 |
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); |
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); |
226 |
|
selector = e1 >> 16; |
227 |
|
offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); |
228 |
|
if ((selector & 0xfffc) == 0) |
229 |
|
raise_exception_err(EXCP0D_GPF, 0); |
230 |
|
|
231 |
|
if (load_segment(&e1, &e2, selector) != 0) |
232 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
233 |
|
if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) |
234 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
235 |
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
236 |
|
if (dpl > cpl) |
237 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
238 |
|
if (!(e2 & DESC_P_MASK)) |
239 |
|
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
240 |
|
if (!(e2 & DESC_C_MASK) && dpl < cpl) { |
241 |
|
/* to inner priviledge */ |
242 |
|
get_ss_esp_from_tss(&ss, &esp, dpl); |
243 |
|
if ((ss & 0xfffc) == 0) |
244 |
|
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
245 |
|
if ((ss & 3) != dpl) |
246 |
|
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
247 |
|
if (load_segment(&ss_e1, &ss_e2, ss) != 0) |
248 |
|
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
249 |
|
ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; |
250 |
|
if (ss_dpl != dpl) |
251 |
|
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
252 |
|
if (!(ss_e2 & DESC_S_MASK) || |
253 |
|
(ss_e2 & DESC_CS_MASK) || |
254 |
|
!(ss_e2 & DESC_W_MASK)) |
255 |
|
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
256 |
|
if (!(ss_e2 & DESC_P_MASK)) |
257 |
|
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
258 |
|
new_stack = 1; |
259 |
|
} else if ((e2 & DESC_C_MASK) || dpl == cpl) { |
260 |
|
/* to same priviledge */ |
261 |
|
new_stack = 0; |
262 |
|
} else { |
263 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
264 |
|
new_stack = 0; /* avoid warning */ |
265 |
|
} |
266 |
|
|
267 |
|
shift = type >> 3; |
268 |
|
has_error_code = 0; |
269 |
|
if (!is_int) { |
270 |
|
switch(intno) { |
271 |
|
case 8: |
272 |
|
case 10: |
273 |
|
case 11: |
274 |
|
case 12: |
275 |
|
case 13: |
276 |
|
case 14: |
277 |
|
case 17: |
278 |
|
has_error_code = 1; |
279 |
|
break; |
280 |
|
} |
281 |
|
} |
282 |
|
push_size = 6 + (new_stack << 2) + (has_error_code << 1); |
283 |
|
if (env->eflags & VM_MASK) |
284 |
|
push_size += 8; |
285 |
|
push_size <<= shift; |
286 |
|
|
287 |
|
/* XXX: check that enough room is available */ |
288 |
|
if (new_stack) { |
289 |
|
old_esp = env->regs[R_ESP]; |
290 |
|
old_ss = env->segs[R_SS].selector; |
291 |
|
load_seg(R_SS, ss, env->eip); |
292 |
|
} else { |
293 |
|
old_esp = 0; |
294 |
|
old_ss = 0; |
295 |
|
esp = env->regs[R_ESP]; |
296 |
|
} |
297 |
|
if (is_int) |
298 |
|
old_eip = next_eip; |
299 |
|
else |
300 |
|
old_eip = env->eip; |
301 |
|
old_cs = env->segs[R_CS].selector; |
302 |
|
load_seg(R_CS, selector, env->eip); |
303 |
|
env->eip = offset; |
304 |
|
env->regs[R_ESP] = esp - push_size; |
305 |
|
ssp = env->segs[R_SS].base + esp; |
306 |
|
if (shift == 1) { |
307 |
|
int old_eflags; |
308 |
|
if (env->eflags & VM_MASK) { |
309 |
|
ssp -= 4; |
310 |
|
stl(ssp, env->segs[R_GS].selector); |
311 |
|
ssp -= 4; |
312 |
|
stl(ssp, env->segs[R_FS].selector); |
313 |
|
ssp -= 4; |
314 |
|
stl(ssp, env->segs[R_DS].selector); |
315 |
|
ssp -= 4; |
316 |
|
stl(ssp, env->segs[R_ES].selector); |
317 |
|
} |
318 |
|
if (new_stack) { |
319 |
|
ssp -= 4; |
320 |
|
stl(ssp, old_ss); |
321 |
|
ssp -= 4; |
322 |
|
stl(ssp, old_esp); |
323 |
|
} |
324 |
|
ssp -= 4; |
325 |
|
old_eflags = compute_eflags(); |
326 |
|
stl(ssp, old_eflags); |
327 |
|
ssp -= 4; |
328 |
|
stl(ssp, old_cs); |
329 |
|
ssp -= 4; |
330 |
|
stl(ssp, old_eip); |
331 |
|
if (has_error_code) { |
332 |
|
ssp -= 4; |
333 |
|
stl(ssp, error_code); |
334 |
|
} |
335 |
|
} else { |
336 |
|
if (new_stack) { |
337 |
|
ssp -= 2; |
338 |
|
stw(ssp, old_ss); |
339 |
|
ssp -= 2; |
340 |
|
stw(ssp, old_esp); |
341 |
|
} |
342 |
|
ssp -= 2; |
343 |
|
stw(ssp, compute_eflags()); |
344 |
|
ssp -= 2; |
345 |
|
stw(ssp, old_cs); |
346 |
|
ssp -= 2; |
347 |
|
stw(ssp, old_eip); |
348 |
|
if (has_error_code) { |
349 |
|
ssp -= 2; |
350 |
|
stw(ssp, error_code); |
351 |
|
} |
352 |
|
} |
353 |
|
|
354 |
|
/* interrupt gate clear IF mask */ |
355 |
|
if ((type & 1) == 0) { |
356 |
|
env->eflags &= ~IF_MASK; |
357 |
|
} |
358 |
|
env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); |
359 |
} |
} |
360 |
|
|
361 |
#else |
/* real mode interrupt */ |
362 |
|
static void do_interrupt_real(int intno, int is_int, int error_code, |
363 |
|
unsigned int next_eip) |
364 |
|
{ |
365 |
|
SegmentCache *dt; |
366 |
|
uint8_t *ptr, *ssp; |
367 |
|
int selector; |
368 |
|
uint32_t offset, esp; |
369 |
|
uint32_t old_cs, old_eip; |
370 |
|
|
371 |
/* |
/* real mode (simpler !) */ |
372 |
* is_int is TRUE if coming from the int instruction. next_eip is the |
dt = &env->idt; |
373 |
* EIP value AFTER the interrupt instruction. It is only relevant if |
if (intno * 4 + 3 > dt->limit) |
374 |
* is_int is TRUE. |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
375 |
*/ |
ptr = dt->base + intno * 4; |
376 |
void raise_interrupt(int intno, int is_int, int error_code, |
offset = lduw(ptr); |
377 |
unsigned int next_eip) |
selector = lduw(ptr + 2); |
378 |
|
esp = env->regs[R_ESP] & 0xffff; |
379 |
|
ssp = env->segs[R_SS].base + esp; |
380 |
|
if (is_int) |
381 |
|
old_eip = next_eip; |
382 |
|
else |
383 |
|
old_eip = env->eip; |
384 |
|
old_cs = env->segs[R_CS].selector; |
385 |
|
ssp -= 2; |
386 |
|
stw(ssp, compute_eflags()); |
387 |
|
ssp -= 2; |
388 |
|
stw(ssp, old_cs); |
389 |
|
ssp -= 2; |
390 |
|
stw(ssp, old_eip); |
391 |
|
esp -= 6; |
392 |
|
|
393 |
|
/* update processor state */ |
394 |
|
env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff); |
395 |
|
env->eip = offset; |
396 |
|
env->segs[R_CS].selector = selector; |
397 |
|
env->segs[R_CS].base = (uint8_t *)(selector << 4); |
398 |
|
env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); |
399 |
|
} |
400 |
|
|
401 |
|
/* fake user mode interrupt */ |
402 |
|
void do_interrupt_user(int intno, int is_int, int error_code, |
403 |
|
unsigned int next_eip) |
404 |
{ |
{ |
405 |
SegmentCache *dt; |
SegmentCache *dt; |
406 |
uint8_t *ptr; |
uint8_t *ptr; |
422 |
code */ |
code */ |
423 |
if (is_int) |
if (is_int) |
424 |
EIP = next_eip; |
EIP = next_eip; |
425 |
|
} |
426 |
|
|
427 |
|
/* |
428 |
|
* Begin excution of an interruption. is_int is TRUE if coming from |
429 |
|
* the int instruction. next_eip is the EIP value AFTER the interrupt |
430 |
|
* instruction. It is only relevant if is_int is TRUE. |
431 |
|
*/ |
432 |
|
void do_interrupt(int intno, int is_int, int error_code, |
433 |
|
unsigned int next_eip) |
434 |
|
{ |
435 |
|
if (env->cr[0] & CR0_PE_MASK) { |
436 |
|
do_interrupt_protected(intno, is_int, error_code, next_eip); |
437 |
|
} else { |
438 |
|
do_interrupt_real(intno, is_int, error_code, next_eip); |
439 |
|
} |
440 |
|
} |
441 |
|
|
442 |
|
/* |
443 |
|
* Signal an interruption. It is executed in the main CPU loop. |
444 |
|
* is_int is TRUE if coming from the int instruction. next_eip is the |
445 |
|
* EIP value AFTER the interrupt instruction. It is only relevant if |
446 |
|
* is_int is TRUE. |
447 |
|
*/ |
448 |
|
void raise_interrupt(int intno, int is_int, int error_code, |
449 |
|
unsigned int next_eip) |
450 |
|
{ |
451 |
env->exception_index = intno; |
env->exception_index = intno; |
452 |
env->error_code = error_code; |
env->error_code = error_code; |
453 |
|
env->exception_is_int = is_int; |
454 |
|
env->exception_next_eip = next_eip; |
455 |
cpu_loop_exit(); |
cpu_loop_exit(); |
456 |
} |
} |
457 |
|
|
|
#endif |
|
|
|
|
458 |
/* shortcuts to generate exceptions */ |
/* shortcuts to generate exceptions */ |
459 |
void raise_exception_err(int exception_index, int error_code) |
void raise_exception_err(int exception_index, int error_code) |
460 |
{ |
{ |
586 |
{ |
{ |
587 |
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
588 |
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
589 |
if (e2 & (1 << 23)) |
if (e2 & DESC_G_MASK) |
590 |
sc->limit = (sc->limit << 12) | 0xfff; |
sc->limit = (sc->limit << 12) | 0xfff; |
591 |
sc->seg_32bit = (e2 >> 22) & 1; |
sc->flags = e2; |
592 |
} |
} |
593 |
|
|
594 |
void helper_lldt_T0(void) |
void helper_lldt_T0(void) |
633 |
|
|
634 |
selector = T0 & 0xffff; |
selector = T0 & 0xffff; |
635 |
if ((selector & 0xfffc) == 0) { |
if ((selector & 0xfffc) == 0) { |
636 |
/* XXX: NULL selector case: invalid LDT */ |
/* NULL selector case: invalid LDT */ |
637 |
env->tr.base = NULL; |
env->tr.base = NULL; |
638 |
env->tr.limit = 0; |
env->tr.limit = 0; |
639 |
|
env->tr.flags = 0; |
640 |
} else { |
} else { |
641 |
if (selector & 0x4) |
if (selector & 0x4) |
642 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
664 |
void load_seg(int seg_reg, int selector, unsigned int cur_eip) |
void load_seg(int seg_reg, int selector, unsigned int cur_eip) |
665 |
{ |
{ |
666 |
SegmentCache *sc; |
SegmentCache *sc; |
|
SegmentCache *dt; |
|
|
int index; |
|
667 |
uint32_t e1, e2; |
uint32_t e1, e2; |
|
uint8_t *ptr; |
|
668 |
|
|
669 |
sc = &env->segs[seg_reg]; |
sc = &env->segs[seg_reg]; |
670 |
if ((selector & 0xfffc) == 0) { |
if ((selector & 0xfffc) == 0) { |
676 |
/* XXX: each access should trigger an exception */ |
/* XXX: each access should trigger an exception */ |
677 |
sc->base = NULL; |
sc->base = NULL; |
678 |
sc->limit = 0; |
sc->limit = 0; |
679 |
sc->seg_32bit = 1; |
sc->flags = 0; |
680 |
} |
} |
681 |
} else { |
} else { |
682 |
if (selector & 0x4) |
if (load_segment(&e1, &e2, selector) != 0) { |
|
dt = &env->ldt; |
|
|
else |
|
|
dt = &env->gdt; |
|
|
index = selector & ~7; |
|
|
if ((index + 7) > dt->limit) { |
|
683 |
EIP = cur_eip; |
EIP = cur_eip; |
684 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
685 |
} |
} |
|
ptr = dt->base + index; |
|
|
e1 = ldl(ptr); |
|
|
e2 = ldl(ptr + 4); |
|
686 |
if (!(e2 & DESC_S_MASK) || |
if (!(e2 & DESC_S_MASK) || |
687 |
(e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { |
(e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { |
688 |
EIP = cur_eip; |
EIP = cur_eip; |
710 |
} |
} |
711 |
load_seg_cache(sc, e1, e2); |
load_seg_cache(sc, e1, e2); |
712 |
#if 0 |
#if 0 |
713 |
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", |
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", |
714 |
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); |
selector, (unsigned long)sc->base, sc->limit, sc->flags); |
715 |
#endif |
#endif |
716 |
} |
} |
717 |
sc->selector = selector; |
sc->selector = selector; |
721 |
void jmp_seg(int selector, unsigned int new_eip) |
void jmp_seg(int selector, unsigned int new_eip) |
722 |
{ |
{ |
723 |
SegmentCache sc1; |
SegmentCache sc1; |
|
SegmentCache *dt; |
|
|
int index; |
|
724 |
uint32_t e1, e2, cpl, dpl, rpl; |
uint32_t e1, e2, cpl, dpl, rpl; |
|
uint8_t *ptr; |
|
725 |
|
|
726 |
if ((selector & 0xfffc) == 0) { |
if ((selector & 0xfffc) == 0) { |
727 |
raise_exception_err(EXCP0D_GPF, 0); |
raise_exception_err(EXCP0D_GPF, 0); |
728 |
} |
} |
729 |
|
|
730 |
if (selector & 0x4) |
if (load_segment(&e1, &e2, selector) != 0) |
|
dt = &env->ldt; |
|
|
else |
|
|
dt = &env->gdt; |
|
|
index = selector & ~7; |
|
|
if ((index + 7) > dt->limit) |
|
731 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
|
ptr = dt->base + index; |
|
|
e1 = ldl(ptr); |
|
|
e2 = ldl(ptr + 4); |
|
732 |
cpl = env->segs[R_CS].selector & 3; |
cpl = env->segs[R_CS].selector & 3; |
733 |
if (e2 & DESC_S_MASK) { |
if (e2 & DESC_S_MASK) { |
734 |
if (!(e2 & DESC_CS_MASK)) |
if (!(e2 & DESC_CS_MASK)) |
760 |
} |
} |
761 |
} |
} |
762 |
|
|
763 |
/* XXX: do more */ |
/* init the segment cache in vm86 mode */ |
764 |
|
static inline void load_seg_vm(int seg, int selector) |
765 |
|
{ |
766 |
|
SegmentCache *sc = &env->segs[seg]; |
767 |
|
selector &= 0xffff; |
768 |
|
sc->base = (uint8_t *)(selector << 4); |
769 |
|
sc->selector = selector; |
770 |
|
sc->flags = 0; |
771 |
|
sc->limit = 0xffff; |
772 |
|
} |
773 |
|
|
774 |
|
/* protected mode iret */ |
775 |
|
void helper_iret_protected(int shift) |
776 |
|
{ |
777 |
|
uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; |
778 |
|
uint32_t new_es, new_ds, new_fs, new_gs; |
779 |
|
uint32_t e1, e2; |
780 |
|
int cpl, dpl, rpl, eflags_mask; |
781 |
|
uint8_t *ssp; |
782 |
|
|
783 |
|
sp = env->regs[R_ESP]; |
784 |
|
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
785 |
|
sp &= 0xffff; |
786 |
|
ssp = env->segs[R_SS].base + sp; |
787 |
|
if (shift == 1) { |
788 |
|
/* 32 bits */ |
789 |
|
new_eflags = ldl(ssp + 8); |
790 |
|
new_cs = ldl(ssp + 4) & 0xffff; |
791 |
|
new_eip = ldl(ssp); |
792 |
|
if (new_eflags & VM_MASK) |
793 |
|
goto return_to_vm86; |
794 |
|
} else { |
795 |
|
/* 16 bits */ |
796 |
|
new_eflags = lduw(ssp + 4); |
797 |
|
new_cs = lduw(ssp + 2); |
798 |
|
new_eip = lduw(ssp); |
799 |
|
} |
800 |
|
if ((new_cs & 0xfffc) == 0) |
801 |
|
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
802 |
|
if (load_segment(&e1, &e2, new_cs) != 0) |
803 |
|
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
804 |
|
if (!(e2 & DESC_S_MASK) || |
805 |
|
!(e2 & DESC_CS_MASK)) |
806 |
|
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
807 |
|
cpl = env->segs[R_CS].selector & 3; |
808 |
|
rpl = new_cs & 3; |
809 |
|
if (rpl < cpl) |
810 |
|
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
811 |
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
812 |
|
if (e2 & DESC_CS_MASK) { |
813 |
|
if (dpl > rpl) |
814 |
|
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
815 |
|
} else { |
816 |
|
if (dpl != rpl) |
817 |
|
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
818 |
|
} |
819 |
|
if (!(e2 & DESC_P_MASK)) |
820 |
|
raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); |
821 |
|
|
822 |
|
if (rpl == cpl) { |
823 |
|
/* return to same priledge level */ |
824 |
|
load_seg(R_CS, new_cs, env->eip); |
825 |
|
new_esp = sp + (6 << shift); |
826 |
|
} else { |
827 |
|
/* return to differentr priviledge level */ |
828 |
|
if (shift == 1) { |
829 |
|
/* 32 bits */ |
830 |
|
new_esp = ldl(ssp + 12); |
831 |
|
new_ss = ldl(ssp + 16) & 0xffff; |
832 |
|
} else { |
833 |
|
/* 16 bits */ |
834 |
|
new_esp = lduw(ssp + 6); |
835 |
|
new_ss = lduw(ssp + 8); |
836 |
|
} |
837 |
|
|
838 |
|
if ((new_ss & 3) != rpl) |
839 |
|
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
840 |
|
if (load_segment(&e1, &e2, new_ss) != 0) |
841 |
|
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
842 |
|
if (!(e2 & DESC_S_MASK) || |
843 |
|
(e2 & DESC_CS_MASK) || |
844 |
|
!(e2 & DESC_W_MASK)) |
845 |
|
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
846 |
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
847 |
|
if (dpl != rpl) |
848 |
|
raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |
849 |
|
if (!(e2 & DESC_P_MASK)) |
850 |
|
raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); |
851 |
|
|
852 |
|
load_seg(R_CS, new_cs, env->eip); |
853 |
|
load_seg(R_SS, new_ss, env->eip); |
854 |
|
} |
855 |
|
if (env->segs[R_SS].flags & DESC_B_MASK) |
856 |
|
env->regs[R_ESP] = new_esp; |
857 |
|
else |
858 |
|
env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | |
859 |
|
(new_esp & 0xffff); |
860 |
|
env->eip = new_eip; |
861 |
|
if (cpl == 0) |
862 |
|
eflags_mask = FL_UPDATE_CPL0_MASK; |
863 |
|
else |
864 |
|
eflags_mask = FL_UPDATE_MASK32; |
865 |
|
if (shift == 0) |
866 |
|
eflags_mask &= 0xffff; |
867 |
|
load_eflags(new_eflags, eflags_mask); |
868 |
|
return; |
869 |
|
|
870 |
|
return_to_vm86: |
871 |
|
new_esp = ldl(ssp + 12); |
872 |
|
new_ss = ldl(ssp + 16); |
873 |
|
new_es = ldl(ssp + 20); |
874 |
|
new_ds = ldl(ssp + 24); |
875 |
|
new_fs = ldl(ssp + 28); |
876 |
|
new_gs = ldl(ssp + 32); |
877 |
|
|
878 |
|
/* modify processor state */ |
879 |
|
load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); |
880 |
|
load_seg_vm(R_CS, new_cs); |
881 |
|
load_seg_vm(R_SS, new_ss); |
882 |
|
load_seg_vm(R_ES, new_es); |
883 |
|
load_seg_vm(R_DS, new_ds); |
884 |
|
load_seg_vm(R_FS, new_fs); |
885 |
|
load_seg_vm(R_GS, new_gs); |
886 |
|
|
887 |
|
env->eip = new_eip; |
888 |
|
env->regs[R_ESP] = new_esp; |
889 |
|
} |
890 |
|
|
891 |
void helper_movl_crN_T0(int reg) |
void helper_movl_crN_T0(int reg) |
892 |
{ |
{ |
893 |
|
env->cr[reg] = T0; |
894 |
switch(reg) { |
switch(reg) { |
895 |
case 0: |
case 0: |
896 |
default: |
cpu_x86_update_cr0(env); |
|
env->cr[0] = reg; |
|
|
break; |
|
|
case 2: |
|
|
env->cr[2] = reg; |
|
897 |
break; |
break; |
898 |
case 3: |
case 3: |
899 |
env->cr[3] = reg; |
cpu_x86_update_cr3(env); |
|
break; |
|
|
case 4: |
|
|
env->cr[4] = reg; |
|
900 |
break; |
break; |
901 |
} |
} |
902 |
} |
} |
907 |
env->dr[reg] = T0; |
env->dr[reg] = T0; |
908 |
} |
} |
909 |
|
|
910 |
|
void helper_invlpg(unsigned int addr) |
911 |
|
{ |
912 |
|
cpu_x86_flush_tlb(env, addr); |
913 |
|
} |
914 |
|
|
915 |
/* rdtsc */ |
/* rdtsc */ |
916 |
#ifndef __i386__ |
#ifndef __i386__ |
917 |
uint64_t emu_time; |
uint64_t emu_time; |
933 |
void helper_lsl(void) |
void helper_lsl(void) |
934 |
{ |
{ |
935 |
unsigned int selector, limit; |
unsigned int selector, limit; |
|
SegmentCache *dt; |
|
|
int index; |
|
936 |
uint32_t e1, e2; |
uint32_t e1, e2; |
|
uint8_t *ptr; |
|
937 |
|
|
938 |
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
939 |
selector = T0 & 0xffff; |
selector = T0 & 0xffff; |
940 |
if (selector & 0x4) |
if (load_segment(&e1, &e2, selector) != 0) |
|
dt = &env->ldt; |
|
|
else |
|
|
dt = &env->gdt; |
|
|
index = selector & ~7; |
|
|
if ((index + 7) > dt->limit) |
|
941 |
return; |
return; |
|
ptr = dt->base + index; |
|
|
e1 = ldl(ptr); |
|
|
e2 = ldl(ptr + 4); |
|
942 |
limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
943 |
if (e2 & (1 << 23)) |
if (e2 & (1 << 23)) |
944 |
limit = (limit << 12) | 0xfff; |
limit = (limit << 12) | 0xfff; |
949 |
void helper_lar(void) |
void helper_lar(void) |
950 |
{ |
{ |
951 |
unsigned int selector; |
unsigned int selector; |
952 |
SegmentCache *dt; |
uint32_t e1, e2; |
|
int index; |
|
|
uint32_t e2; |
|
|
uint8_t *ptr; |
|
953 |
|
|
954 |
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; |
955 |
selector = T0 & 0xffff; |
selector = T0 & 0xffff; |
956 |
if (selector & 0x4) |
if (load_segment(&e1, &e2, selector) != 0) |
|
dt = &env->ldt; |
|
|
else |
|
|
dt = &env->gdt; |
|
|
index = selector & ~7; |
|
|
if ((index + 7) > dt->limit) |
|
957 |
return; |
return; |
|
ptr = dt->base + index; |
|
|
e2 = ldl(ptr + 4); |
|
958 |
T1 = e2 & 0x00f0ff00; |
T1 = e2 & 0x00f0ff00; |
959 |
CC_SRC |= CC_Z; |
CC_SRC |= CC_Z; |
960 |
} |
} |