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