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 | 549 | |
| 550 | 550 | /* sysenter registers */ |
| 551 | 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 | 554 | uint64_t efer; |
| 555 | 555 | uint64_t star; |
| 556 | 556 | |
| ... | ... | @@ -737,7 +737,7 @@ static inline int cpu_get_time_fast(void) |
| 737 | 737 | #define cpu_signal_handler cpu_x86_signal_handler |
| 738 | 738 | #define cpu_list x86_cpu_list |
| 739 | 739 | |
| 740 | -#define CPU_SAVE_VERSION 6 | |
| 740 | +#define CPU_SAVE_VERSION 7 | |
| 741 | 741 | |
| 742 | 742 | /* MMU modes definitions */ |
| 743 | 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 | 55 | DEF_HELPER(void, helper_enter64_level, (int level, int data64, target_ulong t1)) |
| 56 | 56 | #endif |
| 57 | 57 | DEF_HELPER(void, helper_sysenter, (void)) |
| 58 | -DEF_HELPER(void, helper_sysexit, (void)) | |
| 58 | +DEF_HELPER(void, helper_sysexit, (int dflag)) | |
| 59 | 59 | #ifdef TARGET_X86_64 |
| 60 | 60 | DEF_HELPER(void, helper_syscall, (int next_eip_addend)) |
| 61 | 61 | DEF_HELPER(void, helper_sysret, (int dflag)) | ... | ... |
target-i386/machine.c
| ... | ... | @@ -88,9 +88,9 @@ void cpu_save(QEMUFile *f, void *opaque) |
| 88 | 88 | cpu_put_seg(f, &env->gdt); |
| 89 | 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 | 95 | qemu_put_betls(f, &env->cr[0]); |
| 96 | 96 | qemu_put_betls(f, &env->cr[2]); |
| ... | ... | @@ -169,7 +169,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) |
| 169 | 169 | int32_t a20_mask; |
| 170 | 170 | |
| 171 | 171 | if (version_id != 3 && version_id != 4 && version_id != 5 |
| 172 | - && version_id != 6) | |
| 172 | + && version_id != 6 && version_id != 7) | |
| 173 | 173 | return -EINVAL; |
| 174 | 174 | for(i = 0; i < CPU_NB_REGS; i++) |
| 175 | 175 | qemu_get_betls(f, &env->regs[i]); |
| ... | ... | @@ -244,8 +244,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) |
| 244 | 244 | cpu_get_seg(f, &env->idt); |
| 245 | 245 | |
| 246 | 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 | 255 | qemu_get_betls(f, &env->cr[0]); |
| 251 | 256 | qemu_get_betls(f, &env->cr[2]); | ... | ... |
target-i386/op_helper.c
| ... | ... | @@ -2919,11 +2919,23 @@ void helper_sysenter(void) |
| 2919 | 2919 | } |
| 2920 | 2920 | env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); |
| 2921 | 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 | 2939 | cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, |
| 2928 | 2940 | 0, 0xffffffff, |
| 2929 | 2941 | DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | |
| ... | ... | @@ -2933,7 +2945,7 @@ void helper_sysenter(void) |
| 2933 | 2945 | EIP = env->sysenter_eip; |
| 2934 | 2946 | } |
| 2935 | 2947 | |
| 2936 | -void helper_sysexit(void) | |
| 2948 | +void helper_sysexit(int dflag) | |
| 2937 | 2949 | { |
| 2938 | 2950 | int cpl; |
| 2939 | 2951 | |
| ... | ... | @@ -2942,16 +2954,32 @@ void helper_sysexit(void) |
| 2942 | 2954 | raise_exception_err(EXCP0D_GPF, 0); |
| 2943 | 2955 | } |
| 2944 | 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 | 2983 | ESP = ECX; |
| 2956 | 2984 | EIP = EDX; |
| 2957 | 2985 | #ifdef USE_KQEMU | ... | ... |
target-i386/translate.c
| ... | ... | @@ -6505,7 +6505,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
| 6505 | 6505 | tcg_gen_helper_0_0(helper_rdpmc); |
| 6506 | 6506 | break; |
| 6507 | 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 | 6510 | goto illegal_op; |
| 6510 | 6511 | if (!s->pe) { |
| 6511 | 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 | 6521 | } |
| 6521 | 6522 | break; |
| 6522 | 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 | 6526 | goto illegal_op; |
| 6525 | 6527 | if (!s->pe) { |
| 6526 | 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 | 6532 | s->cc_op = CC_OP_DYNAMIC; |
| 6531 | 6533 | } |
| 6532 | 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 | 6536 | gen_eob(s); |
| 6535 | 6537 | } |
| 6536 | 6538 | break; | ... | ... |