| 531 |
check_io(EDX & 0xffff, 4); |
check_io(EDX & 0xffff, 4); |
| 532 |
} |
} |
| 533 |
|
|
| 534 |
|
static inline unsigned int get_sp_mask(unsigned int e2) |
| 535 |
|
{ |
| 536 |
|
if (e2 & DESC_B_MASK) |
| 537 |
|
return 0xffffffff; |
| 538 |
|
else |
| 539 |
|
return 0xffff; |
| 540 |
|
} |
| 541 |
|
|
| 542 |
|
/* XXX: add a is_user flag to have proper security support */ |
| 543 |
|
#define PUSHW(ssp, sp, sp_mask, val)\ |
| 544 |
|
{\ |
| 545 |
|
sp -= 2;\ |
| 546 |
|
stw_kernel((ssp) + (sp & (sp_mask)), (val));\ |
| 547 |
|
} |
| 548 |
|
|
| 549 |
|
#define PUSHL(ssp, sp, sp_mask, val)\ |
| 550 |
|
{\ |
| 551 |
|
sp -= 4;\ |
| 552 |
|
stl_kernel((ssp) + (sp & (sp_mask)), (val));\ |
| 553 |
|
} |
| 554 |
|
|
| 555 |
|
#define POPW(ssp, sp, sp_mask, val)\ |
| 556 |
|
{\ |
| 557 |
|
val = lduw_kernel((ssp) + (sp & (sp_mask)));\ |
| 558 |
|
sp += 2;\ |
| 559 |
|
} |
| 560 |
|
|
| 561 |
|
#define POPL(ssp, sp, sp_mask, val)\ |
| 562 |
|
{\ |
| 563 |
|
val = ldl_kernel((ssp) + (sp & (sp_mask)));\ |
| 564 |
|
sp += 4;\ |
| 565 |
|
} |
| 566 |
|
|
| 567 |
/* protected mode interrupt */ |
/* protected mode interrupt */ |
| 568 |
static void do_interrupt_protected(int intno, int is_int, int error_code, |
static void do_interrupt_protected(int intno, int is_int, int error_code, |
| 569 |
unsigned int next_eip, int is_hw) |
unsigned int next_eip, int is_hw) |
| 570 |
{ |
{ |
| 571 |
SegmentCache *dt; |
SegmentCache *dt; |
| 572 |
uint8_t *ptr, *ssp; |
uint8_t *ptr, *ssp; |
| 573 |
int type, dpl, selector, ss_dpl, cpl; |
int type, dpl, selector, ss_dpl, cpl, sp_mask; |
| 574 |
int has_error_code, new_stack, shift; |
int has_error_code, new_stack, shift; |
| 575 |
uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; |
uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2; |
| 576 |
uint32_t old_cs, old_ss, old_esp, old_eip; |
uint32_t old_eip; |
| 577 |
|
|
| 578 |
#ifdef DEBUG_PCALL |
#ifdef DEBUG_PCALL |
| 579 |
if (loglevel) { |
if (loglevel) { |
| 692 |
if (!(ss_e2 & DESC_P_MASK)) |
if (!(ss_e2 & DESC_P_MASK)) |
| 693 |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
| 694 |
new_stack = 1; |
new_stack = 1; |
| 695 |
|
sp_mask = get_sp_mask(ss_e2); |
| 696 |
|
ssp = get_seg_base(ss_e1, ss_e2); |
| 697 |
} else if ((e2 & DESC_C_MASK) || dpl == cpl) { |
} else if ((e2 & DESC_C_MASK) || dpl == cpl) { |
| 698 |
/* to same priviledge */ |
/* to same priviledge */ |
| 699 |
new_stack = 0; |
new_stack = 0; |
| 700 |
|
sp_mask = get_sp_mask(env->segs[R_SS].flags); |
| 701 |
|
ssp = env->segs[R_SS].base; |
| 702 |
|
esp = ESP; |
| 703 |
} else { |
} else { |
| 704 |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
raise_exception_err(EXCP0D_GPF, selector & 0xfffc); |
| 705 |
new_stack = 0; /* avoid warning */ |
new_stack = 0; /* avoid warning */ |
| 706 |
|
sp_mask = 0; /* avoid warning */ |
| 707 |
|
ssp = NULL; /* avoid warning */ |
| 708 |
|
esp = 0; /* avoid warning */ |
| 709 |
} |
} |
| 710 |
|
|
| 711 |
shift = type >> 3; |
shift = type >> 3; |
| 712 |
|
|
| 713 |
|
#if 0 |
| 714 |
|
/* XXX: check that enough room is available */ |
| 715 |
push_size = 6 + (new_stack << 2) + (has_error_code << 1); |
push_size = 6 + (new_stack << 2) + (has_error_code << 1); |
| 716 |
if (env->eflags & VM_MASK) |
if (env->eflags & VM_MASK) |
| 717 |
push_size += 8; |
push_size += 8; |
| 718 |
push_size <<= shift; |
push_size <<= shift; |
| 719 |
|
#endif |
|
/* XXX: check that enough room is available */ |
|
|
if (new_stack) { |
|
|
old_esp = ESP; |
|
|
old_ss = env->segs[R_SS].selector; |
|
|
ss = (ss & ~3) | dpl; |
|
|
cpu_x86_load_seg_cache(env, R_SS, ss, |
|
|
get_seg_base(ss_e1, ss_e2), |
|
|
get_seg_limit(ss_e1, ss_e2), |
|
|
ss_e2); |
|
|
} else { |
|
|
old_esp = 0; |
|
|
old_ss = 0; |
|
|
esp = ESP; |
|
|
} |
|
| 720 |
if (is_int) |
if (is_int) |
| 721 |
old_eip = next_eip; |
old_eip = next_eip; |
| 722 |
else |
else |
| 723 |
old_eip = env->eip; |
old_eip = env->eip; |
|
old_cs = env->segs[R_CS].selector; |
|
|
selector = (selector & ~3) | dpl; |
|
|
cpu_x86_load_seg_cache(env, R_CS, selector, |
|
|
get_seg_base(e1, e2), |
|
|
get_seg_limit(e1, e2), |
|
|
e2); |
|
|
cpu_x86_set_cpl(env, dpl); |
|
|
env->eip = offset; |
|
|
ESP = esp - push_size; |
|
|
ssp = env->segs[R_SS].base + esp; |
|
| 724 |
if (shift == 1) { |
if (shift == 1) { |
|
int old_eflags; |
|
| 725 |
if (env->eflags & VM_MASK) { |
if (env->eflags & VM_MASK) { |
| 726 |
ssp -= 4; |
PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector); |
| 727 |
stl_kernel(ssp, env->segs[R_GS].selector); |
PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector); |
| 728 |
ssp -= 4; |
PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector); |
| 729 |
stl_kernel(ssp, env->segs[R_FS].selector); |
PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector); |
|
ssp -= 4; |
|
|
stl_kernel(ssp, env->segs[R_DS].selector); |
|
|
ssp -= 4; |
|
|
stl_kernel(ssp, env->segs[R_ES].selector); |
|
| 730 |
} |
} |
| 731 |
if (new_stack) { |
if (new_stack) { |
| 732 |
ssp -= 4; |
PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector); |
| 733 |
stl_kernel(ssp, old_ss); |
PUSHL(ssp, esp, sp_mask, ESP); |
| 734 |
ssp -= 4; |
} |
| 735 |
stl_kernel(ssp, old_esp); |
PUSHL(ssp, esp, sp_mask, compute_eflags()); |
| 736 |
} |
PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector); |
| 737 |
ssp -= 4; |
PUSHL(ssp, esp, sp_mask, old_eip); |
|
old_eflags = compute_eflags(); |
|
|
stl_kernel(ssp, old_eflags); |
|
|
ssp -= 4; |
|
|
stl_kernel(ssp, old_cs); |
|
|
ssp -= 4; |
|
|
stl_kernel(ssp, old_eip); |
|
| 738 |
if (has_error_code) { |
if (has_error_code) { |
| 739 |
ssp -= 4; |
PUSHL(ssp, esp, sp_mask, error_code); |
|
stl_kernel(ssp, error_code); |
|
| 740 |
} |
} |
| 741 |
} else { |
} else { |
| 742 |
if (new_stack) { |
if (new_stack) { |
| 743 |
ssp -= 2; |
PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector); |
| 744 |
stw_kernel(ssp, old_ss); |
PUSHW(ssp, esp, sp_mask, ESP); |
| 745 |
ssp -= 2; |
} |
| 746 |
stw_kernel(ssp, old_esp); |
PUSHW(ssp, esp, sp_mask, compute_eflags()); |
| 747 |
} |
PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector); |
| 748 |
ssp -= 2; |
PUSHW(ssp, esp, sp_mask, old_eip); |
|
stw_kernel(ssp, compute_eflags()); |
|
|
ssp -= 2; |
|
|
stw_kernel(ssp, old_cs); |
|
|
ssp -= 2; |
|
|
stw_kernel(ssp, old_eip); |
|
| 749 |
if (has_error_code) { |
if (has_error_code) { |
| 750 |
ssp -= 2; |
PUSHW(ssp, esp, sp_mask, error_code); |
|
stw_kernel(ssp, error_code); |
|
| 751 |
} |
} |
| 752 |
} |
} |
| 753 |
|
|
| 754 |
|
if (new_stack) { |
| 755 |
|
ss = (ss & ~3) | dpl; |
| 756 |
|
cpu_x86_load_seg_cache(env, R_SS, ss, |
| 757 |
|
ssp, get_seg_limit(ss_e1, ss_e2), ss_e2); |
| 758 |
|
} |
| 759 |
|
ESP = (ESP & ~sp_mask) | (esp & sp_mask); |
| 760 |
|
|
| 761 |
|
selector = (selector & ~3) | dpl; |
| 762 |
|
cpu_x86_load_seg_cache(env, R_CS, selector, |
| 763 |
|
get_seg_base(e1, e2), |
| 764 |
|
get_seg_limit(e1, e2), |
| 765 |
|
e2); |
| 766 |
|
cpu_x86_set_cpl(env, dpl); |
| 767 |
|
env->eip = offset; |
| 768 |
|
|
| 769 |
/* interrupt gate clear IF mask */ |
/* interrupt gate clear IF mask */ |
| 770 |
if ((type & 1) == 0) { |
if ((type & 1) == 0) { |
| 771 |
env->eflags &= ~IF_MASK; |
env->eflags &= ~IF_MASK; |
| 797 |
else |
else |
| 798 |
old_eip = env->eip; |
old_eip = env->eip; |
| 799 |
old_cs = env->segs[R_CS].selector; |
old_cs = env->segs[R_CS].selector; |
| 800 |
esp -= 2; |
/* XXX: use SS segment size ? */ |
| 801 |
stw_kernel(ssp + (esp & 0xffff), compute_eflags()); |
PUSHW(ssp, esp, 0xffff, compute_eflags()); |
| 802 |
esp -= 2; |
PUSHW(ssp, esp, 0xffff, old_cs); |
| 803 |
stw_kernel(ssp + (esp & 0xffff), old_cs); |
PUSHW(ssp, esp, 0xffff, old_eip); |
|
esp -= 2; |
|
|
stw_kernel(ssp + (esp & 0xffff), old_eip); |
|
| 804 |
|
|
| 805 |
/* update processor state */ |
/* update processor state */ |
| 806 |
ESP = (ESP & ~0xffff) | (esp & 0xffff); |
ESP = (ESP & ~0xffff) | (esp & 0xffff); |
| 1262 |
new_cs = T0; |
new_cs = T0; |
| 1263 |
new_eip = T1; |
new_eip = T1; |
| 1264 |
esp = ESP; |
esp = ESP; |
| 1265 |
esp_mask = 0xffffffff; |
esp_mask = get_sp_mask(env->segs[R_SS].flags); |
|
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
|
|
esp_mask = 0xffff; |
|
| 1266 |
ssp = env->segs[R_SS].base; |
ssp = env->segs[R_SS].base; |
| 1267 |
if (shift) { |
if (shift) { |
| 1268 |
esp -= 4; |
PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector); |
| 1269 |
stl_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector); |
PUSHL(ssp, esp, esp_mask, next_eip); |
|
esp -= 4; |
|
|
stl_kernel(ssp + (esp & esp_mask), next_eip); |
|
| 1270 |
} else { |
} else { |
| 1271 |
esp -= 2; |
PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector); |
| 1272 |
stw_kernel(ssp + (esp & esp_mask), env->segs[R_CS].selector); |
PUSHW(ssp, esp, esp_mask, next_eip); |
|
esp -= 2; |
|
|
stw_kernel(ssp + (esp & esp_mask), next_eip); |
|
| 1273 |
} |
} |
| 1274 |
|
|
| 1275 |
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
ESP = (ESP & ~esp_mask) | (esp & esp_mask); |
|
ESP = (ESP & ~0xffff) | (esp & 0xffff); |
|
|
else |
|
|
ESP = esp; |
|
| 1276 |
env->eip = new_eip; |
env->eip = new_eip; |
| 1277 |
env->segs[R_CS].selector = new_cs; |
env->segs[R_CS].selector = new_cs; |
| 1278 |
env->segs[R_CS].base = (uint8_t *)(new_cs << 4); |
env->segs[R_CS].base = (uint8_t *)(new_cs << 4); |
| 1281 |
/* protected mode call */ |
/* protected mode call */ |
| 1282 |
void helper_lcall_protected_T0_T1(int shift, int next_eip) |
void helper_lcall_protected_T0_T1(int shift, int next_eip) |
| 1283 |
{ |
{ |
| 1284 |
int new_cs, new_eip; |
int new_cs, new_eip, new_stack, i; |
| 1285 |
uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; |
uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; |
| 1286 |
uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; |
uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; |
| 1287 |
uint32_t old_ss, old_esp, val, i, limit; |
uint32_t val, limit, old_sp_mask; |
| 1288 |
uint8_t *ssp, *old_ssp; |
uint8_t *ssp, *old_ssp; |
| 1289 |
|
|
| 1290 |
new_cs = T0; |
new_cs = T0; |
| 1325 |
raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); |
raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); |
| 1326 |
|
|
| 1327 |
sp = ESP; |
sp = ESP; |
| 1328 |
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
sp_mask = get_sp_mask(env->segs[R_SS].flags); |
| 1329 |
sp &= 0xffff; |
ssp = env->segs[R_SS].base; |
|
ssp = env->segs[R_SS].base + sp; |
|
| 1330 |
if (shift) { |
if (shift) { |
| 1331 |
ssp -= 4; |
PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); |
| 1332 |
stl_kernel(ssp, env->segs[R_CS].selector); |
PUSHL(ssp, sp, sp_mask, next_eip); |
|
ssp -= 4; |
|
|
stl_kernel(ssp, next_eip); |
|
| 1333 |
} else { |
} else { |
| 1334 |
ssp -= 2; |
PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); |
| 1335 |
stw_kernel(ssp, env->segs[R_CS].selector); |
PUSHW(ssp, sp, sp_mask, next_eip); |
|
ssp -= 2; |
|
|
stw_kernel(ssp, next_eip); |
|
| 1336 |
} |
} |
|
sp -= (4 << shift); |
|
| 1337 |
|
|
| 1338 |
limit = get_seg_limit(e1, e2); |
limit = get_seg_limit(e1, e2); |
| 1339 |
if (new_eip > limit) |
if (new_eip > limit) |
| 1340 |
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
| 1341 |
/* from this point, not restartable */ |
/* from this point, not restartable */ |
| 1342 |
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
ESP = (ESP & ~sp_mask) | (sp & sp_mask); |
|
ESP = (ESP & 0xffff0000) | (sp & 0xffff); |
|
|
else |
|
|
ESP = sp; |
|
| 1343 |
cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, |
cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, |
| 1344 |
get_seg_base(e1, e2), limit, e2); |
get_seg_base(e1, e2), limit, e2); |
| 1345 |
EIP = new_eip; |
EIP = new_eip; |
| 1410 |
if (!(ss_e2 & DESC_P_MASK)) |
if (!(ss_e2 & DESC_P_MASK)) |
| 1411 |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
raise_exception_err(EXCP0A_TSS, ss & 0xfffc); |
| 1412 |
|
|
| 1413 |
push_size = ((param_count * 2) + 8) << shift; |
// push_size = ((param_count * 2) + 8) << shift; |
| 1414 |
|
|
| 1415 |
old_esp = ESP; |
old_sp_mask = get_sp_mask(env->segs[R_SS].flags); |
| 1416 |
old_ss = env->segs[R_SS].selector; |
old_ssp = env->segs[R_SS].base; |
|
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
|
|
old_esp &= 0xffff; |
|
|
old_ssp = env->segs[R_SS].base + old_esp; |
|
| 1417 |
|
|
| 1418 |
/* XXX: from this point not restartable */ |
sp_mask = get_sp_mask(ss_e2); |
| 1419 |
ss = (ss & ~3) | dpl; |
ssp = get_seg_base(ss_e1, ss_e2); |
|
cpu_x86_load_seg_cache(env, R_SS, ss, |
|
|
get_seg_base(ss_e1, ss_e2), |
|
|
get_seg_limit(ss_e1, ss_e2), |
|
|
ss_e2); |
|
|
|
|
|
if (!(ss_e2 & DESC_B_MASK)) |
|
|
sp &= 0xffff; |
|
|
ssp = env->segs[R_SS].base + sp; |
|
| 1420 |
if (shift) { |
if (shift) { |
| 1421 |
ssp -= 4; |
PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector); |
| 1422 |
stl_kernel(ssp, old_ss); |
PUSHL(ssp, sp, sp_mask, ESP); |
| 1423 |
ssp -= 4; |
for(i = param_count - 1; i >= 0; i--) { |
| 1424 |
stl_kernel(ssp, old_esp); |
val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask)); |
| 1425 |
ssp -= 4 * param_count; |
PUSHL(ssp, sp, sp_mask, val); |
|
for(i = 0; i < param_count; i++) { |
|
|
val = ldl_kernel(old_ssp + i * 4); |
|
|
stl_kernel(ssp + i * 4, val); |
|
| 1426 |
} |
} |
| 1427 |
} else { |
} else { |
| 1428 |
ssp -= 2; |
PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector); |
| 1429 |
stw_kernel(ssp, old_ss); |
PUSHW(ssp, sp, sp_mask, ESP); |
| 1430 |
ssp -= 2; |
for(i = param_count - 1; i >= 0; i--) { |
| 1431 |
stw_kernel(ssp, old_esp); |
val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask)); |
| 1432 |
ssp -= 2 * param_count; |
PUSHW(ssp, sp, sp_mask, val); |
|
for(i = 0; i < param_count; i++) { |
|
|
val = lduw_kernel(old_ssp + i * 2); |
|
|
stw_kernel(ssp + i * 2, val); |
|
| 1433 |
} |
} |
| 1434 |
} |
} |
| 1435 |
|
new_stack = 1; |
| 1436 |
} else { |
} else { |
| 1437 |
/* to same priviledge */ |
/* to same priviledge */ |
| 1438 |
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
sp = ESP; |
| 1439 |
sp &= 0xffff; |
sp_mask = get_sp_mask(env->segs[R_SS].flags); |
| 1440 |
ssp = env->segs[R_SS].base + sp; |
ssp = env->segs[R_SS].base; |
| 1441 |
push_size = (4 << shift); |
// push_size = (4 << shift); |
| 1442 |
|
new_stack = 0; |
| 1443 |
} |
} |
| 1444 |
|
|
| 1445 |
if (shift) { |
if (shift) { |
| 1446 |
ssp -= 4; |
PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); |
| 1447 |
stl_kernel(ssp, env->segs[R_CS].selector); |
PUSHL(ssp, sp, sp_mask, next_eip); |
|
ssp -= 4; |
|
|
stl_kernel(ssp, next_eip); |
|
| 1448 |
} else { |
} else { |
| 1449 |
ssp -= 2; |
PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); |
| 1450 |
stw_kernel(ssp, env->segs[R_CS].selector); |
PUSHW(ssp, sp, sp_mask, next_eip); |
| 1451 |
ssp -= 2; |
} |
| 1452 |
stw_kernel(ssp, next_eip); |
|
| 1453 |
|
/* from this point, not restartable */ |
| 1454 |
|
|
| 1455 |
|
if (new_stack) { |
| 1456 |
|
ss = (ss & ~3) | dpl; |
| 1457 |
|
cpu_x86_load_seg_cache(env, R_SS, ss, |
| 1458 |
|
ssp, |
| 1459 |
|
get_seg_limit(ss_e1, ss_e2), |
| 1460 |
|
ss_e2); |
| 1461 |
} |
} |
| 1462 |
|
|
|
sp -= push_size; |
|
| 1463 |
selector = (selector & ~3) | dpl; |
selector = (selector & ~3) | dpl; |
| 1464 |
cpu_x86_load_seg_cache(env, R_CS, selector, |
cpu_x86_load_seg_cache(env, R_CS, selector, |
| 1465 |
get_seg_base(e1, e2), |
get_seg_base(e1, e2), |
| 1466 |
get_seg_limit(e1, e2), |
get_seg_limit(e1, e2), |
| 1467 |
e2); |
e2); |
| 1468 |
cpu_x86_set_cpl(env, dpl); |
cpu_x86_set_cpl(env, dpl); |
| 1469 |
|
ESP = (ESP & ~sp_mask) | (sp & sp_mask); |
|
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
|
|
ESP = (ESP & 0xffff0000) | (sp & 0xffff); |
|
|
else |
|
|
ESP = sp; |
|
| 1470 |
EIP = offset; |
EIP = offset; |
| 1471 |
} |
} |
| 1472 |
} |
} |
| 1474 |
/* real and vm86 mode iret */ |
/* real and vm86 mode iret */ |
| 1475 |
void helper_iret_real(int shift) |
void helper_iret_real(int shift) |
| 1476 |
{ |
{ |
| 1477 |
uint32_t sp, new_cs, new_eip, new_eflags, new_esp; |
uint32_t sp, new_cs, new_eip, new_eflags, sp_mask; |
| 1478 |
uint8_t *ssp; |
uint8_t *ssp; |
| 1479 |
int eflags_mask; |
int eflags_mask; |
| 1480 |
|
|
| 1481 |
sp = ESP & 0xffff; |
sp_mask = 0xffff; /* XXXX: use SS segment size ? */ |
| 1482 |
ssp = env->segs[R_SS].base + sp; |
sp = ESP; |
| 1483 |
|
ssp = env->segs[R_SS].base; |
| 1484 |
if (shift == 1) { |
if (shift == 1) { |
| 1485 |
/* 32 bits */ |
/* 32 bits */ |
| 1486 |
new_eflags = ldl_kernel(ssp + 8); |
POPL(ssp, sp, sp_mask, new_eip); |
| 1487 |
new_cs = ldl_kernel(ssp + 4) & 0xffff; |
POPL(ssp, sp, sp_mask, new_cs); |
| 1488 |
new_eip = ldl_kernel(ssp) & 0xffff; |
new_cs &= 0xffff; |
| 1489 |
|
POPL(ssp, sp, sp_mask, new_eflags); |
| 1490 |
} else { |
} else { |
| 1491 |
/* 16 bits */ |
/* 16 bits */ |
| 1492 |
new_eflags = lduw_kernel(ssp + 4); |
POPW(ssp, sp, sp_mask, new_eip); |
| 1493 |
new_cs = lduw_kernel(ssp + 2); |
POPW(ssp, sp, sp_mask, new_cs); |
| 1494 |
new_eip = lduw_kernel(ssp); |
POPW(ssp, sp, sp_mask, new_eflags); |
| 1495 |
} |
} |
| 1496 |
new_esp = sp + (6 << shift); |
ESP = (ESP & ~sp_mask) | (sp & 0xffff); |
|
ESP = (ESP & 0xffff0000) | |
|
|
(new_esp & 0xffff); |
|
| 1497 |
load_seg_vm(R_CS, new_cs); |
load_seg_vm(R_CS, new_cs); |
| 1498 |
env->eip = new_eip; |
env->eip = new_eip; |
| 1499 |
if (env->eflags & VM_MASK) |
if (env->eflags & VM_MASK) |
| 1508 |
/* protected mode iret */ |
/* protected mode iret */ |
| 1509 |
static inline void helper_ret_protected(int shift, int is_iret, int addend) |
static inline void helper_ret_protected(int shift, int is_iret, int addend) |
| 1510 |
{ |
{ |
| 1511 |
uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; |
uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss, sp_mask; |
| 1512 |
uint32_t new_es, new_ds, new_fs, new_gs; |
uint32_t new_es, new_ds, new_fs, new_gs; |
| 1513 |
uint32_t e1, e2, ss_e1, ss_e2; |
uint32_t e1, e2, ss_e1, ss_e2; |
| 1514 |
int cpl, dpl, rpl, eflags_mask; |
int cpl, dpl, rpl, eflags_mask; |
| 1515 |
uint8_t *ssp; |
uint8_t *ssp; |
| 1516 |
|
|
| 1517 |
|
sp_mask = get_sp_mask(env->segs[R_SS].flags); |
| 1518 |
sp = ESP; |
sp = ESP; |
| 1519 |
if (!(env->segs[R_SS].flags & DESC_B_MASK)) |
ssp = env->segs[R_SS].base; |
|
sp &= 0xffff; |
|
|
ssp = env->segs[R_SS].base + sp; |
|
| 1520 |
if (shift == 1) { |
if (shift == 1) { |
| 1521 |
/* 32 bits */ |
/* 32 bits */ |
| 1522 |
if (is_iret) |
POPL(ssp, sp, sp_mask, new_eip); |
| 1523 |
new_eflags = ldl_kernel(ssp + 8); |
POPL(ssp, sp, sp_mask, new_cs); |
| 1524 |
new_cs = ldl_kernel(ssp + 4) & 0xffff; |
new_cs &= 0xffff; |
| 1525 |
new_eip = ldl_kernel(ssp); |
if (is_iret) { |
| 1526 |
if (is_iret && (new_eflags & VM_MASK)) |
POPL(ssp, sp, sp_mask, new_eflags); |
| 1527 |
goto return_to_vm86; |
if (new_eflags & VM_MASK) |
| 1528 |
|
goto return_to_vm86; |
| 1529 |
|
} |
| 1530 |
} else { |
} else { |
| 1531 |
/* 16 bits */ |
/* 16 bits */ |
| 1532 |
|
POPW(ssp, sp, sp_mask, new_eip); |
| 1533 |
|
POPW(ssp, sp, sp_mask, new_cs); |
| 1534 |
if (is_iret) |
if (is_iret) |
| 1535 |
new_eflags = lduw_kernel(ssp + 4); |
POPW(ssp, sp, sp_mask, new_eflags); |
|
new_cs = lduw_kernel(ssp + 2); |
|
|
new_eip = lduw_kernel(ssp); |
|
| 1536 |
} |
} |
| 1537 |
|
#ifdef DEBUG_PCALL |
| 1538 |
|
if (loglevel) { |
| 1539 |
|
fprintf(logfile, "lret new %04x:%08x\n", |
| 1540 |
|
new_cs, new_eip); |
| 1541 |
|
} |
| 1542 |
|
#endif |
| 1543 |
if ((new_cs & 0xfffc) == 0) |
if ((new_cs & 0xfffc) == 0) |
| 1544 |
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
| 1545 |
if (load_segment(&e1, &e2, new_cs) != 0) |
if (load_segment(&e1, &e2, new_cs) != 0) |
| 1562 |
if (!(e2 & DESC_P_MASK)) |
if (!(e2 & DESC_P_MASK)) |
| 1563 |
raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); |
raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); |
| 1564 |
|
|
| 1565 |
|
sp += addend; |
| 1566 |
if (rpl == cpl) { |
if (rpl == cpl) { |
| 1567 |
/* return to same priledge level */ |
/* return to same priledge level */ |
| 1568 |
cpu_x86_load_seg_cache(env, R_CS, new_cs, |
cpu_x86_load_seg_cache(env, R_CS, new_cs, |
| 1569 |
get_seg_base(e1, e2), |
get_seg_base(e1, e2), |
| 1570 |
get_seg_limit(e1, e2), |
get_seg_limit(e1, e2), |
| 1571 |
e2); |
e2); |
|
new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; |
|
| 1572 |
} else { |
} else { |
| 1573 |
/* return to different priviledge level */ |
/* return to different priviledge level */ |
|
ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; |
|
| 1574 |
if (shift == 1) { |
if (shift == 1) { |
| 1575 |
/* 32 bits */ |
/* 32 bits */ |
| 1576 |
new_esp = ldl_kernel(ssp); |
POPL(ssp, sp, sp_mask, new_esp); |
| 1577 |
new_ss = ldl_kernel(ssp + 4) & 0xffff; |
POPL(ssp, sp, sp_mask, new_ss); |
| 1578 |
|
new_ss &= 0xffff; |
| 1579 |
} else { |
} else { |
| 1580 |
/* 16 bits */ |
/* 16 bits */ |
| 1581 |
new_esp = lduw_kernel(ssp); |
POPW(ssp, sp, sp_mask, new_esp); |
| 1582 |
new_ss = lduw_kernel(ssp + 2); |
POPW(ssp, sp, sp_mask, new_ss); |
| 1583 |
} |
} |
| 1584 |
|
|
| 1585 |
if ((new_ss & 3) != rpl) |
if ((new_ss & 3) != rpl) |
| 1605 |
get_seg_limit(ss_e1, ss_e2), |
get_seg_limit(ss_e1, ss_e2), |
| 1606 |
ss_e2); |
ss_e2); |
| 1607 |
cpu_x86_set_cpl(env, rpl); |
cpu_x86_set_cpl(env, rpl); |
| 1608 |
|
sp = new_esp; |
| 1609 |
|
/* XXX: change sp_mask according to old segment ? */ |
| 1610 |
} |
} |
| 1611 |
if (env->segs[R_SS].flags & DESC_B_MASK) |
ESP = (ESP & ~sp_mask) | (sp & sp_mask); |
|
ESP = new_esp; |
|
|
else |
|
|
ESP = (ESP & 0xffff0000) | |
|
|
(new_esp & 0xffff); |
|
| 1612 |
env->eip = new_eip; |
env->eip = new_eip; |
| 1613 |
if (is_iret) { |
if (is_iret) { |
| 1614 |
/* NOTE: 'cpl' can be different from the current CPL */ |
/* NOTE: 'cpl' can be different from the current CPL */ |
| 1623 |
return; |
return; |
| 1624 |
|
|
| 1625 |
return_to_vm86: |
return_to_vm86: |
| 1626 |
new_esp = ldl_kernel(ssp + 12); |
POPL(ssp, sp, sp_mask, new_esp); |
| 1627 |
new_ss = ldl_kernel(ssp + 16); |
POPL(ssp, sp, sp_mask, new_ss); |
| 1628 |
new_es = ldl_kernel(ssp + 20); |
POPL(ssp, sp, sp_mask, new_es); |
| 1629 |
new_ds = ldl_kernel(ssp + 24); |
POPL(ssp, sp, sp_mask, new_ds); |
| 1630 |
new_fs = ldl_kernel(ssp + 28); |
POPL(ssp, sp, sp_mask, new_fs); |
| 1631 |
new_gs = ldl_kernel(ssp + 32); |
POPL(ssp, sp, sp_mask, new_gs); |
| 1632 |
|
|
| 1633 |
/* modify processor state */ |
/* modify processor state */ |
| 1634 |
load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); |
load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); |
| 1635 |
load_seg_vm(R_CS, new_cs); |
load_seg_vm(R_CS, new_cs & 0xffff); |
| 1636 |
cpu_x86_set_cpl(env, 3); |
cpu_x86_set_cpl(env, 3); |
| 1637 |
load_seg_vm(R_SS, new_ss); |
load_seg_vm(R_SS, new_ss & 0xffff); |
| 1638 |
load_seg_vm(R_ES, new_es); |
load_seg_vm(R_ES, new_es & 0xffff); |
| 1639 |
load_seg_vm(R_DS, new_ds); |
load_seg_vm(R_DS, new_ds & 0xffff); |
| 1640 |
load_seg_vm(R_FS, new_fs); |
load_seg_vm(R_FS, new_fs & 0xffff); |
| 1641 |
load_seg_vm(R_GS, new_gs); |
load_seg_vm(R_GS, new_gs & 0xffff); |
| 1642 |
|
|
| 1643 |
env->eip = new_eip; |
env->eip = new_eip; |
| 1644 |
ESP = new_esp; |
ESP = new_esp; |