diff options
-rw-r--r-- | target-i386/helper.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/target-i386/helper.c b/target-i386/helper.c index ee3f670b51..0d2cd74bc9 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1494,11 +1494,12 @@ void load_seg(int seg_reg, int selector) target_ulong ptr; selector &= 0xffff; + cpl = env->hflags & HF_CPL_MASK; if ((selector & 0xfffc) == 0) { /* null selector case */ if (seg_reg == R_SS #ifdef TARGET_X86_64 - && !(env->hflags & HF_CS64_MASK) + && (!(env->hflags & HF_CS64_MASK) || cpl == 3) #endif ) raise_exception_err(EXCP0D_GPF, 0); @@ -1520,7 +1521,6 @@ void load_seg(int seg_reg, int selector) raise_exception_err(EXCP0D_GPF, selector & 0xfffc); rpl = selector & 3; dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; if (seg_reg == R_SS) { /* must be writable segment */ if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK)) @@ -2054,13 +2054,20 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend) new_ss, new_esp); } #endif - if ((env->hflags & HF_LMA_MASK) && (new_ss & 0xfffc) == 0) { - /* NULL ss is allowed in long mode */ - cpu_x86_load_seg_cache(env, R_SS, new_ss, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | - DESC_W_MASK | DESC_A_MASK); + if ((new_ss & 0xfffc) == 0) { +#ifdef TARGET_X86_64 + /* NULL ss is allowed in long mode if cpl != 3*/ + if ((env->hflags & HF_LMA_MASK) && rpl != 3) { + cpu_x86_load_seg_cache(env, R_SS, new_ss, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (rpl << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + } else +#endif + { + raise_exception_err(EXCP0D_GPF, 0); + } } else { if ((new_ss & 3) != rpl) raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); |