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,6 +933,7 @@ static void do_interrupt64(int intno, int is_int, int error_code, | ||
| 933 | } | 933 | } |
| 934 | env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); | 934 | env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); |
| 935 | } | 935 | } |
| 936 | +#endif | ||
| 936 | 937 | ||
| 937 | void helper_syscall(int next_eip_addend) | 938 | void helper_syscall(int next_eip_addend) |
| 938 | { | 939 | { |
| @@ -942,6 +943,7 @@ void helper_syscall(int next_eip_addend) | @@ -942,6 +943,7 @@ void helper_syscall(int next_eip_addend) | ||
| 942 | raise_exception_err(EXCP06_ILLOP, 0); | 943 | raise_exception_err(EXCP06_ILLOP, 0); |
| 943 | } | 944 | } |
| 944 | selector = (env->star >> 32) & 0xffff; | 945 | selector = (env->star >> 32) & 0xffff; |
| 946 | +#ifdef TARGET_X86_64 | ||
| 945 | if (env->hflags & HF_LMA_MASK) { | 947 | if (env->hflags & HF_LMA_MASK) { |
| 946 | ECX = env->eip + next_eip_addend; | 948 | ECX = env->eip + next_eip_addend; |
| 947 | env->regs[11] = compute_eflags(); | 949 | env->regs[11] = compute_eflags(); |
| @@ -962,7 +964,9 @@ void helper_syscall(int next_eip_addend) | @@ -962,7 +964,9 @@ void helper_syscall(int next_eip_addend) | ||
| 962 | env->eip = env->lstar; | 964 | env->eip = env->lstar; |
| 963 | else | 965 | else |
| 964 | env->eip = env->cstar; | 966 | env->eip = env->cstar; |
| 965 | - } else { | 967 | + } else |
| 968 | +#endif | ||
| 969 | + { | ||
| 966 | ECX = (uint32_t)(env->eip + next_eip_addend); | 970 | ECX = (uint32_t)(env->eip + next_eip_addend); |
| 967 | 971 | ||
| 968 | cpu_x86_set_cpl(env, 0); | 972 | cpu_x86_set_cpl(env, 0); |
| @@ -985,11 +989,15 @@ void helper_sysret(int dflag) | @@ -985,11 +989,15 @@ void helper_sysret(int dflag) | ||
| 985 | { | 989 | { |
| 986 | int cpl, selector; | 990 | int cpl, selector; |
| 987 | 991 | ||
| 992 | + if (!(env->efer & MSR_EFER_SCE)) { | ||
| 993 | + raise_exception_err(EXCP06_ILLOP, 0); | ||
| 994 | + } | ||
| 988 | cpl = env->hflags & HF_CPL_MASK; | 995 | cpl = env->hflags & HF_CPL_MASK; |
| 989 | if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { | 996 | if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) { |
| 990 | raise_exception_err(EXCP0D_GPF, 0); | 997 | raise_exception_err(EXCP0D_GPF, 0); |
| 991 | } | 998 | } |
| 992 | selector = (env->star >> 48) & 0xffff; | 999 | selector = (env->star >> 48) & 0xffff; |
| 1000 | +#ifdef TARGET_X86_64 | ||
| 993 | if (env->hflags & HF_LMA_MASK) { | 1001 | if (env->hflags & HF_LMA_MASK) { |
| 994 | if (dflag == 2) { | 1002 | if (dflag == 2) { |
| 995 | cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, | 1003 | cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, |
| @@ -1015,7 +1023,9 @@ void helper_sysret(int dflag) | @@ -1015,7 +1023,9 @@ void helper_sysret(int dflag) | ||
| 1015 | load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | | 1023 | load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | |
| 1016 | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); | 1024 | IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK); |
| 1017 | cpu_x86_set_cpl(env, 3); | 1025 | cpu_x86_set_cpl(env, 3); |
| 1018 | - } else { | 1026 | + } else |
| 1027 | +#endif | ||
| 1028 | + { | ||
| 1019 | cpu_x86_load_seg_cache(env, R_CS, selector | 3, | 1029 | cpu_x86_load_seg_cache(env, R_CS, selector | 3, |
| 1020 | 0, 0xffffffff, | 1030 | 0, 0xffffffff, |
| 1021 | DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | 1031 | DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
| @@ -1030,8 +1040,15 @@ void helper_sysret(int dflag) | @@ -1030,8 +1040,15 @@ void helper_sysret(int dflag) | ||
| 1030 | env->eflags |= IF_MASK; | 1040 | env->eflags |= IF_MASK; |
| 1031 | cpu_x86_set_cpl(env, 3); | 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 | #endif | 1050 | #endif |
| 1051 | +} | ||
| 1035 | 1052 | ||
| 1036 | /* real mode interrupt */ | 1053 | /* real mode interrupt */ |
| 1037 | static void do_interrupt_real(int intno, int is_int, int error_code, | 1054 | static void do_interrupt_real(int intno, int is_int, int error_code, |
| @@ -1265,9 +1282,21 @@ void helper_cmpxchg8b(void) | @@ -1265,9 +1282,21 @@ void helper_cmpxchg8b(void) | ||
| 1265 | 1282 | ||
| 1266 | void helper_cpuid(void) | 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 | case 0: | 1298 | case 0: |
| 1270 | - EAX = 2; /* max EAX index supported */ | 1299 | + EAX = env->cpuid_level; |
| 1271 | EBX = env->cpuid_vendor1; | 1300 | EBX = env->cpuid_vendor1; |
| 1272 | EDX = env->cpuid_vendor2; | 1301 | EDX = env->cpuid_vendor2; |
| 1273 | ECX = env->cpuid_vendor3; | 1302 | ECX = env->cpuid_vendor3; |
| @@ -1278,16 +1307,15 @@ void helper_cpuid(void) | @@ -1278,16 +1307,15 @@ void helper_cpuid(void) | ||
| 1278 | ECX = env->cpuid_ext_features; | 1307 | ECX = env->cpuid_ext_features; |
| 1279 | EDX = env->cpuid_features; | 1308 | EDX = env->cpuid_features; |
| 1280 | break; | 1309 | break; |
| 1281 | - default: | 1310 | + case 2: |
| 1282 | /* cache info: needed for Pentium Pro compatibility */ | 1311 | /* cache info: needed for Pentium Pro compatibility */ |
| 1283 | EAX = 0x410601; | 1312 | EAX = 0x410601; |
| 1284 | EBX = 0; | 1313 | EBX = 0; |
| 1285 | ECX = 0; | 1314 | ECX = 0; |
| 1286 | EDX = 0; | 1315 | EDX = 0; |
| 1287 | break; | 1316 | break; |
| 1288 | -#ifdef TARGET_X86_64 | ||
| 1289 | case 0x80000000: | 1317 | case 0x80000000: |
| 1290 | - EAX = 0x80000008; | 1318 | + EAX = env->cpuid_xlevel; |
| 1291 | EBX = env->cpuid_vendor1; | 1319 | EBX = env->cpuid_vendor1; |
| 1292 | EDX = env->cpuid_vendor2; | 1320 | EDX = env->cpuid_vendor2; |
| 1293 | ECX = env->cpuid_vendor3; | 1321 | ECX = env->cpuid_vendor3; |
| @@ -1296,8 +1324,15 @@ void helper_cpuid(void) | @@ -1296,8 +1324,15 @@ void helper_cpuid(void) | ||
| 1296 | EAX = env->cpuid_features; | 1324 | EAX = env->cpuid_features; |
| 1297 | EBX = 0; | 1325 | EBX = 0; |
| 1298 | ECX = 0; | 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 | break; | 1336 | break; |
| 1302 | case 0x80000008: | 1337 | case 0x80000008: |
| 1303 | /* virtual & phys address size in low 2 bytes. */ | 1338 | /* virtual & phys address size in low 2 bytes. */ |
| @@ -1306,7 +1341,13 @@ void helper_cpuid(void) | @@ -1306,7 +1341,13 @@ void helper_cpuid(void) | ||
| 1306 | ECX = 0; | 1341 | ECX = 0; |
| 1307 | EDX = 0; | 1342 | EDX = 0; |
| 1308 | break; | 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,11 +1564,11 @@ void load_seg(int seg_reg, int selector) | ||
| 1523 | } | 1564 | } |
| 1524 | 1565 | ||
| 1525 | /* protected mode jump */ | 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 | int new_cs, gate_cs, type; | 1569 | int new_cs, gate_cs, type; |
| 1529 | uint32_t e1, e2, cpl, dpl, rpl, limit; | 1570 | uint32_t e1, e2, cpl, dpl, rpl, limit; |
| 1530 | - target_ulong new_eip; | 1571 | + target_ulong new_eip, next_eip; |
| 1531 | 1572 | ||
| 1532 | new_cs = T0; | 1573 | new_cs = T0; |
| 1533 | new_eip = T1; | 1574 | new_eip = T1; |
| @@ -1573,6 +1614,7 @@ void helper_ljmp_protected_T0_T1(int next_eip) | @@ -1573,6 +1614,7 @@ void helper_ljmp_protected_T0_T1(int next_eip) | ||
| 1573 | case 5: /* task gate */ | 1614 | case 5: /* task gate */ |
| 1574 | if (dpl < cpl || dpl < rpl) | 1615 | if (dpl < cpl || dpl < rpl) |
| 1575 | raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | 1616 | raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); |
| 1617 | + next_eip = env->eip + next_eip_addend; | ||
| 1576 | switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); | 1618 | switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip); |
| 1577 | break; | 1619 | break; |
| 1578 | case 4: /* 286 call gate */ | 1620 | case 4: /* 286 call gate */ |
| @@ -1638,16 +1680,17 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) | @@ -1638,16 +1680,17 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) | ||
| 1638 | } | 1680 | } |
| 1639 | 1681 | ||
| 1640 | /* protected mode call */ | 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 | int new_cs, new_eip, new_stack, i; | 1685 | int new_cs, new_eip, new_stack, i; |
| 1644 | uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; | 1686 | uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; |
| 1645 | uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; | 1687 | uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; |
| 1646 | uint32_t val, limit, old_sp_mask; | 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 | new_cs = T0; | 1691 | new_cs = T0; |
| 1650 | new_eip = T1; | 1692 | new_eip = T1; |
| 1693 | + next_eip = env->eip + next_eip_addend; | ||
| 1651 | #ifdef DEBUG_PCALL | 1694 | #ifdef DEBUG_PCALL |
| 1652 | if (loglevel & CPU_LOG_PCALL) { | 1695 | if (loglevel & CPU_LOG_PCALL) { |
| 1653 | fprintf(logfile, "lcall %04x:%08x s=%d\n", | 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,25 +1727,43 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip) | ||
| 1684 | if (!(e2 & DESC_P_MASK)) | 1727 | if (!(e2 & DESC_P_MASK)) |
| 1685 | raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | 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 | } else { | 1767 | } else { |
| 1707 | /* check gate type */ | 1768 | /* check gate type */ |
| 1708 | type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; | 1769 | type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; |
| @@ -2245,16 +2306,26 @@ void helper_wrmsr(void) | @@ -2245,16 +2306,26 @@ void helper_wrmsr(void) | ||
| 2245 | case MSR_IA32_APICBASE: | 2306 | case MSR_IA32_APICBASE: |
| 2246 | cpu_set_apic_base(env, val); | 2307 | cpu_set_apic_base(env, val); |
| 2247 | break; | 2308 | break; |
| 2248 | -#ifdef TARGET_X86_64 | ||
| 2249 | case MSR_EFER: | 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 | break; | 2324 | break; |
| 2255 | case MSR_STAR: | 2325 | case MSR_STAR: |
| 2256 | env->star = val; | 2326 | env->star = val; |
| 2257 | break; | 2327 | break; |
| 2328 | +#ifdef TARGET_X86_64 | ||
| 2258 | case MSR_LSTAR: | 2329 | case MSR_LSTAR: |
| 2259 | env->lstar = val; | 2330 | env->lstar = val; |
| 2260 | break; | 2331 | break; |
| @@ -2296,13 +2367,13 @@ void helper_rdmsr(void) | @@ -2296,13 +2367,13 @@ void helper_rdmsr(void) | ||
| 2296 | case MSR_IA32_APICBASE: | 2367 | case MSR_IA32_APICBASE: |
| 2297 | val = cpu_get_apic_base(env); | 2368 | val = cpu_get_apic_base(env); |
| 2298 | break; | 2369 | break; |
| 2299 | -#ifdef TARGET_X86_64 | ||
| 2300 | case MSR_EFER: | 2370 | case MSR_EFER: |
| 2301 | val = env->efer; | 2371 | val = env->efer; |
| 2302 | break; | 2372 | break; |
| 2303 | case MSR_STAR: | 2373 | case MSR_STAR: |
| 2304 | val = env->star; | 2374 | val = env->star; |
| 2305 | break; | 2375 | break; |
| 2376 | +#ifdef TARGET_X86_64 | ||
| 2306 | case MSR_LSTAR: | 2377 | case MSR_LSTAR: |
| 2307 | val = env->lstar; | 2378 | val = env->lstar; |
| 2308 | break; | 2379 | break; |