Commit f419b32104ef9da81b52143cc10e90f235c2441a
1 parent
8d9bfc2b
sysret fix - better cpuid support - lcall support for x86_64 - efer access in i386 emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1373 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
110 additions
and
39 deletions
target-i386/helper.c
| ... | ... | @@ -933,6 +933,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, |
| 933 | 933 | } |
| 934 | 934 | env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); |
| 935 | 935 | } |
| 936 | +#endif | |
| 936 | 937 | |
| 937 | 938 | void helper_syscall(int next_eip_addend) |
| 938 | 939 | { |
| ... | ... | @@ -942,6 +943,7 @@ void helper_syscall(int next_eip_addend) |
| 942 | 943 | raise_exception_err(EXCP06_ILLOP, 0); |
| 943 | 944 | } |
| 944 | 945 | selector = (env->star >> 32) & 0xffff; |
| 946 | +#ifdef TARGET_X86_64 | |
| 945 | 947 | if (env->hflags & HF_LMA_MASK) { |
| 946 | 948 | ECX = env->eip + next_eip_addend; |
| 947 | 949 | env->regs[11] = compute_eflags(); |
| ... | ... | @@ -962,7 +964,9 @@ void helper_syscall(int next_eip_addend) |
| 962 | 964 | env->eip = env->lstar; |
| 963 | 965 | else |
| 964 | 966 | env->eip = env->cstar; |
| 965 | - } else { | |
| 967 | + } else | |
| 968 | +#endif | |
| 969 | + { | |
| 966 | 970 | ECX = (uint32_t)(env->eip + next_eip_addend); |
| 967 | 971 | |
| 968 | 972 | cpu_x86_set_cpl(env, 0); |
| ... | ... | @@ -985,11 +989,15 @@ void helper_sysret(int dflag) |
| 985 | 989 | { |
| 986 | 990 | int cpl, selector; |
| 987 | 991 | |
| 992 | + if (!(env->efer & MSR_EFER_SCE)) { | |
| 993 | + raise_exception_err(EXCP06_ILLOP, 0); | |
| 994 | + } | |
| 988 | 995 | cpl = env->hflags & HF_CPL_MASK; |
| 989 | 996 | if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { |
| 990 | 997 | raise_exception_err(EXCP0D_GPF, 0); |
| 991 | 998 | } |
| 992 | 999 | selector = (env->star >> 48) & 0xffff; |
| 1000 | +#ifdef TARGET_X86_64 | |
| 993 | 1001 | if (env->hflags & HF_LMA_MASK) { |
| 994 | 1002 | if (dflag == 2) { |
| 995 | 1003 | cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, |
| ... | ... | @@ -1015,7 +1023,9 @@ void helper_sysret(int dflag) |
| 1015 | 1023 | load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | |
| 1016 | 1024 | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); |
| 1017 | 1025 | cpu_x86_set_cpl(env, 3); |
| 1018 | - } else { | |
| 1026 | + } else | |
| 1027 | +#endif | |
| 1028 | + { | |
| 1019 | 1029 | cpu_x86_load_seg_cache(env, R_CS, selector | 3, |
| 1020 | 1030 | 0, 0xffffffff, |
| 1021 | 1031 | DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
| ... | ... | @@ -1030,8 +1040,15 @@ void helper_sysret(int dflag) |
| 1030 | 1040 | env->eflags |= IF_MASK; |
| 1031 | 1041 | cpu_x86_set_cpl(env, 3); |
| 1032 | 1042 | } |
| 1033 | -} | |
| 1043 | +#ifdef USE_KQEMU | |
| 1044 | + if (kqemu_is_ok(env)) { | |
| 1045 | + if (env->hflags & HF_LMA_MASK) | |
| 1046 | + CC_OP = CC_OP_EFLAGS; | |
| 1047 | + env->exception_index = -1; | |
| 1048 | + cpu_loop_exit(); | |
| 1049 | + } | |
| 1034 | 1050 | #endif |
| 1051 | +} | |
| 1035 | 1052 | |
| 1036 | 1053 | /* real mode interrupt */ |
| 1037 | 1054 | static void do_interrupt_real(int intno, int is_int, int error_code, |
| ... | ... | @@ -1265,9 +1282,21 @@ void helper_cmpxchg8b(void) |
| 1265 | 1282 | |
| 1266 | 1283 | void helper_cpuid(void) |
| 1267 | 1284 | { |
| 1268 | - switch((uint32_t)EAX) { | |
| 1285 | + uint32_t index; | |
| 1286 | + index = (uint32_t)EAX; | |
| 1287 | + | |
| 1288 | + /* test if maximum index reached */ | |
| 1289 | + if (index & 0x80000000) { | |
| 1290 | + if (index > env->cpuid_xlevel) | |
| 1291 | + index = env->cpuid_level; | |
| 1292 | + } else { | |
| 1293 | + if (index > env->cpuid_level) | |
| 1294 | + index = env->cpuid_level; | |
| 1295 | + } | |
| 1296 | + | |
| 1297 | + switch(index) { | |
| 1269 | 1298 | case 0: |
| 1270 | - EAX = 2; /* max EAX index supported */ | |
| 1299 | + EAX = env->cpuid_level; | |
| 1271 | 1300 | EBX = env->cpuid_vendor1; |
| 1272 | 1301 | EDX = env->cpuid_vendor2; |
| 1273 | 1302 | ECX = env->cpuid_vendor3; |
| ... | ... | @@ -1278,16 +1307,15 @@ void helper_cpuid(void) |
| 1278 | 1307 | ECX = env->cpuid_ext_features; |
| 1279 | 1308 | EDX = env->cpuid_features; |
| 1280 | 1309 | break; |
| 1281 | - default: | |
| 1310 | + case 2: | |
| 1282 | 1311 | /* cache info: needed for Pentium Pro compatibility */ |
| 1283 | 1312 | EAX = 0x410601; |
| 1284 | 1313 | EBX = 0; |
| 1285 | 1314 | ECX = 0; |
| 1286 | 1315 | EDX = 0; |
| 1287 | 1316 | break; |
| 1288 | -#ifdef TARGET_X86_64 | |
| 1289 | 1317 | case 0x80000000: |
| 1290 | - EAX = 0x80000008; | |
| 1318 | + EAX = env->cpuid_xlevel; | |
| 1291 | 1319 | EBX = env->cpuid_vendor1; |
| 1292 | 1320 | EDX = env->cpuid_vendor2; |
| 1293 | 1321 | ECX = env->cpuid_vendor3; |
| ... | ... | @@ -1296,8 +1324,15 @@ void helper_cpuid(void) |
| 1296 | 1324 | EAX = env->cpuid_features; |
| 1297 | 1325 | EBX = 0; |
| 1298 | 1326 | ECX = 0; |
| 1299 | - /* long mode + syscall/sysret features */ | |
| 1300 | - EDX = (env->cpuid_features & 0x0183F3FF) | (1 << 29) | (1 << 11); | |
| 1327 | + EDX = env->cpuid_ext2_features; | |
| 1328 | + break; | |
| 1329 | + case 0x80000002: | |
| 1330 | + case 0x80000003: | |
| 1331 | + case 0x80000004: | |
| 1332 | + EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0]; | |
| 1333 | + EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1]; | |
| 1334 | + ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2]; | |
| 1335 | + EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3]; | |
| 1301 | 1336 | break; |
| 1302 | 1337 | case 0x80000008: |
| 1303 | 1338 | /* virtual & phys address size in low 2 bytes. */ |
| ... | ... | @@ -1306,7 +1341,13 @@ void helper_cpuid(void) |
| 1306 | 1341 | ECX = 0; |
| 1307 | 1342 | EDX = 0; |
| 1308 | 1343 | break; |
| 1309 | -#endif | |
| 1344 | + default: | |
| 1345 | + /* reserved values: zero */ | |
| 1346 | + EAX = 0; | |
| 1347 | + EBX = 0; | |
| 1348 | + ECX = 0; | |
| 1349 | + EDX = 0; | |
| 1350 | + break; | |
| 1310 | 1351 | } |
| 1311 | 1352 | } |
| 1312 | 1353 | |
| ... | ... | @@ -1523,11 +1564,11 @@ void load_seg(int seg_reg, int selector) |
| 1523 | 1564 | } |
| 1524 | 1565 | |
| 1525 | 1566 | /* protected mode jump */ |
| 1526 | -void helper_ljmp_protected_T0_T1(int next_eip) | |
| 1567 | +void helper_ljmp_protected_T0_T1(int next_eip_addend) | |
| 1527 | 1568 | { |
| 1528 | 1569 | int new_cs, gate_cs, type; |
| 1529 | 1570 | uint32_t e1, e2, cpl, dpl, rpl, limit; |
| 1530 | - target_ulong new_eip; | |
| 1571 | + target_ulong new_eip, next_eip; | |
| 1531 | 1572 | |
| 1532 | 1573 | new_cs = T0; |
| 1533 | 1574 | new_eip = T1; |
| ... | ... | @@ -1573,6 +1614,7 @@ void helper_ljmp_protected_T0_T1(int next_eip) |
| 1573 | 1614 | case 5: /* task gate */ |
| 1574 | 1615 | if (dpl < cpl || dpl < rpl) |
| 1575 | 1616 | raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
| 1617 | + next_eip = env->eip + next_eip_addend; | |
| 1576 | 1618 | switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); |
| 1577 | 1619 | break; |
| 1578 | 1620 | case 4: /* 286 call gate */ |
| ... | ... | @@ -1638,16 +1680,17 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) |
| 1638 | 1680 | } |
| 1639 | 1681 | |
| 1640 | 1682 | /* protected mode call */ |
| 1641 | -void helper_lcall_protected_T0_T1(int shift, int next_eip) | |
| 1683 | +void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) | |
| 1642 | 1684 | { |
| 1643 | 1685 | int new_cs, new_eip, new_stack, i; |
| 1644 | 1686 | uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; |
| 1645 | 1687 | uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; |
| 1646 | 1688 | uint32_t val, limit, old_sp_mask; |
| 1647 | - target_ulong ssp, old_ssp; | |
| 1689 | + target_ulong ssp, old_ssp, next_eip; | |
| 1648 | 1690 | |
| 1649 | 1691 | new_cs = T0; |
| 1650 | 1692 | new_eip = T1; |
| 1693 | + next_eip = env->eip + next_eip_addend; | |
| 1651 | 1694 | #ifdef DEBUG_PCALL |
| 1652 | 1695 | if (loglevel & CPU_LOG_PCALL) { |
| 1653 | 1696 | fprintf(logfile, "lcall %04x:%08x s=%d\n", |
| ... | ... | @@ -1684,25 +1727,43 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) |
| 1684 | 1727 | if (!(e2 & DESC_P_MASK)) |
| 1685 | 1728 | raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); |
| 1686 | 1729 | |
| 1687 | - sp = ESP; | |
| 1688 | - sp_mask = get_sp_mask(env->segs[R_SS].flags); | |
| 1689 | - ssp = env->segs[R_SS].base; | |
| 1690 | - if (shift) { | |
| 1691 | - PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); | |
| 1692 | - PUSHL(ssp, sp, sp_mask, next_eip); | |
| 1693 | - } else { | |
| 1694 | - PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); | |
| 1695 | - PUSHW(ssp, sp, sp_mask, next_eip); | |
| 1730 | +#ifdef TARGET_X86_64 | |
| 1731 | + /* XXX: check 16/32 bit cases in long mode */ | |
| 1732 | + if (shift == 2) { | |
| 1733 | + target_ulong rsp; | |
| 1734 | + /* 64 bit case */ | |
| 1735 | + rsp = ESP; | |
| 1736 | + PUSHQ(rsp, env->segs[R_CS].selector); | |
| 1737 | + PUSHQ(rsp, next_eip); | |
| 1738 | + /* from this point, not restartable */ | |
| 1739 | + ESP = rsp; | |
| 1740 | + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, | |
| 1741 | + get_seg_base(e1, e2), | |
| 1742 | + get_seg_limit(e1, e2), e2); | |
| 1743 | + EIP = new_eip; | |
| 1744 | + } else | |
| 1745 | +#endif | |
| 1746 | + { | |
| 1747 | + sp = ESP; | |
| 1748 | + sp_mask = get_sp_mask(env->segs[R_SS].flags); | |
| 1749 | + ssp = env->segs[R_SS].base; | |
| 1750 | + if (shift) { | |
| 1751 | + PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector); | |
| 1752 | + PUSHL(ssp, sp, sp_mask, next_eip); | |
| 1753 | + } else { | |
| 1754 | + PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector); | |
| 1755 | + PUSHW(ssp, sp, sp_mask, next_eip); | |
| 1756 | + } | |
| 1757 | + | |
| 1758 | + limit = get_seg_limit(e1, e2); | |
| 1759 | + if (new_eip > limit) | |
| 1760 | + raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 1761 | + /* from this point, not restartable */ | |
| 1762 | + ESP = (ESP & ~sp_mask) | (sp & sp_mask); | |
| 1763 | + cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, | |
| 1764 | + get_seg_base(e1, e2), limit, e2); | |
| 1765 | + EIP = new_eip; | |
| 1696 | 1766 | } |
| 1697 | - | |
| 1698 | - limit = get_seg_limit(e1, e2); | |
| 1699 | - if (new_eip > limit) | |
| 1700 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 1701 | - /* from this point, not restartable */ | |
| 1702 | - ESP = (ESP & ~sp_mask) | (sp & sp_mask); | |
| 1703 | - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, | |
| 1704 | - get_seg_base(e1, e2), limit, e2); | |
| 1705 | - EIP = new_eip; | |
| 1706 | 1767 | } else { |
| 1707 | 1768 | /* check gate type */ |
| 1708 | 1769 | type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
| ... | ... | @@ -2245,16 +2306,26 @@ void helper_wrmsr(void) |
| 2245 | 2306 | case MSR_IA32_APICBASE: |
| 2246 | 2307 | cpu_set_apic_base(env, val); |
| 2247 | 2308 | break; |
| 2248 | -#ifdef TARGET_X86_64 | |
| 2249 | 2309 | case MSR_EFER: |
| 2250 | -#define MSR_EFER_UPDATE_MASK (MSR_EFER_SCE | MSR_EFER_LME | \ | |
| 2251 | - MSR_EFER_NXE | MSR_EFER_FFXSR) | |
| 2252 | - env->efer = (env->efer & ~MSR_EFER_UPDATE_MASK) | | |
| 2253 | - (val & MSR_EFER_UPDATE_MASK); | |
| 2310 | + { | |
| 2311 | + uint64_t update_mask; | |
| 2312 | + update_mask = 0; | |
| 2313 | + if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) | |
| 2314 | + update_mask |= MSR_EFER_SCE; | |
| 2315 | + if (env->cpuid_ext2_features & CPUID_EXT2_LM) | |
| 2316 | + update_mask |= MSR_EFER_LME; | |
| 2317 | + if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) | |
| 2318 | + update_mask |= MSR_EFER_FFXSR; | |
| 2319 | + if (env->cpuid_ext2_features & CPUID_EXT2_NX) | |
| 2320 | + update_mask |= MSR_EFER_NXE; | |
| 2321 | + env->efer = (env->efer & ~update_mask) | | |
| 2322 | + (val & update_mask); | |
| 2323 | + } | |
| 2254 | 2324 | break; |
| 2255 | 2325 | case MSR_STAR: |
| 2256 | 2326 | env->star = val; |
| 2257 | 2327 | break; |
| 2328 | +#ifdef TARGET_X86_64 | |
| 2258 | 2329 | case MSR_LSTAR: |
| 2259 | 2330 | env->lstar = val; |
| 2260 | 2331 | break; |
| ... | ... | @@ -2296,13 +2367,13 @@ void helper_rdmsr(void) |
| 2296 | 2367 | case MSR_IA32_APICBASE: |
| 2297 | 2368 | val = cpu_get_apic_base(env); |
| 2298 | 2369 | break; |
| 2299 | -#ifdef TARGET_X86_64 | |
| 2300 | 2370 | case MSR_EFER: |
| 2301 | 2371 | val = env->efer; |
| 2302 | 2372 | break; |
| 2303 | 2373 | case MSR_STAR: |
| 2304 | 2374 | val = env->star; |
| 2305 | 2375 | break; |
| 2376 | +#ifdef TARGET_X86_64 | |
| 2306 | 2377 | case MSR_LSTAR: |
| 2307 | 2378 | val = env->lstar; |
| 2308 | 2379 | break; | ... | ... |