Commit 2436b61a6b386d712a1813b036921443bd1c5c39
1 parent
e737b32a
SYSENTER/SYSEXIT IA-32e implementation (Alexander Graf).
On Intel CPUs, sysenter and sysexit are valid in 64-bit mode. This patch makes both 64-bit aware and enables them for Intel CPUs. Add cpu save/load for 64-bit wide sysenter variables. Signed-off-by: Alexander Graf <agraf@suse.de> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5318 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
64 additions
and
29 deletions
target-i386/cpu.h
| @@ -549,8 +549,8 @@ typedef struct CPUX86State { | @@ -549,8 +549,8 @@ typedef struct CPUX86State { | ||
| 549 | 549 | ||
| 550 | /* sysenter registers */ | 550 | /* sysenter registers */ |
| 551 | uint32_t sysenter_cs; | 551 | uint32_t sysenter_cs; |
| 552 | - uint32_t sysenter_esp; | ||
| 553 | - uint32_t sysenter_eip; | 552 | + target_ulong sysenter_esp; |
| 553 | + target_ulong sysenter_eip; | ||
| 554 | uint64_t efer; | 554 | uint64_t efer; |
| 555 | uint64_t star; | 555 | uint64_t star; |
| 556 | 556 | ||
| @@ -737,7 +737,7 @@ static inline int cpu_get_time_fast(void) | @@ -737,7 +737,7 @@ static inline int cpu_get_time_fast(void) | ||
| 737 | #define cpu_signal_handler cpu_x86_signal_handler | 737 | #define cpu_signal_handler cpu_x86_signal_handler |
| 738 | #define cpu_list x86_cpu_list | 738 | #define cpu_list x86_cpu_list |
| 739 | 739 | ||
| 740 | -#define CPU_SAVE_VERSION 6 | 740 | +#define CPU_SAVE_VERSION 7 |
| 741 | 741 | ||
| 742 | /* MMU modes definitions */ | 742 | /* MMU modes definitions */ |
| 743 | #define MMU_MODE0_SUFFIX _kernel | 743 | #define MMU_MODE0_SUFFIX _kernel |
target-i386/helper.h
| @@ -55,7 +55,7 @@ DEF_HELPER(void, helper_enter_level, (int level, int data32, target_ulong t1)) | @@ -55,7 +55,7 @@ DEF_HELPER(void, helper_enter_level, (int level, int data32, target_ulong t1)) | ||
| 55 | DEF_HELPER(void, helper_enter64_level, (int level, int data64, target_ulong t1)) | 55 | DEF_HELPER(void, helper_enter64_level, (int level, int data64, target_ulong t1)) |
| 56 | #endif | 56 | #endif |
| 57 | DEF_HELPER(void, helper_sysenter, (void)) | 57 | DEF_HELPER(void, helper_sysenter, (void)) |
| 58 | -DEF_HELPER(void, helper_sysexit, (void)) | 58 | +DEF_HELPER(void, helper_sysexit, (int dflag)) |
| 59 | #ifdef TARGET_X86_64 | 59 | #ifdef TARGET_X86_64 |
| 60 | DEF_HELPER(void, helper_syscall, (int next_eip_addend)) | 60 | DEF_HELPER(void, helper_syscall, (int next_eip_addend)) |
| 61 | DEF_HELPER(void, helper_sysret, (int dflag)) | 61 | DEF_HELPER(void, helper_sysret, (int dflag)) |
target-i386/machine.c
| @@ -88,9 +88,9 @@ void cpu_save(QEMUFile *f, void *opaque) | @@ -88,9 +88,9 @@ void cpu_save(QEMUFile *f, void *opaque) | ||
| 88 | cpu_put_seg(f, &env->gdt); | 88 | cpu_put_seg(f, &env->gdt); |
| 89 | cpu_put_seg(f, &env->idt); | 89 | cpu_put_seg(f, &env->idt); |
| 90 | 90 | ||
| 91 | - qemu_put_be32s(f, &env->sysenter_cs); | ||
| 92 | - qemu_put_be32s(f, &env->sysenter_esp); | ||
| 93 | - qemu_put_be32s(f, &env->sysenter_eip); | 91 | + qemu_put_betls(f, &env->sysenter_cs); |
| 92 | + qemu_put_betls(f, &env->sysenter_esp); | ||
| 93 | + qemu_put_betls(f, &env->sysenter_eip); | ||
| 94 | 94 | ||
| 95 | qemu_put_betls(f, &env->cr[0]); | 95 | qemu_put_betls(f, &env->cr[0]); |
| 96 | qemu_put_betls(f, &env->cr[2]); | 96 | qemu_put_betls(f, &env->cr[2]); |
| @@ -169,7 +169,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) | @@ -169,7 +169,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) | ||
| 169 | int32_t a20_mask; | 169 | int32_t a20_mask; |
| 170 | 170 | ||
| 171 | if (version_id != 3 && version_id != 4 && version_id != 5 | 171 | if (version_id != 3 && version_id != 4 && version_id != 5 |
| 172 | - && version_id != 6) | 172 | + && version_id != 6 && version_id != 7) |
| 173 | return -EINVAL; | 173 | return -EINVAL; |
| 174 | for(i = 0; i < CPU_NB_REGS; i++) | 174 | for(i = 0; i < CPU_NB_REGS; i++) |
| 175 | qemu_get_betls(f, &env->regs[i]); | 175 | qemu_get_betls(f, &env->regs[i]); |
| @@ -244,8 +244,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) | @@ -244,8 +244,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) | ||
| 244 | cpu_get_seg(f, &env->idt); | 244 | cpu_get_seg(f, &env->idt); |
| 245 | 245 | ||
| 246 | qemu_get_be32s(f, &env->sysenter_cs); | 246 | qemu_get_be32s(f, &env->sysenter_cs); |
| 247 | - qemu_get_be32s(f, &env->sysenter_esp); | ||
| 248 | - qemu_get_be32s(f, &env->sysenter_eip); | 247 | + if (version_id >= 7) { |
| 248 | + qemu_get_betls(f, &env->sysenter_esp); | ||
| 249 | + qemu_get_betls(f, &env->sysenter_eip); | ||
| 250 | + } else { | ||
| 251 | + qemu_get_be32s(f, &env->sysenter_esp); | ||
| 252 | + qemu_get_be32s(f, &env->sysenter_eip); | ||
| 253 | + } | ||
| 249 | 254 | ||
| 250 | qemu_get_betls(f, &env->cr[0]); | 255 | qemu_get_betls(f, &env->cr[0]); |
| 251 | qemu_get_betls(f, &env->cr[2]); | 256 | qemu_get_betls(f, &env->cr[2]); |
target-i386/op_helper.c
| @@ -2919,11 +2919,23 @@ void helper_sysenter(void) | @@ -2919,11 +2919,23 @@ void helper_sysenter(void) | ||
| 2919 | } | 2919 | } |
| 2920 | env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); | 2920 | env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); |
| 2921 | cpu_x86_set_cpl(env, 0); | 2921 | cpu_x86_set_cpl(env, 0); |
| 2922 | - cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, | ||
| 2923 | - 0, 0xffffffff, | ||
| 2924 | - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2925 | - DESC_S_MASK | | ||
| 2926 | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); | 2922 | + |
| 2923 | +#ifdef TARGET_X86_64 | ||
| 2924 | + if (env->hflags & HF_LMA_MASK) { | ||
| 2925 | + cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, | ||
| 2926 | + 0, 0xffffffff, | ||
| 2927 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2928 | + DESC_S_MASK | | ||
| 2929 | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); | ||
| 2930 | + } else | ||
| 2931 | +#endif | ||
| 2932 | + { | ||
| 2933 | + cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, | ||
| 2934 | + 0, 0xffffffff, | ||
| 2935 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2936 | + DESC_S_MASK | | ||
| 2937 | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); | ||
| 2938 | + } | ||
| 2927 | cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, | 2939 | cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, |
| 2928 | 0, 0xffffffff, | 2940 | 0, 0xffffffff, |
| 2929 | DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | 2941 | DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
| @@ -2933,7 +2945,7 @@ void helper_sysenter(void) | @@ -2933,7 +2945,7 @@ void helper_sysenter(void) | ||
| 2933 | EIP = env->sysenter_eip; | 2945 | EIP = env->sysenter_eip; |
| 2934 | } | 2946 | } |
| 2935 | 2947 | ||
| 2936 | -void helper_sysexit(void) | 2948 | +void helper_sysexit(int dflag) |
| 2937 | { | 2949 | { |
| 2938 | int cpl; | 2950 | int cpl; |
| 2939 | 2951 | ||
| @@ -2942,16 +2954,32 @@ void helper_sysexit(void) | @@ -2942,16 +2954,32 @@ void helper_sysexit(void) | ||
| 2942 | raise_exception_err(EXCP0D_GPF, 0); | 2954 | raise_exception_err(EXCP0D_GPF, 0); |
| 2943 | } | 2955 | } |
| 2944 | cpu_x86_set_cpl(env, 3); | 2956 | cpu_x86_set_cpl(env, 3); |
| 2945 | - cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, | ||
| 2946 | - 0, 0xffffffff, | ||
| 2947 | - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2948 | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | | ||
| 2949 | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); | ||
| 2950 | - cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, | ||
| 2951 | - 0, 0xffffffff, | ||
| 2952 | - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2953 | - DESC_S_MASK | (3 << DESC_DPL_SHIFT) | | ||
| 2954 | - DESC_W_MASK | DESC_A_MASK); | 2957 | +#ifdef TARGET_X86_64 |
| 2958 | + if (dflag == 2) { | ||
| 2959 | + cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3, | ||
| 2960 | + 0, 0xffffffff, | ||
| 2961 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2962 | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | | ||
| 2963 | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK); | ||
| 2964 | + cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3, | ||
| 2965 | + 0, 0xffffffff, | ||
| 2966 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2967 | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | | ||
| 2968 | + DESC_W_MASK | DESC_A_MASK); | ||
| 2969 | + } else | ||
| 2970 | +#endif | ||
| 2971 | + { | ||
| 2972 | + cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, | ||
| 2973 | + 0, 0xffffffff, | ||
| 2974 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2975 | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | | ||
| 2976 | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); | ||
| 2977 | + cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, | ||
| 2978 | + 0, 0xffffffff, | ||
| 2979 | + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | | ||
| 2980 | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | | ||
| 2981 | + DESC_W_MASK | DESC_A_MASK); | ||
| 2982 | + } | ||
| 2955 | ESP = ECX; | 2983 | ESP = ECX; |
| 2956 | EIP = EDX; | 2984 | EIP = EDX; |
| 2957 | #ifdef USE_KQEMU | 2985 | #ifdef USE_KQEMU |
target-i386/translate.c
| @@ -6505,7 +6505,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | @@ -6505,7 +6505,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
| 6505 | tcg_gen_helper_0_0(helper_rdpmc); | 6505 | tcg_gen_helper_0_0(helper_rdpmc); |
| 6506 | break; | 6506 | break; |
| 6507 | case 0x134: /* sysenter */ | 6507 | case 0x134: /* sysenter */ |
| 6508 | - if (CODE64(s)) | 6508 | + /* For Intel SYSENTER is valid on 64-bit */ |
| 6509 | + if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) | ||
| 6509 | goto illegal_op; | 6510 | goto illegal_op; |
| 6510 | if (!s->pe) { | 6511 | if (!s->pe) { |
| 6511 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | 6512 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| @@ -6520,7 +6521,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | @@ -6520,7 +6521,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
| 6520 | } | 6521 | } |
| 6521 | break; | 6522 | break; |
| 6522 | case 0x135: /* sysexit */ | 6523 | case 0x135: /* sysexit */ |
| 6523 | - if (CODE64(s)) | 6524 | + /* For Intel SYSEXIT is valid on 64-bit */ |
| 6525 | + if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1) | ||
| 6524 | goto illegal_op; | 6526 | goto illegal_op; |
| 6525 | if (!s->pe) { | 6527 | if (!s->pe) { |
| 6526 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); | 6528 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| @@ -6530,7 +6532,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | @@ -6530,7 +6532,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) | ||
| 6530 | s->cc_op = CC_OP_DYNAMIC; | 6532 | s->cc_op = CC_OP_DYNAMIC; |
| 6531 | } | 6533 | } |
| 6532 | gen_jmp_im(pc_start - s->cs_base); | 6534 | gen_jmp_im(pc_start - s->cs_base); |
| 6533 | - tcg_gen_helper_0_0(helper_sysexit); | 6535 | + tcg_gen_helper_0_1(helper_sysexit, tcg_const_i32(dflag)); |
| 6534 | gen_eob(s); | 6536 | gen_eob(s); |
| 6535 | } | 6537 | } |
| 6536 | break; | 6538 | break; |