Commit f4beb510a41980e119f787746442ca1b87c06754
1 parent
d731dae8
precise exceptions - more accurate interrupt semantics
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@193 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
250 additions
and
54 deletions
linux-user/main.c
@@ -100,24 +100,35 @@ int cpu_x86_inl(CPUX86State *env, int addr) | @@ -100,24 +100,35 @@ int cpu_x86_inl(CPUX86State *env, int addr) | ||
100 | return 0; | 100 | return 0; |
101 | } | 101 | } |
102 | 102 | ||
103 | -void write_dt(void *ptr, unsigned long addr, unsigned long limit, | ||
104 | - int seg32_bit) | 103 | +static void write_dt(void *ptr, unsigned long addr, unsigned long limit, |
104 | + int flags) | ||
105 | { | 105 | { |
106 | - unsigned int e1, e2, limit_in_pages; | ||
107 | - limit_in_pages = 0; | ||
108 | - if (limit > 0xffff) { | ||
109 | - limit = limit >> 12; | ||
110 | - limit_in_pages = 1; | ||
111 | - } | 106 | + unsigned int e1, e2; |
112 | e1 = (addr << 16) | (limit & 0xffff); | 107 | e1 = (addr << 16) | (limit & 0xffff); |
113 | e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); | 108 | e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); |
114 | - e2 |= limit_in_pages << 23; /* byte granularity */ | ||
115 | - e2 |= seg32_bit << 22; /* 32 bit segment */ | 109 | + e2 |= flags; |
110 | + stl((uint8_t *)ptr, e1); | ||
111 | + stl((uint8_t *)ptr + 4, e2); | ||
112 | +} | ||
113 | + | ||
114 | +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, | ||
115 | + unsigned long addr, unsigned int sel) | ||
116 | +{ | ||
117 | + unsigned int e1, e2; | ||
118 | + e1 = (addr & 0xffff) | (sel << 16); | ||
119 | + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); | ||
116 | stl((uint8_t *)ptr, e1); | 120 | stl((uint8_t *)ptr, e1); |
117 | stl((uint8_t *)ptr + 4, e2); | 121 | stl((uint8_t *)ptr + 4, e2); |
118 | } | 122 | } |
119 | 123 | ||
120 | uint64_t gdt_table[6]; | 124 | uint64_t gdt_table[6]; |
125 | +uint64_t idt_table[256]; | ||
126 | + | ||
127 | +/* only dpl matters as we do only user space emulation */ | ||
128 | +static void set_idt(int n, unsigned int dpl) | ||
129 | +{ | ||
130 | + set_gate(idt_table + n, 0, dpl, 0, 0); | ||
131 | +} | ||
121 | 132 | ||
122 | void cpu_loop(CPUX86State *env) | 133 | void cpu_loop(CPUX86State *env) |
123 | { | 134 | { |
@@ -128,30 +139,34 @@ void cpu_loop(CPUX86State *env) | @@ -128,30 +139,34 @@ void cpu_loop(CPUX86State *env) | ||
128 | for(;;) { | 139 | for(;;) { |
129 | trapnr = cpu_x86_exec(env); | 140 | trapnr = cpu_x86_exec(env); |
130 | switch(trapnr) { | 141 | switch(trapnr) { |
142 | + case 0x80: | ||
143 | + /* linux syscall */ | ||
144 | + env->regs[R_EAX] = do_syscall(env, | ||
145 | + env->regs[R_EAX], | ||
146 | + env->regs[R_EBX], | ||
147 | + env->regs[R_ECX], | ||
148 | + env->regs[R_EDX], | ||
149 | + env->regs[R_ESI], | ||
150 | + env->regs[R_EDI], | ||
151 | + env->regs[R_EBP]); | ||
152 | + break; | ||
153 | + case EXCP0B_NOSEG: | ||
154 | + case EXCP0C_STACK: | ||
155 | + info.si_signo = SIGBUS; | ||
156 | + info.si_errno = 0; | ||
157 | + info.si_code = TARGET_SI_KERNEL; | ||
158 | + info._sifields._sigfault._addr = 0; | ||
159 | + queue_signal(info.si_signo, &info); | ||
160 | + break; | ||
131 | case EXCP0D_GPF: | 161 | case EXCP0D_GPF: |
132 | if (env->eflags & VM_MASK) { | 162 | if (env->eflags & VM_MASK) { |
133 | handle_vm86_fault(env); | 163 | handle_vm86_fault(env); |
134 | } else { | 164 | } else { |
135 | - pc = env->seg_cache[R_CS].base + env->eip; | ||
136 | - if (pc[0] == 0xcd && pc[1] == 0x80) { | ||
137 | - /* syscall */ | ||
138 | - env->eip += 2; | ||
139 | - env->regs[R_EAX] = do_syscall(env, | ||
140 | - env->regs[R_EAX], | ||
141 | - env->regs[R_EBX], | ||
142 | - env->regs[R_ECX], | ||
143 | - env->regs[R_EDX], | ||
144 | - env->regs[R_ESI], | ||
145 | - env->regs[R_EDI], | ||
146 | - env->regs[R_EBP]); | ||
147 | - } else { | ||
148 | - /* XXX: more precise info */ | ||
149 | - info.si_signo = SIGSEGV; | ||
150 | - info.si_errno = 0; | ||
151 | - info.si_code = TARGET_SI_KERNEL; | ||
152 | - info._sifields._sigfault._addr = 0; | ||
153 | - queue_signal(info.si_signo, &info); | ||
154 | - } | 165 | + info.si_signo = SIGSEGV; |
166 | + info.si_errno = 0; | ||
167 | + info.si_code = TARGET_SI_KERNEL; | ||
168 | + info._sifields._sigfault._addr = 0; | ||
169 | + queue_signal(info.si_signo, &info); | ||
155 | } | 170 | } |
156 | break; | 171 | break; |
157 | case EXCP0E_PAGE: | 172 | case EXCP0E_PAGE: |
@@ -365,11 +380,40 @@ int main(int argc, char **argv) | @@ -365,11 +380,40 @@ int main(int argc, char **argv) | ||
365 | env->regs[R_ESP] = regs->esp; | 380 | env->regs[R_ESP] = regs->esp; |
366 | env->eip = regs->eip; | 381 | env->eip = regs->eip; |
367 | 382 | ||
383 | + /* linux interrupt setup */ | ||
384 | + env->idt.base = (void *)idt_table; | ||
385 | + env->idt.limit = sizeof(idt_table) - 1; | ||
386 | + set_idt(0, 0); | ||
387 | + set_idt(1, 0); | ||
388 | + set_idt(2, 0); | ||
389 | + set_idt(3, 3); | ||
390 | + set_idt(4, 3); | ||
391 | + set_idt(5, 3); | ||
392 | + set_idt(6, 0); | ||
393 | + set_idt(7, 0); | ||
394 | + set_idt(8, 0); | ||
395 | + set_idt(9, 0); | ||
396 | + set_idt(10, 0); | ||
397 | + set_idt(11, 0); | ||
398 | + set_idt(12, 0); | ||
399 | + set_idt(13, 0); | ||
400 | + set_idt(14, 0); | ||
401 | + set_idt(15, 0); | ||
402 | + set_idt(16, 0); | ||
403 | + set_idt(17, 0); | ||
404 | + set_idt(18, 0); | ||
405 | + set_idt(19, 0); | ||
406 | + set_idt(0x80, 3); | ||
407 | + | ||
368 | /* linux segment setup */ | 408 | /* linux segment setup */ |
369 | env->gdt.base = (void *)gdt_table; | 409 | env->gdt.base = (void *)gdt_table; |
370 | env->gdt.limit = sizeof(gdt_table) - 1; | 410 | env->gdt.limit = sizeof(gdt_table) - 1; |
371 | - write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1); | ||
372 | - write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1); | 411 | + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, |
412 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | | ||
413 | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); | ||
414 | + write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, | ||
415 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | | ||
416 | + (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); | ||
373 | cpu_x86_load_seg(env, R_CS, __USER_CS); | 417 | cpu_x86_load_seg(env, R_CS, __USER_CS); |
374 | cpu_x86_load_seg(env, R_DS, __USER_DS); | 418 | cpu_x86_load_seg(env, R_DS, __USER_DS); |
375 | cpu_x86_load_seg(env, R_ES, __USER_DS); | 419 | cpu_x86_load_seg(env, R_ES, __USER_DS); |
op-i386.c
@@ -364,8 +364,10 @@ void OPPROTO op_divb_AL_T0(void) | @@ -364,8 +364,10 @@ void OPPROTO op_divb_AL_T0(void) | ||
364 | 364 | ||
365 | num = (EAX & 0xffff); | 365 | num = (EAX & 0xffff); |
366 | den = (T0 & 0xff); | 366 | den = (T0 & 0xff); |
367 | - if (den == 0) | 367 | + if (den == 0) { |
368 | + EIP = PARAM1; | ||
368 | raise_exception(EXCP00_DIVZ); | 369 | raise_exception(EXCP00_DIVZ); |
370 | + } | ||
369 | q = (num / den) & 0xff; | 371 | q = (num / den) & 0xff; |
370 | r = (num % den) & 0xff; | 372 | r = (num % den) & 0xff; |
371 | EAX = (EAX & 0xffff0000) | (r << 8) | q; | 373 | EAX = (EAX & 0xffff0000) | (r << 8) | q; |
@@ -377,8 +379,10 @@ void OPPROTO op_idivb_AL_T0(void) | @@ -377,8 +379,10 @@ void OPPROTO op_idivb_AL_T0(void) | ||
377 | 379 | ||
378 | num = (int16_t)EAX; | 380 | num = (int16_t)EAX; |
379 | den = (int8_t)T0; | 381 | den = (int8_t)T0; |
380 | - if (den == 0) | 382 | + if (den == 0) { |
383 | + EIP = PARAM1; | ||
381 | raise_exception(EXCP00_DIVZ); | 384 | raise_exception(EXCP00_DIVZ); |
385 | + } | ||
382 | q = (num / den) & 0xff; | 386 | q = (num / den) & 0xff; |
383 | r = (num % den) & 0xff; | 387 | r = (num % den) & 0xff; |
384 | EAX = (EAX & 0xffff0000) | (r << 8) | q; | 388 | EAX = (EAX & 0xffff0000) | (r << 8) | q; |
@@ -390,8 +394,10 @@ void OPPROTO op_divw_AX_T0(void) | @@ -390,8 +394,10 @@ void OPPROTO op_divw_AX_T0(void) | ||
390 | 394 | ||
391 | num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); | 395 | num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
392 | den = (T0 & 0xffff); | 396 | den = (T0 & 0xffff); |
393 | - if (den == 0) | 397 | + if (den == 0) { |
398 | + EIP = PARAM1; | ||
394 | raise_exception(EXCP00_DIVZ); | 399 | raise_exception(EXCP00_DIVZ); |
400 | + } | ||
395 | q = (num / den) & 0xffff; | 401 | q = (num / den) & 0xffff; |
396 | r = (num % den) & 0xffff; | 402 | r = (num % den) & 0xffff; |
397 | EAX = (EAX & 0xffff0000) | q; | 403 | EAX = (EAX & 0xffff0000) | q; |
@@ -404,8 +410,10 @@ void OPPROTO op_idivw_AX_T0(void) | @@ -404,8 +410,10 @@ void OPPROTO op_idivw_AX_T0(void) | ||
404 | 410 | ||
405 | num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); | 411 | num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
406 | den = (int16_t)T0; | 412 | den = (int16_t)T0; |
407 | - if (den == 0) | 413 | + if (den == 0) { |
414 | + EIP = PARAM1; | ||
408 | raise_exception(EXCP00_DIVZ); | 415 | raise_exception(EXCP00_DIVZ); |
416 | + } | ||
409 | q = (num / den) & 0xffff; | 417 | q = (num / den) & 0xffff; |
410 | r = (num % den) & 0xffff; | 418 | r = (num % den) & 0xffff; |
411 | EAX = (EAX & 0xffff0000) | q; | 419 | EAX = (EAX & 0xffff0000) | q; |
@@ -435,8 +443,10 @@ void OPPROTO op_divl_EAX_T0(void) | @@ -435,8 +443,10 @@ void OPPROTO op_divl_EAX_T0(void) | ||
435 | 443 | ||
436 | num = EAX | ((uint64_t)EDX << 32); | 444 | num = EAX | ((uint64_t)EDX << 32); |
437 | den = T0; | 445 | den = T0; |
438 | - if (den == 0) | 446 | + if (den == 0) { |
447 | + EIP = PARAM1; | ||
439 | raise_exception(EXCP00_DIVZ); | 448 | raise_exception(EXCP00_DIVZ); |
449 | + } | ||
440 | #ifdef BUGGY_GCC_DIV64 | 450 | #ifdef BUGGY_GCC_DIV64 |
441 | r = div64(&q, num, den); | 451 | r = div64(&q, num, den); |
442 | #else | 452 | #else |
@@ -454,8 +464,10 @@ void OPPROTO op_idivl_EAX_T0(void) | @@ -454,8 +464,10 @@ void OPPROTO op_idivl_EAX_T0(void) | ||
454 | 464 | ||
455 | num = EAX | ((uint64_t)EDX << 32); | 465 | num = EAX | ((uint64_t)EDX << 32); |
456 | den = T0; | 466 | den = T0; |
457 | - if (den == 0) | 467 | + if (den == 0) { |
468 | + EIP = PARAM1; | ||
458 | raise_exception(EXCP00_DIVZ); | 469 | raise_exception(EXCP00_DIVZ); |
470 | + } | ||
459 | #ifdef BUGGY_GCC_DIV64 | 471 | #ifdef BUGGY_GCC_DIV64 |
460 | r = idiv64(&q, num, den); | 472 | r = idiv64(&q, num, den); |
461 | #else | 473 | #else |
@@ -614,12 +626,102 @@ void OPPROTO op_jmp_im(void) | @@ -614,12 +626,102 @@ void OPPROTO op_jmp_im(void) | ||
614 | EIP = PARAM1; | 626 | EIP = PARAM1; |
615 | } | 627 | } |
616 | 628 | ||
617 | -void OPPROTO op_int_im(void) | 629 | +#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) | ||
618 | { | 719 | { |
619 | int intno; | 720 | int intno; |
721 | + unsigned int next_eip; | ||
620 | intno = PARAM1; | 722 | intno = PARAM1; |
621 | - EIP = PARAM2; | ||
622 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | 723 | + next_eip = PARAM2; |
724 | + raise_interrupt(intno, 1, 0, next_eip); | ||
623 | } | 725 | } |
624 | 726 | ||
625 | void OPPROTO op_raise_exception(void) | 727 | void OPPROTO op_raise_exception(void) |
@@ -634,8 +736,7 @@ void OPPROTO op_into(void) | @@ -634,8 +736,7 @@ void OPPROTO op_into(void) | ||
634 | int eflags; | 736 | int eflags; |
635 | eflags = cc_table[CC_OP].compute_all(); | 737 | eflags = cc_table[CC_OP].compute_all(); |
636 | if (eflags & CC_O) { | 738 | if (eflags & CC_O) { |
637 | - EIP = PARAM1; | ||
638 | - raise_exception(EXCP04_INTO); | 739 | + raise_interrupt(EXCP04_INTO, 1, 0, PARAM1); |
639 | } | 740 | } |
640 | FORCE_RET(); | 741 | FORCE_RET(); |
641 | } | 742 | } |
@@ -674,8 +775,10 @@ void OPPROTO op_boundw(void) | @@ -674,8 +775,10 @@ void OPPROTO op_boundw(void) | ||
674 | low = ldsw((uint8_t *)A0); | 775 | low = ldsw((uint8_t *)A0); |
675 | high = ldsw((uint8_t *)A0 + 2); | 776 | high = ldsw((uint8_t *)A0 + 2); |
676 | v = (int16_t)T0; | 777 | v = (int16_t)T0; |
677 | - if (v < low || v > high) | 778 | + if (v < low || v > high) { |
779 | + EIP = PARAM1; | ||
678 | raise_exception(EXCP05_BOUND); | 780 | raise_exception(EXCP05_BOUND); |
781 | + } | ||
679 | FORCE_RET(); | 782 | FORCE_RET(); |
680 | } | 783 | } |
681 | 784 | ||
@@ -685,8 +788,10 @@ void OPPROTO op_boundl(void) | @@ -685,8 +788,10 @@ void OPPROTO op_boundl(void) | ||
685 | low = ldl((uint8_t *)A0); | 788 | low = ldl((uint8_t *)A0); |
686 | high = ldl((uint8_t *)A0 + 4); | 789 | high = ldl((uint8_t *)A0 + 4); |
687 | v = T0; | 790 | v = T0; |
688 | - if (v < low || v > high) | 791 | + if (v < low || v > high) { |
792 | + EIP = PARAM1; | ||
689 | raise_exception(EXCP05_BOUND); | 793 | raise_exception(EXCP05_BOUND); |
794 | + } | ||
690 | FORCE_RET(); | 795 | FORCE_RET(); |
691 | } | 796 | } |
692 | 797 | ||
@@ -1116,8 +1221,8 @@ void OPPROTO op_das(void) | @@ -1116,8 +1221,8 @@ void OPPROTO op_das(void) | ||
1116 | 1221 | ||
1117 | /* segment handling */ | 1222 | /* segment handling */ |
1118 | 1223 | ||
1119 | -/* XXX: use static VM86 information */ | ||
1120 | -void load_seg(int seg_reg, int selector) | 1224 | +/* only works if protected mode and not VM86 */ |
1225 | +void load_seg(int seg_reg, int selector, unsigned cur_eip) | ||
1121 | { | 1226 | { |
1122 | SegmentCache *sc; | 1227 | SegmentCache *sc; |
1123 | SegmentDescriptorTable *dt; | 1228 | SegmentDescriptorTable *dt; |
@@ -1126,21 +1231,56 @@ void load_seg(int seg_reg, int selector) | @@ -1126,21 +1231,56 @@ void load_seg(int seg_reg, int selector) | ||
1126 | uint8_t *ptr; | 1231 | uint8_t *ptr; |
1127 | 1232 | ||
1128 | sc = &env->seg_cache[seg_reg]; | 1233 | sc = &env->seg_cache[seg_reg]; |
1129 | - if (env->eflags & VM_MASK) { | ||
1130 | - sc->base = (void *)(selector << 4); | ||
1131 | - sc->limit = 0xffff; | ||
1132 | - sc->seg_32bit = 0; | 1234 | + if ((selector & 0xfffc) == 0) { |
1235 | + /* null selector case */ | ||
1236 | + if (seg_reg == R_SS) { | ||
1237 | + 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 | + } | ||
1133 | } else { | 1245 | } else { |
1134 | if (selector & 0x4) | 1246 | if (selector & 0x4) |
1135 | dt = &env->ldt; | 1247 | dt = &env->ldt; |
1136 | else | 1248 | else |
1137 | dt = &env->gdt; | 1249 | dt = &env->gdt; |
1138 | index = selector & ~7; | 1250 | index = selector & ~7; |
1139 | - if ((index + 7) > dt->limit) | ||
1140 | - raise_exception_err(EXCP0D_GPF, selector); | 1251 | + if ((index + 7) > dt->limit) { |
1252 | + EIP = cur_eip; | ||
1253 | + raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | ||
1254 | + } | ||
1141 | ptr = dt->base + index; | 1255 | ptr = dt->base + index; |
1142 | e1 = ldl(ptr); | 1256 | e1 = ldl(ptr); |
1143 | e2 = ldl(ptr + 4); | 1257 | 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 | + | ||
1144 | sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); | 1284 | sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
1145 | sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); | 1285 | sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
1146 | if (e2 & (1 << 23)) | 1286 | if (e2 & (1 << 23)) |
@@ -1156,7 +1296,19 @@ void load_seg(int seg_reg, int selector) | @@ -1156,7 +1296,19 @@ void load_seg(int seg_reg, int selector) | ||
1156 | 1296 | ||
1157 | void OPPROTO op_movl_seg_T0(void) | 1297 | void OPPROTO op_movl_seg_T0(void) |
1158 | { | 1298 | { |
1159 | - load_seg(PARAM1, T0 & 0xffff); | 1299 | + 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); | ||
1160 | } | 1312 | } |
1161 | 1313 | ||
1162 | void OPPROTO op_movl_T0_seg(void) | 1314 | void OPPROTO op_movl_T0_seg(void) |