Commit 883da8e21932b24630f87ed4d801ea1ad48b735b

Authored by bellard
1 parent 78ebca6e

task switch fixes


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@681 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 18 additions and 13 deletions
target-i386/helper.c
@@ -277,7 +277,8 @@ static void tss_load_seg(int seg_reg, int selector) @@ -277,7 +277,8 @@ static void tss_load_seg(int seg_reg, int selector)
277 277
278 /* XXX: restore CPU state in registers (PowerPC case) */ 278 /* XXX: restore CPU state in registers (PowerPC case) */
279 static void switch_tss(int tss_selector, 279 static void switch_tss(int tss_selector,
280 - uint32_t e1, uint32_t e2, int source) 280 + uint32_t e1, uint32_t e2, int source,
  281 + uint32_t next_eip)
281 { 282 {
282 int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; 283 int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
283 uint8_t *tss_base; 284 uint8_t *tss_base;
@@ -369,7 +370,7 @@ static void switch_tss(int tss_selector, @@ -369,7 +370,7 @@ static void switch_tss(int tss_selector,
369 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { 370 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
370 uint8_t *ptr; 371 uint8_t *ptr;
371 uint32_t e2; 372 uint32_t e2;
372 - ptr = env->gdt.base + (env->tr.selector << 3); 373 + ptr = env->gdt.base + (env->tr.selector & ~7);
373 e2 = ldl_kernel(ptr + 4); 374 e2 = ldl_kernel(ptr + 4);
374 e2 &= ~DESC_TSS_BUSY_MASK; 375 e2 &= ~DESC_TSS_BUSY_MASK;
375 stl_kernel(ptr + 4, e2); 376 stl_kernel(ptr + 4, e2);
@@ -381,7 +382,7 @@ static void switch_tss(int tss_selector, @@ -381,7 +382,7 @@ static void switch_tss(int tss_selector,
381 /* save the current state in the old TSS */ 382 /* save the current state in the old TSS */
382 if (type & 8) { 383 if (type & 8) {
383 /* 32 bit */ 384 /* 32 bit */
384 - stl_kernel(env->tr.base + 0x20, env->eip); 385 + stl_kernel(env->tr.base + 0x20, next_eip);
385 stl_kernel(env->tr.base + 0x24, old_eflags); 386 stl_kernel(env->tr.base + 0x24, old_eflags);
386 for(i = 0; i < 8; i++) 387 for(i = 0; i < 8; i++)
387 stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]); 388 stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]);
@@ -389,7 +390,7 @@ static void switch_tss(int tss_selector, @@ -389,7 +390,7 @@ static void switch_tss(int tss_selector,
389 stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); 390 stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
390 } else { 391 } else {
391 /* 16 bit */ 392 /* 16 bit */
392 - stw_kernel(env->tr.base + 0x0e, new_eip); 393 + stw_kernel(env->tr.base + 0x0e, next_eip);
393 stw_kernel(env->tr.base + 0x10, old_eflags); 394 stw_kernel(env->tr.base + 0x10, old_eflags);
394 for(i = 0; i < 8; i++) 395 for(i = 0; i < 8; i++)
395 stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]); 396 stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]);
@@ -409,7 +410,7 @@ static void switch_tss(int tss_selector, @@ -409,7 +410,7 @@ static void switch_tss(int tss_selector,
409 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { 410 if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
410 uint8_t *ptr; 411 uint8_t *ptr;
411 uint32_t e2; 412 uint32_t e2;
412 - ptr = env->gdt.base + (tss_selector << 3); 413 + ptr = env->gdt.base + (tss_selector & ~7);
413 e2 = ldl_kernel(ptr + 4); 414 e2 = ldl_kernel(ptr + 4);
414 e2 |= DESC_TSS_BUSY_MASK; 415 e2 |= DESC_TSS_BUSY_MASK;
415 stl_kernel(ptr + 4, e2); 416 stl_kernel(ptr + 4, e2);
@@ -418,6 +419,7 @@ static void switch_tss(int tss_selector, @@ -418,6 +419,7 @@ static void switch_tss(int tss_selector,
418 /* set the new CPU state */ 419 /* set the new CPU state */
419 /* from this point, any exception which occurs can give problems */ 420 /* from this point, any exception which occurs can give problems */
420 env->cr[0] |= CR0_TS_MASK; 421 env->cr[0] |= CR0_TS_MASK;
  422 + env->hflags |= HF_TS_MASK;
421 env->tr.selector = tss_selector; 423 env->tr.selector = tss_selector;
422 env->tr.base = tss_base; 424 env->tr.base = tss_base;
423 env->tr.limit = tss_limit; 425 env->tr.limit = tss_limit;
@@ -486,6 +488,7 @@ static void switch_tss(int tss_selector, @@ -486,6 +488,7 @@ static void switch_tss(int tss_selector,
486 488
487 /* check that EIP is in the CS segment limits */ 489 /* check that EIP is in the CS segment limits */
488 if (new_eip > env->segs[R_CS].limit) { 490 if (new_eip > env->segs[R_CS].limit) {
  491 + /* XXX: different exception if CALL ? */
489 raise_exception_err(EXCP0D_GPF, 0); 492 raise_exception_err(EXCP0D_GPF, 0);
490 } 493 }
491 } 494 }
@@ -603,6 +606,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, @@ -603,6 +606,10 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
603 break; 606 break;
604 } 607 }
605 } 608 }
  609 + if (is_int)
  610 + old_eip = next_eip;
  611 + else
  612 + old_eip = env->eip;
606 613
607 dt = &env->idt; 614 dt = &env->idt;
608 if (intno * 8 + 7 > dt->limit) 615 if (intno * 8 + 7 > dt->limit)
@@ -617,7 +624,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, @@ -617,7 +624,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
617 /* must do that check here to return the correct error code */ 624 /* must do that check here to return the correct error code */
618 if (!(e2 & DESC_P_MASK)) 625 if (!(e2 & DESC_P_MASK))
619 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); 626 raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
620 - switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL); 627 + switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
621 if (has_error_code) { 628 if (has_error_code) {
622 int mask; 629 int mask;
623 /* push the error code */ 630 /* push the error code */
@@ -713,10 +720,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code, @@ -713,10 +720,6 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
713 push_size += 8; 720 push_size += 8;
714 push_size <<= shift; 721 push_size <<= shift;
715 #endif 722 #endif
716 - if (is_int)  
717 - old_eip = next_eip;  
718 - else  
719 - old_eip = env->eip;  
720 if (shift == 1) { 723 if (shift == 1) {
721 if (new_stack) { 724 if (new_stack) {
722 if (env->eflags & VM_MASK) { 725 if (env->eflags & VM_MASK) {
@@ -1264,7 +1267,8 @@ void helper_ljmp_protected_T0_T1(void) @@ -1264,7 +1267,8 @@ void helper_ljmp_protected_T0_T1(void)
1264 case 5: /* task gate */ 1267 case 5: /* task gate */
1265 if (dpl < cpl || dpl < rpl) 1268 if (dpl < cpl || dpl < rpl)
1266 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 1269 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1267 - switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP); 1270 + /* XXX: check if it is really the current EIP */
  1271 + switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, env->eip);
1268 break; 1272 break;
1269 case 4: /* 286 call gate */ 1273 case 4: /* 286 call gate */
1270 case 12: /* 386 call gate */ 1274 case 12: /* 386 call gate */
@@ -1405,7 +1409,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) @@ -1405,7 +1409,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip)
1405 case 5: /* task gate */ 1409 case 5: /* task gate */
1406 if (dpl < cpl || dpl < rpl) 1410 if (dpl < cpl || dpl < rpl)
1407 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); 1411 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
1408 - switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL); 1412 + switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
1409 return; 1413 return;
1410 case 4: /* 286 call gate */ 1414 case 4: /* 286 call gate */
1411 case 12: /* 386 call gate */ 1415 case 12: /* 386 call gate */
@@ -1744,7 +1748,8 @@ void helper_iret_protected(int shift) @@ -1744,7 +1748,8 @@ void helper_iret_protected(int shift)
1744 /* NOTE: we check both segment and busy TSS */ 1748 /* NOTE: we check both segment and busy TSS */
1745 if (type != 3) 1749 if (type != 3)
1746 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc); 1750 raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
1747 - switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET); 1751 + /* XXX: check if it is really the current EIP */
  1752 + switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, env->eip);
1748 } else { 1753 } else {
1749 helper_ret_protected(shift, 1, 0); 1754 helper_ret_protected(shift, 1, 0);
1750 } 1755 }