Revision 883da8e2 target-i386/helper.c
b/target-i386/helper.c | ||
---|---|---|
277 | 277 |
|
278 | 278 |
/* XXX: restore CPU state in registers (PowerPC case) */ |
279 | 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 | 283 |
int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i; |
283 | 284 |
uint8_t *tss_base; |
... | ... | |
369 | 370 |
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { |
370 | 371 |
uint8_t *ptr; |
371 | 372 |
uint32_t e2; |
372 |
ptr = env->gdt.base + (env->tr.selector << 3);
|
|
373 |
ptr = env->gdt.base + (env->tr.selector & ~7);
|
|
373 | 374 |
e2 = ldl_kernel(ptr + 4); |
374 | 375 |
e2 &= ~DESC_TSS_BUSY_MASK; |
375 | 376 |
stl_kernel(ptr + 4, e2); |
... | ... | |
381 | 382 |
/* save the current state in the old TSS */ |
382 | 383 |
if (type & 8) { |
383 | 384 |
/* 32 bit */ |
384 |
stl_kernel(env->tr.base + 0x20, env->eip);
|
|
385 |
stl_kernel(env->tr.base + 0x20, next_eip);
|
|
385 | 386 |
stl_kernel(env->tr.base + 0x24, old_eflags); |
386 | 387 |
for(i = 0; i < 8; i++) |
387 | 388 |
stl_kernel(env->tr.base + (0x28 + i * 4), env->regs[i]); |
... | ... | |
389 | 390 |
stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector); |
390 | 391 |
} else { |
391 | 392 |
/* 16 bit */ |
392 |
stw_kernel(env->tr.base + 0x0e, new_eip);
|
|
393 |
stw_kernel(env->tr.base + 0x0e, next_eip);
|
|
393 | 394 |
stw_kernel(env->tr.base + 0x10, old_eflags); |
394 | 395 |
for(i = 0; i < 8; i++) |
395 | 396 |
stw_kernel(env->tr.base + (0x12 + i * 2), env->regs[i]); |
... | ... | |
409 | 410 |
if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) { |
410 | 411 |
uint8_t *ptr; |
411 | 412 |
uint32_t e2; |
412 |
ptr = env->gdt.base + (tss_selector << 3);
|
|
413 |
ptr = env->gdt.base + (tss_selector & ~7);
|
|
413 | 414 |
e2 = ldl_kernel(ptr + 4); |
414 | 415 |
e2 |= DESC_TSS_BUSY_MASK; |
415 | 416 |
stl_kernel(ptr + 4, e2); |
... | ... | |
418 | 419 |
/* set the new CPU state */ |
419 | 420 |
/* from this point, any exception which occurs can give problems */ |
420 | 421 |
env->cr[0] |= CR0_TS_MASK; |
422 |
env->hflags |= HF_TS_MASK; |
|
421 | 423 |
env->tr.selector = tss_selector; |
422 | 424 |
env->tr.base = tss_base; |
423 | 425 |
env->tr.limit = tss_limit; |
... | ... | |
486 | 488 |
|
487 | 489 |
/* check that EIP is in the CS segment limits */ |
488 | 490 |
if (new_eip > env->segs[R_CS].limit) { |
491 |
/* XXX: different exception if CALL ? */ |
|
489 | 492 |
raise_exception_err(EXCP0D_GPF, 0); |
490 | 493 |
} |
491 | 494 |
} |
... | ... | |
603 | 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 | 614 |
dt = &env->idt; |
608 | 615 |
if (intno * 8 + 7 > dt->limit) |
... | ... | |
617 | 624 |
/* must do that check here to return the correct error code */ |
618 | 625 |
if (!(e2 & DESC_P_MASK)) |
619 | 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 | 628 |
if (has_error_code) { |
622 | 629 |
int mask; |
623 | 630 |
/* push the error code */ |
... | ... | |
713 | 720 |
push_size += 8; |
714 | 721 |
push_size <<= shift; |
715 | 722 |
#endif |
716 |
if (is_int) |
|
717 |
old_eip = next_eip; |
|
718 |
else |
|
719 |
old_eip = env->eip; |
|
720 | 723 |
if (shift == 1) { |
721 | 724 |
if (new_stack) { |
722 | 725 |
if (env->eflags & VM_MASK) { |
... | ... | |
1264 | 1267 |
case 5: /* task gate */ |
1265 | 1268 |
if (dpl < cpl || dpl < rpl) |
1266 | 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 | 1272 |
break; |
1269 | 1273 |
case 4: /* 286 call gate */ |
1270 | 1274 |
case 12: /* 386 call gate */ |
... | ... | |
1405 | 1409 |
case 5: /* task gate */ |
1406 | 1410 |
if (dpl < cpl || dpl < rpl) |
1407 | 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 | 1413 |
return; |
1410 | 1414 |
case 4: /* 286 call gate */ |
1411 | 1415 |
case 12: /* 386 call gate */ |
... | ... | |
1744 | 1748 |
/* NOTE: we check both segment and busy TSS */ |
1745 | 1749 |
if (type != 3) |
1746 | 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 | 1753 |
} else { |
1749 | 1754 |
helper_ret_protected(shift, 1, 0); |
1750 | 1755 |
} |
Also available in: Unified diff