Commit 883da8e21932b24630f87ed4d801ea1ad48b735b
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 | } |