364 |
|
|
365 |
num = (EAX & 0xffff); |
num = (EAX & 0xffff); |
366 |
den = (T0 & 0xff); |
den = (T0 & 0xff); |
367 |
if (den == 0) |
if (den == 0) { |
368 |
|
EIP = PARAM1; |
369 |
raise_exception(EXCP00_DIVZ); |
raise_exception(EXCP00_DIVZ); |
370 |
|
} |
371 |
q = (num / den) & 0xff; |
q = (num / den) & 0xff; |
372 |
r = (num % den) & 0xff; |
r = (num % den) & 0xff; |
373 |
EAX = (EAX & 0xffff0000) | (r << 8) | q; |
EAX = (EAX & 0xffff0000) | (r << 8) | q; |
379 |
|
|
380 |
num = (int16_t)EAX; |
num = (int16_t)EAX; |
381 |
den = (int8_t)T0; |
den = (int8_t)T0; |
382 |
if (den == 0) |
if (den == 0) { |
383 |
|
EIP = PARAM1; |
384 |
raise_exception(EXCP00_DIVZ); |
raise_exception(EXCP00_DIVZ); |
385 |
|
} |
386 |
q = (num / den) & 0xff; |
q = (num / den) & 0xff; |
387 |
r = (num % den) & 0xff; |
r = (num % den) & 0xff; |
388 |
EAX = (EAX & 0xffff0000) | (r << 8) | q; |
EAX = (EAX & 0xffff0000) | (r << 8) | q; |
394 |
|
|
395 |
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
396 |
den = (T0 & 0xffff); |
den = (T0 & 0xffff); |
397 |
if (den == 0) |
if (den == 0) { |
398 |
|
EIP = PARAM1; |
399 |
raise_exception(EXCP00_DIVZ); |
raise_exception(EXCP00_DIVZ); |
400 |
|
} |
401 |
q = (num / den) & 0xffff; |
q = (num / den) & 0xffff; |
402 |
r = (num % den) & 0xffff; |
r = (num % den) & 0xffff; |
403 |
EAX = (EAX & 0xffff0000) | q; |
EAX = (EAX & 0xffff0000) | q; |
410 |
|
|
411 |
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
412 |
den = (int16_t)T0; |
den = (int16_t)T0; |
413 |
if (den == 0) |
if (den == 0) { |
414 |
|
EIP = PARAM1; |
415 |
raise_exception(EXCP00_DIVZ); |
raise_exception(EXCP00_DIVZ); |
416 |
|
} |
417 |
q = (num / den) & 0xffff; |
q = (num / den) & 0xffff; |
418 |
r = (num % den) & 0xffff; |
r = (num % den) & 0xffff; |
419 |
EAX = (EAX & 0xffff0000) | q; |
EAX = (EAX & 0xffff0000) | q; |
443 |
|
|
444 |
num = EAX | ((uint64_t)EDX << 32); |
num = EAX | ((uint64_t)EDX << 32); |
445 |
den = T0; |
den = T0; |
446 |
if (den == 0) |
if (den == 0) { |
447 |
|
EIP = PARAM1; |
448 |
raise_exception(EXCP00_DIVZ); |
raise_exception(EXCP00_DIVZ); |
449 |
|
} |
450 |
#ifdef BUGGY_GCC_DIV64 |
#ifdef BUGGY_GCC_DIV64 |
451 |
r = div64(&q, num, den); |
r = div64(&q, num, den); |
452 |
#else |
#else |
464 |
|
|
465 |
num = EAX | ((uint64_t)EDX << 32); |
num = EAX | ((uint64_t)EDX << 32); |
466 |
den = T0; |
den = T0; |
467 |
if (den == 0) |
if (den == 0) { |
468 |
|
EIP = PARAM1; |
469 |
raise_exception(EXCP00_DIVZ); |
raise_exception(EXCP00_DIVZ); |
470 |
|
} |
471 |
#ifdef BUGGY_GCC_DIV64 |
#ifdef BUGGY_GCC_DIV64 |
472 |
r = idiv64(&q, num, den); |
r = idiv64(&q, num, den); |
473 |
#else |
#else |
626 |
EIP = PARAM1; |
EIP = PARAM1; |
627 |
} |
} |
628 |
|
|
629 |
void OPPROTO op_int_im(void) |
#if 0 |
630 |
|
/* full interrupt support (only useful for real CPU emulation, not |
631 |
|
finished) - I won't do it any time soon, finish it if you want ! */ |
632 |
|
void raise_interrupt(int intno, int is_int, int error_code, |
633 |
|
unsigned int next_eip) |
634 |
|
{ |
635 |
|
SegmentDescriptorTable *dt; |
636 |
|
uint8_t *ptr; |
637 |
|
int type, dpl, cpl; |
638 |
|
uint32_t e1, e2; |
639 |
|
|
640 |
|
dt = &env->idt; |
641 |
|
if (intno * 8 + 7 > dt->limit) |
642 |
|
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
643 |
|
ptr = dt->base + intno * 8; |
644 |
|
e1 = ldl(ptr); |
645 |
|
e2 = ldl(ptr + 4); |
646 |
|
/* check gate type */ |
647 |
|
type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
648 |
|
switch(type) { |
649 |
|
case 5: /* task gate */ |
650 |
|
case 6: /* 286 interrupt gate */ |
651 |
|
case 7: /* 286 trap gate */ |
652 |
|
case 14: /* 386 interrupt gate */ |
653 |
|
case 15: /* 386 trap gate */ |
654 |
|
break; |
655 |
|
default: |
656 |
|
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
657 |
|
break; |
658 |
|
} |
659 |
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
660 |
|
cpl = env->segs[R_CS] & 3; |
661 |
|
/* check privledge if software int */ |
662 |
|
if (is_int && dpl < cpl) |
663 |
|
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
664 |
|
/* check valid bit */ |
665 |
|
if (!(e2 & DESC_P_MASK)) |
666 |
|
raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); |
667 |
|
} |
668 |
|
|
669 |
|
#else |
670 |
|
|
671 |
|
/* |
672 |
|
* is_int is TRUE if coming from the int instruction. next_eip is the |
673 |
|
* EIP value AFTER the interrupt instruction. It is only relevant if |
674 |
|
* is_int is TRUE. |
675 |
|
*/ |
676 |
|
void raise_interrupt(int intno, int is_int, int error_code, |
677 |
|
unsigned int next_eip) |
678 |
|
{ |
679 |
|
SegmentDescriptorTable *dt; |
680 |
|
uint8_t *ptr; |
681 |
|
int dpl, cpl; |
682 |
|
uint32_t e2; |
683 |
|
|
684 |
|
dt = &env->idt; |
685 |
|
ptr = dt->base + (intno * 8); |
686 |
|
e2 = ldl(ptr + 4); |
687 |
|
|
688 |
|
dpl = (e2 >> DESC_DPL_SHIFT) & 3; |
689 |
|
cpl = 3; |
690 |
|
/* check privledge if software int */ |
691 |
|
if (is_int && dpl < cpl) |
692 |
|
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
693 |
|
|
694 |
|
/* Since we emulate only user space, we cannot do more than |
695 |
|
exiting the emulation with the suitable exception and error |
696 |
|
code */ |
697 |
|
if (is_int) |
698 |
|
EIP = next_eip; |
699 |
|
env->exception_index = intno; |
700 |
|
env->error_code = error_code; |
701 |
|
|
702 |
|
cpu_loop_exit(); |
703 |
|
} |
704 |
|
|
705 |
|
#endif |
706 |
|
|
707 |
|
/* shortcuts to generate exceptions */ |
708 |
|
void raise_exception_err(int exception_index, int error_code) |
709 |
|
{ |
710 |
|
raise_interrupt(exception_index, 0, error_code, 0); |
711 |
|
} |
712 |
|
|
713 |
|
void raise_exception(int exception_index) |
714 |
|
{ |
715 |
|
raise_interrupt(exception_index, 0, 0, 0); |
716 |
|
} |
717 |
|
|
718 |
|
void OPPROTO op_raise_interrupt(void) |
719 |
{ |
{ |
720 |
int intno; |
int intno; |
721 |
|
unsigned int next_eip; |
722 |
intno = PARAM1; |
intno = PARAM1; |
723 |
EIP = PARAM2; |
next_eip = PARAM2; |
724 |
raise_exception_err(EXCP0D_GPF, intno * 8 + 2); |
raise_interrupt(intno, 1, 0, next_eip); |
725 |
} |
} |
726 |
|
|
727 |
void OPPROTO op_raise_exception(void) |
void OPPROTO op_raise_exception(void) |
736 |
int eflags; |
int eflags; |
737 |
eflags = cc_table[CC_OP].compute_all(); |
eflags = cc_table[CC_OP].compute_all(); |
738 |
if (eflags & CC_O) { |
if (eflags & CC_O) { |
739 |
EIP = PARAM1; |
raise_interrupt(EXCP04_INTO, 1, 0, PARAM1); |
|
raise_exception(EXCP04_INTO); |
|
740 |
} |
} |
741 |
FORCE_RET(); |
FORCE_RET(); |
742 |
} |
} |
775 |
low = ldsw((uint8_t *)A0); |
low = ldsw((uint8_t *)A0); |
776 |
high = ldsw((uint8_t *)A0 + 2); |
high = ldsw((uint8_t *)A0 + 2); |
777 |
v = (int16_t)T0; |
v = (int16_t)T0; |
778 |
if (v < low || v > high) |
if (v < low || v > high) { |
779 |
|
EIP = PARAM1; |
780 |
raise_exception(EXCP05_BOUND); |
raise_exception(EXCP05_BOUND); |
781 |
|
} |
782 |
FORCE_RET(); |
FORCE_RET(); |
783 |
} |
} |
784 |
|
|
788 |
low = ldl((uint8_t *)A0); |
low = ldl((uint8_t *)A0); |
789 |
high = ldl((uint8_t *)A0 + 4); |
high = ldl((uint8_t *)A0 + 4); |
790 |
v = T0; |
v = T0; |
791 |
if (v < low || v > high) |
if (v < low || v > high) { |
792 |
|
EIP = PARAM1; |
793 |
raise_exception(EXCP05_BOUND); |
raise_exception(EXCP05_BOUND); |
794 |
|
} |
795 |
FORCE_RET(); |
FORCE_RET(); |
796 |
} |
} |
797 |
|
|
1221 |
|
|
1222 |
/* segment handling */ |
/* segment handling */ |
1223 |
|
|
1224 |
/* XXX: use static VM86 information */ |
/* only works if protected mode and not VM86 */ |
1225 |
void load_seg(int seg_reg, int selector) |
void load_seg(int seg_reg, int selector, unsigned cur_eip) |
1226 |
{ |
{ |
1227 |
SegmentCache *sc; |
SegmentCache *sc; |
1228 |
SegmentDescriptorTable *dt; |
SegmentDescriptorTable *dt; |
1231 |
uint8_t *ptr; |
uint8_t *ptr; |
1232 |
|
|
1233 |
sc = &env->seg_cache[seg_reg]; |
sc = &env->seg_cache[seg_reg]; |
1234 |
if (env->eflags & VM_MASK) { |
if ((selector & 0xfffc) == 0) { |
1235 |
sc->base = (void *)(selector << 4); |
/* null selector case */ |
1236 |
sc->limit = 0xffff; |
if (seg_reg == R_SS) { |
1237 |
sc->seg_32bit = 0; |
EIP = cur_eip; |
1238 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1239 |
|
} else { |
1240 |
|
/* XXX: each access should trigger an exception */ |
1241 |
|
sc->base = NULL; |
1242 |
|
sc->limit = 0; |
1243 |
|
sc->seg_32bit = 1; |
1244 |
|
} |
1245 |
} else { |
} else { |
1246 |
if (selector & 0x4) |
if (selector & 0x4) |
1247 |
dt = &env->ldt; |
dt = &env->ldt; |
1248 |
else |
else |
1249 |
dt = &env->gdt; |
dt = &env->gdt; |
1250 |
index = selector & ~7; |
index = selector & ~7; |
1251 |
if ((index + 7) > dt->limit) |
if ((index + 7) > dt->limit) { |
1252 |
raise_exception_err(EXCP0D_GPF, selector); |
EIP = cur_eip; |
1253 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1254 |
|
} |
1255 |
ptr = dt->base + index; |
ptr = dt->base + index; |
1256 |
e1 = ldl(ptr); |
e1 = ldl(ptr); |
1257 |
e2 = ldl(ptr + 4); |
e2 = ldl(ptr + 4); |
1258 |
|
if (!(e2 & DESC_S_MASK) || |
1259 |
|
(e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { |
1260 |
|
EIP = cur_eip; |
1261 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1262 |
|
} |
1263 |
|
|
1264 |
|
if (seg_reg == R_SS) { |
1265 |
|
if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { |
1266 |
|
EIP = cur_eip; |
1267 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1268 |
|
} |
1269 |
|
} else { |
1270 |
|
if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { |
1271 |
|
EIP = cur_eip; |
1272 |
|
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
1273 |
|
} |
1274 |
|
} |
1275 |
|
|
1276 |
|
if (!(e2 & DESC_P_MASK)) { |
1277 |
|
EIP = cur_eip; |
1278 |
|
if (seg_reg == R_SS) |
1279 |
|
raise_exception_err(EXCP0C_STACK, selector & 0xfffc); |
1280 |
|
else |
1281 |
|
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); |
1282 |
|
} |
1283 |
|
|
1284 |
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
1285 |
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
1286 |
if (e2 & (1 << 23)) |
if (e2 & (1 << 23)) |
1296 |
|
|
1297 |
void OPPROTO op_movl_seg_T0(void) |
void OPPROTO op_movl_seg_T0(void) |
1298 |
{ |
{ |
1299 |
load_seg(PARAM1, T0 & 0xffff); |
load_seg(PARAM1, T0 & 0xffff, PARAM2); |
1300 |
|
} |
1301 |
|
|
1302 |
|
/* faster VM86 version */ |
1303 |
|
void OPPROTO op_movl_seg_T0_vm(void) |
1304 |
|
{ |
1305 |
|
int selector; |
1306 |
|
|
1307 |
|
selector = T0 & 0xffff; |
1308 |
|
/* env->segs[] access */ |
1309 |
|
*(uint32_t *)((char *)env + PARAM1) = selector; |
1310 |
|
/* env->seg_cache[] access */ |
1311 |
|
((SegmentCache *)((char *)env + PARAM2))->base = (void *)(selector << 4); |
1312 |
} |
} |
1313 |
|
|
1314 |
void OPPROTO op_movl_T0_seg(void) |
void OPPROTO op_movl_T0_seg(void) |