* [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks @ 2008-07-09 12:12 Jan Kiszka 2008-07-14 10:34 ` [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 Jan Kiszka 0 siblings, 1 reply; 13+ messages in thread From: Jan Kiszka @ 2008-07-09 12:12 UTC (permalink / raw) To: qemu-devel As announced earlier, I developed an add-on feature for x86 emulation to support segment type and limit checks. Now I finally completed porting it over to latest SVN and added (hopefully) all the cases that were missing so far (as the customer didn't need them). The idea of this patch is to generate calls to a check helper only in case the user requested this support via "-seg-checks". This feature remains off by default as most x86 OSes do not care about protection via segmentation anymore (and it was even removed from 64-bit modes by the CPU vendors). Moreover, checking the segment type and limit on every memory access is nothing that makes QEMU faster, so you will only want this if you are looking for very accurate emulation. The attached patch passed our own test cases, and it boots standard Linux into X, both scenarios with -seg-checks enabled. However, though things have been checked twice, I wouldn't be surprised if there are a few typos or other errors in the check instrumentations. But at least, those won't have any impact on the disabled, standard case. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> --- target-i386/cpu.h | 8 target-i386/helper.h | 5 target-i386/op_helper.c | 59 ++++++ target-i386/translate.c | 409 +++++++++++++++++++++++++++++++++++++++--------- vl.c | 7 5 files changed, 417 insertions(+), 71 deletions(-) Index: b/target-i386/cpu.h =================================================================== --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -94,6 +94,10 @@ #define DESC_TSS_BUSY_MASK (1 << 9) +/* flags for segment access checks */ +#define ACC_READ 0x0000 +#define ACC_WRITE 0x0100 + /* eflags masks */ #define CC_C 0x0001 #define CC_P 0x0004 @@ -751,6 +755,10 @@ static inline void cpu_clone_regs(CPUSta env->regs[R_ESP] = newsp; env->regs[R_EAX] = 0; } + +#define seg_checks 0 +#else +extern int seg_checks; #endif #define CPU_PC_FROM_TB(env, tb) env->eip = tb->pc - tb->cs_base Index: b/target-i386/translate.c =================================================================== --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -591,7 +591,7 @@ static inline void gen_jmp_im(target_ulo tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, eip)); } -static inline void gen_string_movl_A0_ESI(DisasContext *s) +static inline int gen_string_movl_A0_ESI(DisasContext *s) { int override; @@ -604,6 +604,7 @@ static inline void gen_string_movl_A0_ES } else { gen_op_movq_A0_reg(R_ESI); } + return -1; } else #endif if (s->aflag) { @@ -615,6 +616,7 @@ static inline void gen_string_movl_A0_ES gen_op_addl_A0_reg_sN(0, R_ESI); } else { gen_op_movl_A0_reg(R_ESI); + return R_DS; } } else { /* 16 address, always override */ @@ -624,13 +626,15 @@ static inline void gen_string_movl_A0_ES gen_op_andl_A0_ffff(); gen_op_addl_A0_seg(override); } + return override; } -static inline void gen_string_movl_A0_EDI(DisasContext *s) +static inline int gen_string_movl_A0_EDI(DisasContext *s) { #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_movq_A0_reg(R_EDI); + return -1; } else #endif if (s->aflag) { @@ -645,6 +649,7 @@ static inline void gen_string_movl_A0_ED gen_op_andl_A0_ffff(); gen_op_addl_A0_seg(R_ES); } + return R_ES; } static inline void gen_op_movl_T0_Dshift(int ot) @@ -752,11 +757,31 @@ static void gen_check_io(DisasContext *s } } +static inline void gen_check_segmented_access(int seg_reg, int type) +{ + tcg_gen_helper_0_3(helper_check_segmented_access, cpu_A0, + tcg_const_i32(seg_reg), tcg_const_i32(type)); +} + +static inline void gen_check_segmented_access_size(int seg_reg, int type, + int size) +{ + tcg_gen_helper_0_4(helper_check_segmented_access_size, cpu_A0, + tcg_const_i32(seg_reg), tcg_const_i32(type), + tcg_const_i32(size)); +} + static inline void gen_movs(DisasContext *s, int ot) { - gen_string_movl_A0_ESI(s); + int seg_reg; + + seg_reg = gen_string_movl_A0_ESI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); gen_op_st_T0_A0(ot + s->mem_index); gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_ESI); @@ -1165,8 +1190,12 @@ static int gen_jz_ecx_string(DisasContex static inline void gen_stos(DisasContext *s, int ot) { + int seg_reg; + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); gen_op_st_T0_A0(ot + s->mem_index); gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_EDI); @@ -1174,7 +1203,11 @@ static inline void gen_stos(DisasContext static inline void gen_lods(DisasContext *s, int ot) { - gen_string_movl_A0_ESI(s); + int seg_reg; + + seg_reg = gen_string_movl_A0_ESI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); gen_op_mov_reg_T0(ot, R_EAX); gen_op_movl_T0_Dshift(ot); @@ -1183,8 +1216,12 @@ static inline void gen_lods(DisasContext static inline void gen_scas(DisasContext *s, int ot) { + int seg_reg; + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_cmpl_T0_T1_cc(); gen_op_movl_T0_Dshift(ot); @@ -1193,9 +1230,15 @@ static inline void gen_scas(DisasContext static inline void gen_cmps(DisasContext *s, int ot) { - gen_string_movl_A0_ESI(s); + int seg_reg; + + seg_reg = gen_string_movl_A0_ESI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_cmpl_T0_T1_cc(); gen_op_movl_T0_Dshift(ot); @@ -1205,9 +1248,13 @@ static inline void gen_cmps(DisasContext static inline void gen_ins(DisasContext *s, int ot) { + int seg_reg; + if (use_icount) gen_io_start(); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); /* Note: we must do this dummy write first to be restartable in case of page fault. */ gen_op_movl_T0_0(); @@ -1225,9 +1272,13 @@ static inline void gen_ins(DisasContext static inline void gen_outs(DisasContext *s, int ot) { + int seg_reg; + if (use_icount) gen_io_start(); - gen_string_movl_A0_ESI(s); + seg_reg = gen_string_movl_A0_ESI(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); gen_op_mov_TN_reg(OT_WORD, 1, R_EDX); @@ -1882,7 +1933,7 @@ static void gen_shifti(DisasContext *s1, } } -static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) +static int gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) { target_long disp; int havesib; @@ -2064,6 +2115,7 @@ static void gen_lea_modrm(DisasContext * disp = 0; *reg_ptr = opreg; *offset_ptr = disp; + return override; } static void gen_nop_modrm(DisasContext *s, int modrm) @@ -2117,11 +2169,10 @@ static void gen_nop_modrm(DisasContext * } /* used for LEA and MOV AX, mem */ -static void gen_add_A0_ds_seg(DisasContext *s) +static int gen_add_A0_ds_seg(DisasContext *s) { int override, must_add_seg; must_add_seg = s->addseg; - override = R_DS; if (s->override >= 0) { override = s->override; must_add_seg = 1; @@ -2138,13 +2189,14 @@ static void gen_add_A0_ds_seg(DisasConte gen_op_addl_A0_seg(override); } } + return override; } /* generate modrm memory load or store of 'reg'. TMP0 is used if reg != OR_TMP0 */ static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store) { - int mod, rm, opreg, disp; + int mod, rm, opreg, disp, seg_reg; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); @@ -2159,12 +2211,16 @@ static void gen_ldst_modrm(DisasContext gen_op_mov_reg_T0(ot, reg); } } else { - gen_lea_modrm(s, modrm, &opreg, &disp); + seg_reg = gen_lea_modrm(s, modrm, &opreg, &disp); if (is_store) { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); if (reg != OR_TMP0) gen_op_mov_TN_reg(ot, 0, reg); gen_op_st_T0_A0(ot + s->mem_index); } else { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); if (reg != OR_TMP0) gen_op_mov_reg_T0(ot, reg); @@ -2398,6 +2454,8 @@ static void gen_push_T0(DisasContext *s) tcg_gen_mov_tl(cpu_T[1], cpu_A0); gen_op_addl_A0_seg(R_SS); } + if (seg_checks) + gen_check_segmented_access(R_SS, ACC_WRITE | (OT_WORD + s->dflag)); gen_op_st_T0_A0(s->dflag + 1 + s->mem_index); if (s->ss32 && !s->addseg) gen_op_mov_reg_A0(1, R_ESP); @@ -2437,6 +2495,8 @@ static void gen_push_T1(DisasContext *s) gen_op_andl_A0_ffff(); gen_op_addl_A0_seg(R_SS); } + if (seg_checks) + gen_check_segmented_access(R_SS, ACC_WRITE | (OT_WORD + s->dflag)); gen_op_st_T1_A0(s->dflag + 1 + s->mem_index); if (s->ss32 && !s->addseg) @@ -2464,6 +2524,8 @@ static void gen_pop_T0(DisasContext *s) gen_op_andl_A0_ffff(); gen_op_addl_A0_seg(R_SS); } + if (seg_checks) + gen_check_segmented_access(R_SS, ACC_READ | (OT_WORD + s->dflag)); gen_op_ld_T0_A0(s->dflag + 1 + s->mem_index); } } @@ -2501,6 +2563,8 @@ static void gen_pusha(DisasContext *s) tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) gen_op_addl_A0_seg(R_SS); + if (seg_checks) + gen_check_segmented_access(R_SS, ACC_WRITE | (OT_WORD + s->dflag + 3)); for(i = 0;i < 8; i++) { gen_op_mov_TN_reg(OT_LONG, 0, 7 - i); gen_op_st_T0_A0(OT_WORD + s->dflag + s->mem_index); @@ -2520,6 +2584,8 @@ static void gen_popa(DisasContext *s) tcg_gen_addi_tl(cpu_T[1], cpu_T[1], 16 << s->dflag); if (s->addseg) gen_op_addl_A0_seg(R_SS); + if (seg_checks) + gen_check_segmented_access(R_SS, ACC_READ | (OT_WORD + s->dflag + 3)); for(i = 0;i < 8; i++) { /* ESP is not reloaded */ if (i != 3) { @@ -2571,6 +2637,8 @@ static void gen_enter(DisasContext *s, i tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) gen_op_addl_A0_seg(R_SS); + if (seg_checks) + gen_check_segmented_access(R_SS, ACC_WRITE | ot); /* push bp */ gen_op_mov_TN_reg(OT_LONG, 0, R_EBP); gen_op_st_T0_A0(ot + s->mem_index); @@ -2924,7 +2992,7 @@ static void *sse_op_table5[256] = { static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) { int b1, op1_offset, op2_offset, is_xmm, val, ot; - int modrm, mod, rm, reg, reg_addr, offset_addr; + int seg_reg, modrm, mod, rm, reg, reg_addr, offset_addr; void *sse_op2; b &= 0xff; @@ -2990,7 +3058,9 @@ static void gen_sse(DisasContext *s, int case 0x0e7: /* movntq */ if (mod == 3) goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); break; case 0x1e7: /* movntdq */ @@ -2999,7 +3069,9 @@ static void gen_sse(DisasContext *s, int case 0x3f0: /* lddqu */ if (mod == 3) goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | (OT_QUAD + 1)); gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); break; case 0x6e: /* movd mm, ea */ @@ -3035,7 +3107,9 @@ static void gen_sse(DisasContext *s, int break; case 0x6f: /* movq mm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); } else { rm = (modrm & 7); @@ -3052,7 +3126,9 @@ static void gen_sse(DisasContext *s, int case 0x16f: /* movdqa xmm, ea */ case 0x26f: /* movdqu xmm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | (OT_QUAD + 1)); gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); @@ -3062,7 +3138,9 @@ static void gen_sse(DisasContext *s, int break; case 0x210: /* movss xmm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); gen_op_movl_T0_0(); @@ -3077,7 +3155,9 @@ static void gen_sse(DisasContext *s, int break; case 0x310: /* movsd xmm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); gen_op_movl_T0_0(); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); @@ -3091,7 +3171,9 @@ static void gen_sse(DisasContext *s, int case 0x012: /* movlps */ case 0x112: /* movlpd */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { /* movhlps */ @@ -3102,7 +3184,9 @@ static void gen_sse(DisasContext *s, int break; case 0x212: /* movsldup */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | (OT_QUAD + 1)); gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); @@ -3118,7 +3202,9 @@ static void gen_sse(DisasContext *s, int break; case 0x312: /* movddup */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); @@ -3131,7 +3217,9 @@ static void gen_sse(DisasContext *s, int case 0x016: /* movhps */ case 0x116: /* movhpd */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); } else { /* movlhps */ @@ -3142,7 +3230,9 @@ static void gen_sse(DisasContext *s, int break; case 0x216: /* movshdup */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | (OT_QUAD + 1)); gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); @@ -3186,7 +3276,9 @@ static void gen_sse(DisasContext *s, int break; case 0x27e: /* movq xmm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); @@ -3197,7 +3289,9 @@ static void gen_sse(DisasContext *s, int break; case 0x7f: /* movq ea, mm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); } else { rm = (modrm & 7); @@ -3212,7 +3306,9 @@ static void gen_sse(DisasContext *s, int case 0x17f: /* movdqa ea, xmm */ case 0x27f: /* movdqu ea, xmm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | (OT_QUAD + 1)); gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); @@ -3222,7 +3318,9 @@ static void gen_sse(DisasContext *s, int break; case 0x211: /* movss ea, xmm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_LONG); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); gen_op_st_T0_A0(OT_LONG + s->mem_index); } else { @@ -3233,7 +3331,9 @@ static void gen_sse(DisasContext *s, int break; case 0x311: /* movsd ea, xmm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); @@ -3244,7 +3344,9 @@ static void gen_sse(DisasContext *s, int case 0x013: /* movlps */ case 0x113: /* movlpd */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { goto illegal_op; @@ -3253,7 +3355,9 @@ static void gen_sse(DisasContext *s, int case 0x017: /* movhps */ case 0x117: /* movhpd */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); } else { goto illegal_op; @@ -3313,7 +3417,9 @@ static void gen_sse(DisasContext *s, int case 0x12a: /* cvtpi2pd */ tcg_gen_helper_0_0(helper_enter_mmx); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); op2_offset = offsetof(CPUX86State,mmx_t0); gen_ldq_env_A0(s->mem_index, op2_offset); } else { @@ -3353,7 +3459,9 @@ static void gen_sse(DisasContext *s, int case 0x12d: /* cvtpd2pi */ tcg_gen_helper_0_0(helper_enter_mmx); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | (OT_QUAD + 1)); op2_offset = offsetof(CPUX86State,xmm_t0); gen_ldo_env_A0(s->mem_index, op2_offset); } else { @@ -3384,10 +3492,14 @@ static void gen_sse(DisasContext *s, int case 0x32d: /* cvtsd2si */ ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if ((b >> 8) & 1) { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_Q(0))); } else { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0))); } @@ -3443,7 +3555,9 @@ static void gen_sse(DisasContext *s, int break; case 0x1d6: /* movq ea, xmm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); @@ -3499,20 +3613,26 @@ static void gen_sse(DisasContext *s, int if (is_xmm) { op1_offset = offsetof(CPUX86State,xmm_regs[reg]); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); op2_offset = offsetof(CPUX86State,xmm_t0); if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) || b == 0xc2)) { /* specific case for SSE single instructions */ if (b1 == 2) { /* 32 bit access */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0))); } else { /* 64 bit access */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_D(0))); } } else { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | (OT_QUAD + 1)); gen_ldo_env_A0(s->mem_index, op2_offset); } } else { @@ -3522,7 +3642,9 @@ static void gen_sse(DisasContext *s, int } else { op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); op2_offset = offsetof(CPUX86State,mmx_t0); gen_ldq_env_A0(s->mem_index, op2_offset); } else { @@ -3597,7 +3719,7 @@ static target_ulong disas_insn(DisasCont { int b, prefixes, aflag, dflag; int shift, ot; - int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; + int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val, seg_reg; target_ulong next_eip, tval; int rex_w, rex_r; @@ -3762,7 +3884,10 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ((op == OP_CMPL) ? ACC_READ : ACC_WRITE) | ot); opreg = OR_TMP0; } else if (op == OP_XORL && rm == reg) { xor_zero: @@ -3784,7 +3909,9 @@ static target_ulong disas_insn(DisasCont reg = ((modrm >> 3) & 7) | rex_r; rm = (modrm & 7) | REX_B(s); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T1_A0(ot + s->mem_index); } else if (op == OP_XORL && rm == reg) { goto xor_zero; @@ -3826,7 +3953,10 @@ static target_ulong disas_insn(DisasCont s->rip_offset = 1; else s->rip_offset = insn_const_size(ot); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ((op == OP_CMPL) ? ACC_READ : ACC_WRITE) | ot); opreg = OR_TMP0; } else { opreg = rm; @@ -3872,7 +4002,10 @@ static target_ulong disas_insn(DisasCont if (mod != 3) { if (op == 0) s->rip_offset = insn_const_size(ot); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ((op == 2 || op == 3) ? ACC_WRITE : ACC_READ) | ot); gen_op_ld_T0_A0(ot + s->mem_index); } else { gen_op_mov_TN_reg(ot, 0, rm); @@ -4118,7 +4251,10 @@ static target_ulong disas_insn(DisasCont } } if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ((op < 2) ? ACC_WRITE : ACC_READ) | ot); if (op >= 2 && op != 3 && op != 5) gen_op_ld_T0_A0(ot + s->mem_index); } else { @@ -4357,7 +4493,9 @@ static target_ulong disas_insn(DisasCont gen_op_mov_reg_T1(ot, reg); gen_op_mov_reg_T0(ot, rm); } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); gen_op_mov_TN_reg(ot, 0, reg); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_addl_T0_T1(); @@ -4389,7 +4527,9 @@ static target_ulong disas_insn(DisasCont rm = (modrm & 7) | REX_B(s); gen_op_mov_v_reg(ot, t0, rm); } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); tcg_gen_mov_tl(a0, cpu_A0); gen_op_ld_v(ot + s->mem_index, t0, a0); rm = 0; /* avoid warning */ @@ -4444,7 +4584,9 @@ static target_ulong disas_insn(DisasCont gen_jmp_im(pc_start - s->cs_base); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_BYTE); tcg_gen_helper_0_1(helper_cmpxchg8b, cpu_A0); } s->cc_op = CC_OP_EFLAGS; @@ -4614,7 +4756,9 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; if (mod != 3) { s->rip_offset = insn_const_size(ot); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); } val = insn_get(s, ot); gen_op_movl_T0_im(val); @@ -4703,7 +4847,9 @@ static target_ulong disas_insn(DisasCont } gen_op_mov_reg_T0(d_ot, reg); } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); if (b & 8) { gen_op_lds_T0_A0(ot + s->mem_index); } else { @@ -4725,7 +4871,9 @@ static target_ulong disas_insn(DisasCont s->override = -1; val = s->addseg; s->addseg = 0; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); s->addseg = val; gen_op_mov_reg_A0(ot - OT_WORD, reg); break; @@ -4756,11 +4904,15 @@ static target_ulong disas_insn(DisasCont } gen_op_movl_A0_im(offset_addr); } - gen_add_A0_ds_seg(s); + seg_reg = gen_add_A0_ds_seg(s); if ((b & 2) == 0) { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); gen_op_mov_reg_T0(ot, R_EAX); } else { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); gen_op_mov_TN_reg(ot, 0, R_EAX); gen_op_st_T0_A0(ot + s->mem_index); } @@ -4785,7 +4937,9 @@ static target_ulong disas_insn(DisasCont else tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); } - gen_add_A0_ds_seg(s); + seg_reg = gen_add_A0_ds_seg(s); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_BYTE); gen_op_ldu_T0_A0(OT_BYTE + s->mem_index); gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; @@ -4837,7 +4991,9 @@ static target_ulong disas_insn(DisasCont gen_op_mov_reg_T0(ot, rm); gen_op_mov_reg_T1(ot, reg); } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); gen_op_mov_TN_reg(ot, 0, reg); /* for xchg, lock is implicit */ if (!(prefixes & PREFIX_LOCK)) @@ -4874,7 +5030,10 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_READ, + (1 << ot) + 2); gen_op_ld_T1_A0(ot + s->mem_index); gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ @@ -4909,7 +5068,9 @@ static target_ulong disas_insn(DisasCont if (shift == 2) { s->rip_offset = 1; } - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); opreg = OR_TMP0; } else { opreg = (modrm & 7) | REX_B(s); @@ -4959,7 +5120,9 @@ static target_ulong disas_insn(DisasCont rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); opreg = OR_TMP0; } else { opreg = rm; @@ -4990,7 +5153,7 @@ static target_ulong disas_insn(DisasCont op = ((b & 7) << 3) | ((modrm >> 3) & 7); if (mod != 3) { /* memory op */ - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); switch(op) { case 0x00 ... 0x07: /* fxxxs */ case 0x10 ... 0x17: /* fixxxl */ @@ -5002,22 +5165,34 @@ static target_ulong disas_insn(DisasCont switch(op >> 4) { case 0: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_flds_FT0, cpu_tmp2_i32); break; case 1: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fildl_FT0, cpu_tmp2_i32); break; case 2: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_READ | OT_QUAD); tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); tcg_gen_helper_0_1(helper_fldl_FT0, cpu_tmp1_i64); break; case 3: default: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_READ | OT_WORD); gen_op_lds_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fildl_FT0, cpu_tmp2_i32); @@ -5041,22 +5216,34 @@ static target_ulong disas_insn(DisasCont case 0: switch(op >> 4) { case 0: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_flds_ST0, cpu_tmp2_i32); break; case 1: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fildl_ST0, cpu_tmp2_i32); break; case 2: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_READ | OT_QUAD); tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); tcg_gen_helper_0_1(helper_fldl_ST0, cpu_tmp1_i64); break; case 3: default: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_READ | OT_WORD); gen_op_lds_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fildl_ST0, cpu_tmp2_i32); @@ -5067,17 +5254,26 @@ static target_ulong disas_insn(DisasCont /* XXX: the corresponding CPUID bit must be tested ! */ switch(op >> 4) { case 1: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_WRITE | OT_LONG); tcg_gen_helper_1_0(helper_fisttl_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 2: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_WRITE | OT_QUAD); tcg_gen_helper_1_0(helper_fisttll_ST0, cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); break; case 3: default: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_WRITE | OT_WORD); tcg_gen_helper_1_0(helper_fistt_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); @@ -5088,22 +5284,34 @@ static target_ulong disas_insn(DisasCont default: switch(op >> 4) { case 0: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_WRITE | OT_LONG); tcg_gen_helper_1_0(helper_fsts_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 1: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_WRITE | OT_LONG); tcg_gen_helper_1_0(helper_fistl_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 2: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_WRITE | OT_QUAD); tcg_gen_helper_1_0(helper_fstl_ST0, cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); break; case 3: default: + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, + ACC_WRITE | OT_WORD); tcg_gen_helper_1_0(helper_fist_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); @@ -5115,6 +5323,9 @@ static target_ulong disas_insn(DisasCont } break; case 0x0c: /* fldenv mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_READ, + (s->dflag) ? 28 : 14); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5122,11 +5333,16 @@ static target_ulong disas_insn(DisasCont cpu_A0, tcg_const_i32(s->dflag)); break; case 0x0d: /* fldcw mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_WORD); gen_op_ld_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fldcw, cpu_tmp2_i32); break; case 0x0e: /* fnstenv mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_WRITE, + (s->dflag) ? 28 : 14); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5134,17 +5350,23 @@ static target_ulong disas_insn(DisasCont cpu_A0, tcg_const_i32(s->dflag)); break; case 0x0f: /* fnstcw mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_WORD); tcg_gen_helper_1_0(helper_fnstcw, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x1d: /* fldt mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_READ, 10); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); tcg_gen_helper_0_1(helper_fldt_ST0, cpu_A0); break; case 0x1f: /* fstpt mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_WRITE, 10); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5152,6 +5374,9 @@ static target_ulong disas_insn(DisasCont tcg_gen_helper_0_0(helper_fpop); break; case 0x2c: /* frstor mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_WRITE, + (s->dflag) ? 108 : 94); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5159,6 +5384,9 @@ static target_ulong disas_insn(DisasCont cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2e: /* fnsave mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_WRITE, + (s->dflag) ? 108 : 94); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5166,17 +5394,23 @@ static target_ulong disas_insn(DisasCont cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2f: /* fnstsw mem */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_WORD); tcg_gen_helper_1_0(helper_fnstsw, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x3c: /* fbld */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_READ, 10); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); tcg_gen_helper_0_1(helper_fbld_ST0, cpu_A0); break; case 0x3e: /* fbstp */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_WRITE, 10); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5184,11 +5418,15 @@ static target_ulong disas_insn(DisasCont tcg_gen_helper_0_0(helper_fpop); break; case 0x3d: /* fildll */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_QUAD); tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); tcg_gen_helper_0_1(helper_fildll_ST0, cpu_tmp1_i64); break; case 0x3f: /* fistpll */ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_QUAD); tcg_gen_helper_1_0(helper_fistll_ST0, cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); @@ -5734,6 +5972,8 @@ static target_ulong disas_insn(DisasCont tcg_const_i32(val)); } else { gen_stack_A0(s); + if (seg_checks) + gen_check_segmented_access(R_SS, ACC_READ | (OT_LONG + s->dflag)); /* pop offset */ gen_op_ld_T0_A0(1 + s->dflag + s->mem_index); if (s->dflag == 0) @@ -5870,7 +6110,9 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; t0 = tcg_temp_local_new(TCG_TYPE_TL); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); } else { rm = (modrm & 7) | REX_B(s); @@ -6012,7 +6254,9 @@ static target_ulong disas_insn(DisasCont rm = (modrm & 7) | REX_B(s); if (mod != 3) { s->rip_offset = 1; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); gen_op_ld_T0_A0(ot + s->mem_index); } else { gen_op_mov_TN_reg(ot, 0, rm); @@ -6043,7 +6287,9 @@ static target_ulong disas_insn(DisasCont rm = (modrm & 7) | REX_B(s); gen_op_mov_TN_reg(OT_LONG, 1, reg); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); /* specific case: we need to add a displacement */ gen_exts(ot, cpu_T[1]); tcg_gen_sari_tl(cpu_tmp0, cpu_T[1], 3 + ot); @@ -6272,7 +6518,9 @@ static target_ulong disas_insn(DisasCont if (mod == 3) goto illegal_op; gen_op_mov_TN_reg(ot, 0, reg); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | (ot + 1)); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); if (ot == OT_WORD) @@ -6553,7 +6801,10 @@ static target_ulong disas_insn(DisasCont if (mod == 3) goto illegal_op; gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_WRITE, + CODE64(s) ? 10 : 6); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.limit)); gen_op_st_T0_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); @@ -6602,7 +6853,10 @@ static target_ulong disas_insn(DisasCont } } else { /* sidt */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_WRITE, + CODE64(s) ? 10 : 6); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.limit)); gen_op_st_T0_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); @@ -6708,7 +6962,10 @@ static target_ulong disas_insn(DisasCont } else { gen_svm_check_intercept(s, pc_start, op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_READ, + CODE64(s) ? 10 : 6); gen_op_ld_T1_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); gen_op_ld_T0_A0(CODE64(s) + OT_LONG + s->mem_index); @@ -6824,7 +7081,9 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; rm = modrm & 7; if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | ot); gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); } else { gen_op_mov_v_reg(ot, t0, rm); @@ -7013,7 +7272,9 @@ static target_ulong disas_insn(DisasCont gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_WRITE, 512); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -7028,7 +7289,9 @@ static target_ulong disas_insn(DisasCont gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access_size(seg_reg, ACC_READ, 512); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -7044,11 +7307,15 @@ static target_ulong disas_insn(DisasCont if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK) || mod == 3) goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (op == 2) { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr)); } else { + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(seg_reg, ACC_WRITE | OT_LONG); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr)); gen_op_st_T0_A0(OT_LONG + s->mem_index); } Index: b/vl.c =================================================================== --- a/vl.c +++ b/vl.c @@ -198,6 +198,7 @@ CharDriverState *serial_hds[MAX_SERIAL_P CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; #ifdef TARGET_I386 int win2k_install_hack = 0; +int seg_checks = 0; #endif int usb_enabled = 0; static VLANState *first_vlan; @@ -7434,6 +7435,7 @@ static void help(int exitcode) "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" "-no-acpi disable ACPI\n" + "-seg-checks enable runtime segment access checks\n" #endif #ifdef CONFIG_CURSES "-curses use a curses/ncurses interface instead of SDL\n" @@ -7495,6 +7497,7 @@ enum { QEMU_OPTION_snapshot, #ifdef TARGET_I386 QEMU_OPTION_no_fd_bootchk, + QEMU_OPTION_seg_checks, #endif QEMU_OPTION_m, QEMU_OPTION_nographic, @@ -7588,6 +7591,7 @@ const QEMUOption qemu_options[] = { { "snapshot", 0, QEMU_OPTION_snapshot }, #ifdef TARGET_I386 { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk }, + { "seg-checks", 0, QEMU_OPTION_seg_checks }, #endif { "m", HAS_ARG, QEMU_OPTION_m }, { "nographic", 0, QEMU_OPTION_nographic }, @@ -8383,6 +8387,9 @@ int main(int argc, char **argv) case QEMU_OPTION_kernel_kqemu: kqemu_allowed = 2; break; + case QEMU_OPTION_seg_checks: + seg_checks = 1; + break; #endif case QEMU_OPTION_usb: usb_enabled = 1; Index: b/target-i386/helper.h =================================================================== --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -218,4 +218,9 @@ DEF_HELPER(target_ulong, helper_rclq, (t DEF_HELPER(target_ulong, helper_rcrq, (target_ulong t0, target_ulong t1)) #endif +DEF_HELPER(void, helper_check_segmented_access, (target_ulong a0, + int seg_reg, int type)) +DEF_HELPER(void, helper_check_segmented_access_size, (target_ulong a0, + int seg_reg, int type, int size)) + #undef DEF_HELPER Index: b/target-i386/op_helper.c =================================================================== --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -2231,6 +2231,65 @@ void helper_load_seg(int seg_reg, int se } } +static void log_seg_violation(target_ulong a0, int seg_reg, int type, int size) +{ + static const char *seg_name[] = { "ES", "CS", "SS", "DS", "FS", "GS" }; + + fprintf(logfile, "segment violation: %s %d byte via %s from %x:" + TARGET_FMT_lx ", base " TARGET_FMT_lx ", limit %x, " + "flags %x\n", + (type & ACC_WRITE) ? "write" : "read", size, seg_name[seg_reg], + env->segs[seg_reg].selector, a0 - env->segs[seg_reg].base, + env->segs[seg_reg].base, env->segs[seg_reg].limit, + env->segs[seg_reg].flags); +} + +void helper_check_segmented_access_size(target_ulong a0, int seg_reg, + int type, int size) +{ + int seg_type = env->segs[seg_reg].flags & 0x1F00; + target_long addr = a0 - env->segs[seg_reg].base; + + if (!(env->cr[0] & CR0_PE_MASK) || (env->hflags & HF_CS64_MASK)) + return; + + if (!(seg_type & 0x1000)) { + if (loglevel & CPU_LOG_INT) + log_seg_violation(a0, seg_reg, type, size); + raise_exception(EXCP0D_GPF); + } + + if (type & ACC_WRITE) { + if (seg_type & 0x0800 || !(seg_type & 0x0200)) { + if (loglevel & CPU_LOG_INT) + log_seg_violation(a0, seg_reg, type, size); + raise_exception(EXCP0D_GPF); + } + } else { + if (seg_type & 0x0800 && !(seg_type & 0x0200)) { + if (loglevel & CPU_LOG_INT) + log_seg_violation(a0, seg_reg, type, size); + raise_exception(EXCP0D_GPF); + } + } + + if (((seg_type & 0x0C00) == 0x0400 + && (addr > (((env->segs[seg_reg].flags & 0x400000) ? + 0xFFFFFFFF : 0xFFFF) - size) + || addr <= env->segs[seg_reg].limit)) + || addr > env->segs[seg_reg].limit - size) { + if (loglevel & CPU_LOG_INT) + log_seg_violation(a0, seg_reg, type, size); + raise_exception(EXCP0D_GPF); + } +} + +void helper_check_segmented_access(target_ulong a0, int seg_reg, int type) +{ + helper_check_segmented_access_size(a0, seg_reg, type, + (1 << (type & 0xFF)) - 1); +} + /* protected mode jump */ void helper_ljmp_protected(int new_cs, target_ulong new_eip, int next_eip_addend) ^ permalink raw reply [flat|nested] 13+ messages in thread
* [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-09 12:12 [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks Jan Kiszka @ 2008-07-14 10:34 ` Jan Kiszka 2008-07-14 10:55 ` Jamie Lokier 2008-07-14 11:05 ` [Qemu-devel] " Daniel P. Berrange 0 siblings, 2 replies; 13+ messages in thread From: Jan Kiszka @ 2008-07-14 10:34 UTC (permalink / raw) To: qemu-devel This is the second version of my segment type and register check. It reduces the impact on the translator code significantly, and it also fixes a bug of the "size" helper variant in the previous version. The idea of this patch is to generate calls to a check helper only in case the user requested this support via "-seg-checks". This feature remains off by default as most x86 OSes do not care about protection via segmentation anymore (and it was even removed from 64-bit modes by the CPU vendors). Moreover, checking the segment type and limit on every memory access is nothing that makes QEMU faster, so you will only want this if you are looking for very accurate emulation. On Fabrice's request I tried to find the conditions which allow enabling -seg-checks by default but kicking it out most of the time during code translation. That works for 64-bit mode, of course, but I still see no clear indication for the case that 32-bit guests are not interested in type checking specifically. If you see one, let me know. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> --- target-i386/cpu.h | 8 + target-i386/helper.h | 3 target-i386/op_helper.c | 50 ++++++++ target-i386/translate.c | 299 ++++++++++++++++++++++++++++++++++++------------ vl.c | 7 + 5 files changed, 296 insertions(+), 71 deletions(-) Index: b/target-i386/cpu.h =================================================================== --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -94,6 +94,10 @@ #define DESC_TSS_BUSY_MASK (1 << 9) +/* flags for segment access checks */ +#define ACC_READ 0x0000 +#define ACC_WRITE 0x0100 + /* eflags masks */ #define CC_C 0x0001 #define CC_P 0x0004 @@ -751,6 +755,10 @@ static inline void cpu_clone_regs(CPUSta env->regs[R_ESP] = newsp; env->regs[R_EAX] = 0; } + +#define seg_checks 0 +#else +extern int seg_checks; #endif #define CPU_PC_FROM_TB(env, tb) env->eip = tb->pc - tb->cs_base Index: b/target-i386/translate.c =================================================================== --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -591,7 +591,7 @@ static inline void gen_jmp_im(target_ulo tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, eip)); } -static inline void gen_string_movl_A0_ESI(DisasContext *s) +static inline int gen_string_movl_A0_ESI(DisasContext *s) { int override; @@ -604,6 +604,7 @@ static inline void gen_string_movl_A0_ES } else { gen_op_movq_A0_reg(R_ESI); } + return -1; } else #endif if (s->aflag) { @@ -615,6 +616,7 @@ static inline void gen_string_movl_A0_ES gen_op_addl_A0_reg_sN(0, R_ESI); } else { gen_op_movl_A0_reg(R_ESI); + return R_DS; } } else { /* 16 address, always override */ @@ -624,13 +626,15 @@ static inline void gen_string_movl_A0_ES gen_op_andl_A0_ffff(); gen_op_addl_A0_seg(override); } + return override; } -static inline void gen_string_movl_A0_EDI(DisasContext *s) +static inline int gen_string_movl_A0_EDI(DisasContext *s) { #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_movq_A0_reg(R_EDI); + return -1; } else #endif if (s->aflag) { @@ -645,6 +649,7 @@ static inline void gen_string_movl_A0_ED gen_op_andl_A0_ffff(); gen_op_addl_A0_seg(R_ES); } + return R_ES; } static inline void gen_op_movl_T0_Dshift(int ot) @@ -752,11 +757,38 @@ static void gen_check_io(DisasContext *s } } +static void gen_check_segmented_access(DisasContext *s, int seg_reg, int type, + int size) +{ + if (!s->pe || CODE64(s)) + return; + tcg_gen_helper_0_4(helper_check_segmented_access, cpu_A0, + tcg_const_i32(seg_reg), tcg_const_i32(type), + tcg_const_i32(size)); +} + +static inline void gen_check_seg_access(DisasContext *s, int seg_reg, int type) +{ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(s, seg_reg, type, 1 << (type & 0xFF)); +} + +static inline void gen_check_seg_access_size(DisasContext *s, int seg_reg, + int type, int size) +{ + if (seg_checks && seg_reg >= 0) + gen_check_segmented_access(s, seg_reg, type, size); +} + static inline void gen_movs(DisasContext *s, int ot) { - gen_string_movl_A0_ESI(s); + int seg_reg; + + seg_reg = gen_string_movl_A0_ESI(s); + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); gen_op_st_T0_A0(ot + s->mem_index); gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_ESI); @@ -1165,8 +1197,11 @@ static int gen_jz_ecx_string(DisasContex static inline void gen_stos(DisasContext *s, int ot) { + int seg_reg; + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); gen_op_st_T0_A0(ot + s->mem_index); gen_op_movl_T0_Dshift(ot); gen_op_add_reg_T0(s->aflag, R_EDI); @@ -1174,7 +1209,10 @@ static inline void gen_stos(DisasContext static inline void gen_lods(DisasContext *s, int ot) { - gen_string_movl_A0_ESI(s); + int seg_reg; + + seg_reg = gen_string_movl_A0_ESI(s); + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); gen_op_mov_reg_T0(ot, R_EAX); gen_op_movl_T0_Dshift(ot); @@ -1183,8 +1221,11 @@ static inline void gen_lods(DisasContext static inline void gen_scas(DisasContext *s, int ot) { + int seg_reg; + gen_op_mov_TN_reg(OT_LONG, 0, R_EAX); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_cmpl_T0_T1_cc(); gen_op_movl_T0_Dshift(ot); @@ -1193,9 +1234,13 @@ static inline void gen_scas(DisasContext static inline void gen_cmps(DisasContext *s, int ot) { - gen_string_movl_A0_ESI(s); + int seg_reg; + + seg_reg = gen_string_movl_A0_ESI(s); + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_cmpl_T0_T1_cc(); gen_op_movl_T0_Dshift(ot); @@ -1205,9 +1250,12 @@ static inline void gen_cmps(DisasContext static inline void gen_ins(DisasContext *s, int ot) { + int seg_reg; + if (use_icount) gen_io_start(); - gen_string_movl_A0_EDI(s); + seg_reg = gen_string_movl_A0_EDI(s); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); /* Note: we must do this dummy write first to be restartable in case of page fault. */ gen_op_movl_T0_0(); @@ -1225,9 +1273,12 @@ static inline void gen_ins(DisasContext static inline void gen_outs(DisasContext *s, int ot) { + int seg_reg; + if (use_icount) gen_io_start(); - gen_string_movl_A0_ESI(s); + seg_reg = gen_string_movl_A0_ESI(s); + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); gen_op_mov_TN_reg(OT_WORD, 1, R_EDX); @@ -1882,7 +1933,7 @@ static void gen_shifti(DisasContext *s1, } } -static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) +static int gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) { target_long disp; int havesib; @@ -2064,6 +2115,7 @@ static void gen_lea_modrm(DisasContext * disp = 0; *reg_ptr = opreg; *offset_ptr = disp; + return override; } static void gen_nop_modrm(DisasContext *s, int modrm) @@ -2117,11 +2169,10 @@ static void gen_nop_modrm(DisasContext * } /* used for LEA and MOV AX, mem */ -static void gen_add_A0_ds_seg(DisasContext *s) +static int gen_add_A0_ds_seg(DisasContext *s) { int override, must_add_seg; must_add_seg = s->addseg; - override = R_DS; if (s->override >= 0) { override = s->override; must_add_seg = 1; @@ -2138,13 +2189,14 @@ static void gen_add_A0_ds_seg(DisasConte gen_op_addl_A0_seg(override); } } + return override; } /* generate modrm memory load or store of 'reg'. TMP0 is used if reg != OR_TMP0 */ static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store) { - int mod, rm, opreg, disp; + int mod, rm, opreg, disp, seg_reg; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); @@ -2159,12 +2211,14 @@ static void gen_ldst_modrm(DisasContext gen_op_mov_reg_T0(ot, reg); } } else { - gen_lea_modrm(s, modrm, &opreg, &disp); + seg_reg = gen_lea_modrm(s, modrm, &opreg, &disp); if (is_store) { + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); if (reg != OR_TMP0) gen_op_mov_TN_reg(ot, 0, reg); gen_op_st_T0_A0(ot + s->mem_index); } else { + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); if (reg != OR_TMP0) gen_op_mov_reg_T0(ot, reg); @@ -2398,6 +2452,7 @@ static void gen_push_T0(DisasContext *s) tcg_gen_mov_tl(cpu_T[1], cpu_A0); gen_op_addl_A0_seg(R_SS); } + gen_check_seg_access(s, R_SS, ACC_WRITE | (OT_WORD + s->dflag)); gen_op_st_T0_A0(s->dflag + 1 + s->mem_index); if (s->ss32 && !s->addseg) gen_op_mov_reg_A0(1, R_ESP); @@ -2437,6 +2492,7 @@ static void gen_push_T1(DisasContext *s) gen_op_andl_A0_ffff(); gen_op_addl_A0_seg(R_SS); } + gen_check_seg_access(s, R_SS, ACC_WRITE | (OT_WORD + s->dflag)); gen_op_st_T1_A0(s->dflag + 1 + s->mem_index); if (s->ss32 && !s->addseg) @@ -2464,6 +2520,7 @@ static void gen_pop_T0(DisasContext *s) gen_op_andl_A0_ffff(); gen_op_addl_A0_seg(R_SS); } + gen_check_seg_access(s, R_SS, ACC_READ | (OT_WORD + s->dflag)); gen_op_ld_T0_A0(s->dflag + 1 + s->mem_index); } } @@ -2501,6 +2558,7 @@ static void gen_pusha(DisasContext *s) tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) gen_op_addl_A0_seg(R_SS); + gen_check_seg_access(s, R_SS, ACC_WRITE | (OT_WORD + s->dflag + 3)); for(i = 0;i < 8; i++) { gen_op_mov_TN_reg(OT_LONG, 0, 7 - i); gen_op_st_T0_A0(OT_WORD + s->dflag + s->mem_index); @@ -2520,6 +2578,7 @@ static void gen_popa(DisasContext *s) tcg_gen_addi_tl(cpu_T[1], cpu_T[1], 16 << s->dflag); if (s->addseg) gen_op_addl_A0_seg(R_SS); + gen_check_seg_access(s, R_SS, ACC_READ | (OT_WORD + s->dflag + 3)); for(i = 0;i < 8; i++) { /* ESP is not reloaded */ if (i != 3) { @@ -2571,6 +2630,7 @@ static void gen_enter(DisasContext *s, i tcg_gen_mov_tl(cpu_T[1], cpu_A0); if (s->addseg) gen_op_addl_A0_seg(R_SS); + gen_check_seg_access(s, R_SS, ACC_WRITE | ot); /* push bp */ gen_op_mov_TN_reg(OT_LONG, 0, R_EBP); gen_op_st_T0_A0(ot + s->mem_index); @@ -2924,7 +2984,7 @@ static void *sse_op_table5[256] = { static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) { int b1, op1_offset, op2_offset, is_xmm, val, ot; - int modrm, mod, rm, reg, reg_addr, offset_addr; + int seg_reg, modrm, mod, rm, reg, reg_addr, offset_addr; void *sse_op2; b &= 0xff; @@ -2990,7 +3050,8 @@ static void gen_sse(DisasContext *s, int case 0x0e7: /* movntq */ if (mod == 3) goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); break; case 0x1e7: /* movntdq */ @@ -2999,7 +3060,8 @@ static void gen_sse(DisasContext *s, int case 0x3f0: /* lddqu */ if (mod == 3) goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, 16); gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); break; case 0x6e: /* movd mm, ea */ @@ -3035,7 +3097,8 @@ static void gen_sse(DisasContext *s, int break; case 0x6f: /* movq mm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); } else { rm = (modrm & 7); @@ -3052,7 +3115,8 @@ static void gen_sse(DisasContext *s, int case 0x16f: /* movdqa xmm, ea */ case 0x26f: /* movdqu xmm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_READ, 16); gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); @@ -3062,7 +3126,8 @@ static void gen_sse(DisasContext *s, int break; case 0x210: /* movss xmm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); gen_op_movl_T0_0(); @@ -3077,7 +3142,8 @@ static void gen_sse(DisasContext *s, int break; case 0x310: /* movsd xmm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); gen_op_movl_T0_0(); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); @@ -3091,7 +3157,8 @@ static void gen_sse(DisasContext *s, int case 0x012: /* movlps */ case 0x112: /* movlpd */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { /* movhlps */ @@ -3102,7 +3169,8 @@ static void gen_sse(DisasContext *s, int break; case 0x212: /* movsldup */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_READ, 16); gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); @@ -3118,7 +3186,8 @@ static void gen_sse(DisasContext *s, int break; case 0x312: /* movddup */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); @@ -3131,7 +3200,8 @@ static void gen_sse(DisasContext *s, int case 0x016: /* movhps */ case 0x116: /* movhpd */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); } else { /* movlhps */ @@ -3142,7 +3212,8 @@ static void gen_sse(DisasContext *s, int break; case 0x216: /* movshdup */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_READ, 16); gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); @@ -3186,7 +3257,8 @@ static void gen_sse(DisasContext *s, int break; case 0x27e: /* movq xmm, ea */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); @@ -3197,7 +3269,8 @@ static void gen_sse(DisasContext *s, int break; case 0x7f: /* movq ea, mm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx)); } else { rm = (modrm & 7); @@ -3212,7 +3285,8 @@ static void gen_sse(DisasContext *s, int case 0x17f: /* movdqa ea, xmm */ case 0x27f: /* movdqu ea, xmm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, 16); gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); } else { rm = (modrm & 7) | REX_B(s); @@ -3222,7 +3296,8 @@ static void gen_sse(DisasContext *s, int break; case 0x211: /* movss ea, xmm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_LONG); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); gen_op_st_T0_A0(OT_LONG + s->mem_index); } else { @@ -3233,7 +3308,8 @@ static void gen_sse(DisasContext *s, int break; case 0x311: /* movsd ea, xmm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); @@ -3244,7 +3320,8 @@ static void gen_sse(DisasContext *s, int case 0x013: /* movlps */ case 0x113: /* movlpd */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { goto illegal_op; @@ -3253,7 +3330,8 @@ static void gen_sse(DisasContext *s, int case 0x017: /* movhps */ case 0x117: /* movhpd */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); } else { goto illegal_op; @@ -3313,7 +3391,8 @@ static void gen_sse(DisasContext *s, int case 0x12a: /* cvtpi2pd */ tcg_gen_helper_0_0(helper_enter_mmx); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); op2_offset = offsetof(CPUX86State,mmx_t0); gen_ldq_env_A0(s->mem_index, op2_offset); } else { @@ -3353,7 +3432,8 @@ static void gen_sse(DisasContext *s, int case 0x12d: /* cvtpd2pi */ tcg_gen_helper_0_0(helper_enter_mmx); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_READ, 16); op2_offset = offsetof(CPUX86State,xmm_t0); gen_ldo_env_A0(s->mem_index, op2_offset); } else { @@ -3384,10 +3464,12 @@ static void gen_sse(DisasContext *s, int case 0x32d: /* cvtsd2si */ ot = (s->dflag == 2) ? OT_QUAD : OT_LONG; if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if ((b >> 8) & 1) { + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_Q(0))); } else { + gen_check_seg_access(s, seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0))); } @@ -3443,7 +3525,8 @@ static void gen_sse(DisasContext *s, int break; case 0x1d6: /* movq ea, xmm */ if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); } else { rm = (modrm & 7) | REX_B(s); @@ -3499,20 +3582,23 @@ static void gen_sse(DisasContext *s, int if (is_xmm) { op1_offset = offsetof(CPUX86State,xmm_regs[reg]); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); op2_offset = offsetof(CPUX86State,xmm_t0); if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) || b == 0xc2)) { /* specific case for SSE single instructions */ if (b1 == 2) { /* 32 bit access */ + gen_check_seg_access(s, seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0))); } else { /* 64 bit access */ + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_D(0))); } } else { + gen_check_seg_access_size(s, seg_reg, ACC_READ, 16); gen_ldo_env_A0(s->mem_index, op2_offset); } } else { @@ -3522,7 +3608,8 @@ static void gen_sse(DisasContext *s, int } else { op1_offset = offsetof(CPUX86State,fpregs[reg].mmx); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); op2_offset = offsetof(CPUX86State,mmx_t0); gen_ldq_env_A0(s->mem_index, op2_offset); } else { @@ -3597,7 +3684,7 @@ static target_ulong disas_insn(DisasCont { int b, prefixes, aflag, dflag; int shift, ot; - int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; + int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val, seg_reg; target_ulong next_eip, tval; int rex_w, rex_r; @@ -3762,7 +3849,9 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, + ((op == OP_CMPL) ? ACC_READ : ACC_WRITE) | ot); opreg = OR_TMP0; } else if (op == OP_XORL && rm == reg) { xor_zero: @@ -3784,7 +3873,8 @@ static target_ulong disas_insn(DisasCont reg = ((modrm >> 3) & 7) | rex_r; rm = (modrm & 7) | REX_B(s); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T1_A0(ot + s->mem_index); } else if (op == OP_XORL && rm == reg) { goto xor_zero; @@ -3826,7 +3916,9 @@ static target_ulong disas_insn(DisasCont s->rip_offset = 1; else s->rip_offset = insn_const_size(ot); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, + ((op == OP_CMPL) ? ACC_READ : ACC_WRITE) | ot); opreg = OR_TMP0; } else { opreg = rm; @@ -3872,7 +3964,9 @@ static target_ulong disas_insn(DisasCont if (mod != 3) { if (op == 0) s->rip_offset = insn_const_size(ot); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, + ((op == 2 || op == 3) ? ACC_WRITE : ACC_READ) | ot); gen_op_ld_T0_A0(ot + s->mem_index); } else { gen_op_mov_TN_reg(ot, 0, rm); @@ -4118,7 +4212,9 @@ static target_ulong disas_insn(DisasCont } } if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, + ((op < 2) ? ACC_WRITE : ACC_READ) | ot); if (op >= 2 && op != 3 && op != 5) gen_op_ld_T0_A0(ot + s->mem_index); } else { @@ -4357,7 +4453,8 @@ static target_ulong disas_insn(DisasCont gen_op_mov_reg_T1(ot, reg); gen_op_mov_reg_T0(ot, rm); } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); gen_op_mov_TN_reg(ot, 0, reg); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_addl_T0_T1(); @@ -4389,7 +4486,8 @@ static target_ulong disas_insn(DisasCont rm = (modrm & 7) | REX_B(s); gen_op_mov_v_reg(ot, t0, rm); } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); tcg_gen_mov_tl(a0, cpu_A0); gen_op_ld_v(ot + s->mem_index, t0, a0); rm = 0; /* avoid warning */ @@ -4444,7 +4542,8 @@ static target_ulong disas_insn(DisasCont gen_jmp_im(pc_start - s->cs_base); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_BYTE); tcg_gen_helper_0_1(helper_cmpxchg8b, cpu_A0); } s->cc_op = CC_OP_EFLAGS; @@ -4614,7 +4713,8 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; if (mod != 3) { s->rip_offset = insn_const_size(ot); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); } val = insn_get(s, ot); gen_op_movl_T0_im(val); @@ -4703,7 +4803,8 @@ static target_ulong disas_insn(DisasCont } gen_op_mov_reg_T0(d_ot, reg); } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | ot); if (b & 8) { gen_op_lds_T0_A0(ot + s->mem_index); } else { @@ -4725,7 +4826,8 @@ static target_ulong disas_insn(DisasCont s->override = -1; val = s->addseg; s->addseg = 0; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); s->addseg = val; gen_op_mov_reg_A0(ot - OT_WORD, reg); break; @@ -4756,11 +4858,13 @@ static target_ulong disas_insn(DisasCont } gen_op_movl_A0_im(offset_addr); } - gen_add_A0_ds_seg(s); + seg_reg = gen_add_A0_ds_seg(s); if ((b & 2) == 0) { + gen_check_seg_access(s, seg_reg, ACC_READ | ot); gen_op_ld_T0_A0(ot + s->mem_index); gen_op_mov_reg_T0(ot, R_EAX); } else { + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); gen_op_mov_TN_reg(ot, 0, R_EAX); gen_op_st_T0_A0(ot + s->mem_index); } @@ -4785,7 +4889,8 @@ static target_ulong disas_insn(DisasCont else tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff); } - gen_add_A0_ds_seg(s); + seg_reg = gen_add_A0_ds_seg(s); + gen_check_seg_access(s, seg_reg, ACC_READ | OT_BYTE); gen_op_ldu_T0_A0(OT_BYTE + s->mem_index); gen_op_mov_reg_T0(OT_BYTE, R_EAX); break; @@ -4837,7 +4942,8 @@ static target_ulong disas_insn(DisasCont gen_op_mov_reg_T0(ot, rm); gen_op_mov_reg_T1(ot, reg); } else { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); gen_op_mov_TN_reg(ot, 0, reg); /* for xchg, lock is implicit */ if (!(prefixes & PREFIX_LOCK)) @@ -4874,7 +4980,8 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; if (mod == 3) goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_READ, (1 << ot) + 2); gen_op_ld_T1_A0(ot + s->mem_index); gen_add_A0_im(s, 1 << (ot - OT_WORD + 1)); /* load the segment first to handle exceptions properly */ @@ -4909,7 +5016,8 @@ static target_ulong disas_insn(DisasCont if (shift == 2) { s->rip_offset = 1; } - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); opreg = OR_TMP0; } else { opreg = (modrm & 7) | REX_B(s); @@ -4959,7 +5067,8 @@ static target_ulong disas_insn(DisasCont rm = (modrm & 7) | REX_B(s); reg = ((modrm >> 3) & 7) | rex_r; if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); opreg = OR_TMP0; } else { opreg = rm; @@ -4990,7 +5099,7 @@ static target_ulong disas_insn(DisasCont op = ((b & 7) << 3) | ((modrm >> 3) & 7); if (mod != 3) { /* memory op */ - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); switch(op) { case 0x00 ... 0x07: /* fxxxs */ case 0x10 ... 0x17: /* fixxxl */ @@ -5002,22 +5111,26 @@ static target_ulong disas_insn(DisasCont switch(op >> 4) { case 0: + gen_check_seg_access(s, seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_flds_FT0, cpu_tmp2_i32); break; case 1: + gen_check_seg_access(s, seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fildl_FT0, cpu_tmp2_i32); break; case 2: + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); tcg_gen_helper_0_1(helper_fldl_FT0, cpu_tmp1_i64); break; case 3: default: + gen_check_seg_access(s, seg_reg, ACC_READ | OT_WORD); gen_op_lds_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fildl_FT0, cpu_tmp2_i32); @@ -5041,22 +5154,26 @@ static target_ulong disas_insn(DisasCont case 0: switch(op >> 4) { case 0: + gen_check_seg_access(s, seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_flds_ST0, cpu_tmp2_i32); break; case 1: + gen_check_seg_access(s, seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fildl_ST0, cpu_tmp2_i32); break; case 2: + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); tcg_gen_helper_0_1(helper_fldl_ST0, cpu_tmp1_i64); break; case 3: default: + gen_check_seg_access(s, seg_reg, ACC_READ | OT_WORD); gen_op_lds_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fildl_ST0, cpu_tmp2_i32); @@ -5067,17 +5184,20 @@ static target_ulong disas_insn(DisasCont /* XXX: the corresponding CPUID bit must be tested ! */ switch(op >> 4) { case 1: + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_LONG); tcg_gen_helper_1_0(helper_fisttl_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 2: + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); tcg_gen_helper_1_0(helper_fisttll_ST0, cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); break; case 3: default: + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_WORD); tcg_gen_helper_1_0(helper_fistt_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); @@ -5088,22 +5208,26 @@ static target_ulong disas_insn(DisasCont default: switch(op >> 4) { case 0: + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_LONG); tcg_gen_helper_1_0(helper_fsts_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 1: + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_LONG); tcg_gen_helper_1_0(helper_fistl_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_LONG + s->mem_index); break; case 2: + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); tcg_gen_helper_1_0(helper_fstl_ST0, cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); break; case 3: default: + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_WORD); tcg_gen_helper_1_0(helper_fist_ST0, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); @@ -5115,6 +5239,8 @@ static target_ulong disas_insn(DisasCont } break; case 0x0c: /* fldenv mem */ + gen_check_seg_access_size(s, seg_reg, ACC_READ, + (s->dflag) ? 28 : 14); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5122,11 +5248,14 @@ static target_ulong disas_insn(DisasCont cpu_A0, tcg_const_i32(s->dflag)); break; case 0x0d: /* fldcw mem */ + gen_check_seg_access(s, seg_reg, ACC_READ | OT_WORD); gen_op_ld_T0_A0(OT_WORD + s->mem_index); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); tcg_gen_helper_0_1(helper_fldcw, cpu_tmp2_i32); break; case 0x0e: /* fnstenv mem */ + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, + (s->dflag) ? 28 : 14); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5134,17 +5263,20 @@ static target_ulong disas_insn(DisasCont cpu_A0, tcg_const_i32(s->dflag)); break; case 0x0f: /* fnstcw mem */ + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_WORD); tcg_gen_helper_1_0(helper_fnstcw, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x1d: /* fldt mem */ + gen_check_seg_access_size(s, seg_reg, ACC_READ, 10); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); tcg_gen_helper_0_1(helper_fldt_ST0, cpu_A0); break; case 0x1f: /* fstpt mem */ + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, 10); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5152,6 +5284,8 @@ static target_ulong disas_insn(DisasCont tcg_gen_helper_0_0(helper_fpop); break; case 0x2c: /* frstor mem */ + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, + (s->dflag) ? 108 : 94); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5159,6 +5293,8 @@ static target_ulong disas_insn(DisasCont cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2e: /* fnsave mem */ + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, + (s->dflag) ? 108 : 94); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5166,17 +5302,20 @@ static target_ulong disas_insn(DisasCont cpu_A0, tcg_const_i32(s->dflag)); break; case 0x2f: /* fnstsw mem */ + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_WORD); tcg_gen_helper_1_0(helper_fnstsw, cpu_tmp2_i32); tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32); gen_op_st_T0_A0(OT_WORD + s->mem_index); break; case 0x3c: /* fbld */ + gen_check_seg_access_size(s, seg_reg, ACC_READ, 10); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); tcg_gen_helper_0_1(helper_fbld_ST0, cpu_A0); break; case 0x3e: /* fbstp */ + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, 10); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -5184,11 +5323,13 @@ static target_ulong disas_insn(DisasCont tcg_gen_helper_0_0(helper_fpop); break; case 0x3d: /* fildll */ + gen_check_seg_access(s, seg_reg, ACC_READ | OT_QUAD); tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); tcg_gen_helper_0_1(helper_fildll_ST0, cpu_tmp1_i64); break; case 0x3f: /* fistpll */ + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_QUAD); tcg_gen_helper_1_0(helper_fistll_ST0, cpu_tmp1_i64); tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, (s->mem_index >> 2) - 1); @@ -5734,6 +5875,7 @@ static target_ulong disas_insn(DisasCont tcg_const_i32(val)); } else { gen_stack_A0(s); + gen_check_seg_access(s, R_SS, ACC_READ | (OT_LONG + s->dflag)); /* pop offset */ gen_op_ld_T0_A0(1 + s->dflag + s->mem_index); if (s->dflag == 0) @@ -5870,7 +6012,8 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; t0 = tcg_temp_local_new(TCG_TYPE_TL); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); } else { rm = (modrm & 7) | REX_B(s); @@ -6012,7 +6155,8 @@ static target_ulong disas_insn(DisasCont rm = (modrm & 7) | REX_B(s); if (mod != 3) { s->rip_offset = 1; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); gen_op_ld_T0_A0(ot + s->mem_index); } else { gen_op_mov_TN_reg(ot, 0, rm); @@ -6043,7 +6187,8 @@ static target_ulong disas_insn(DisasCont rm = (modrm & 7) | REX_B(s); gen_op_mov_TN_reg(OT_LONG, 1, reg); if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); /* specific case: we need to add a displacement */ gen_exts(ot, cpu_T[1]); tcg_gen_sari_tl(cpu_tmp0, cpu_T[1], 3 + ot); @@ -6272,7 +6417,8 @@ static target_ulong disas_insn(DisasCont if (mod == 3) goto illegal_op; gen_op_mov_TN_reg(ot, 0, reg); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_READ | (ot + 1)); gen_jmp_im(pc_start - s->cs_base); tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]); if (ot == OT_WORD) @@ -6553,7 +6699,9 @@ static target_ulong disas_insn(DisasCont if (mod == 3) goto illegal_op; gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, + CODE64(s) ? 10 : 6); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.limit)); gen_op_st_T0_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); @@ -6602,7 +6750,9 @@ static target_ulong disas_insn(DisasCont } } else { /* sidt */ gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, + CODE64(s) ? 10 : 6); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.limit)); gen_op_st_T0_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); @@ -6708,7 +6858,9 @@ static target_ulong disas_insn(DisasCont } else { gen_svm_check_intercept(s, pc_start, op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE); - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_READ, + CODE64(s) ? 10 : 6); gen_op_ld_T1_A0(OT_WORD + s->mem_index); gen_add_A0_im(s, 2); gen_op_ld_T0_A0(CODE64(s) + OT_LONG + s->mem_index); @@ -6824,7 +6976,8 @@ static target_ulong disas_insn(DisasCont mod = (modrm >> 6) & 3; rm = modrm & 7; if (mod != 3) { - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access(s, seg_reg, ACC_WRITE | ot); gen_op_ld_v(ot + s->mem_index, t0, cpu_A0); } else { gen_op_mov_v_reg(ot, t0, rm); @@ -7013,7 +7166,8 @@ static target_ulong disas_insn(DisasCont gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_WRITE, 512); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -7028,7 +7182,8 @@ static target_ulong disas_insn(DisasCont gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_check_seg_access_size(s, seg_reg, ACC_READ, 512); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); @@ -7044,11 +7199,13 @@ static target_ulong disas_insn(DisasCont if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK) || mod == 3) goto illegal_op; - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + seg_reg = gen_lea_modrm(s, modrm, ®_addr, &offset_addr); if (op == 2) { + gen_check_seg_access(s, seg_reg, ACC_READ | OT_LONG); gen_op_ld_T0_A0(OT_LONG + s->mem_index); tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr)); } else { + gen_check_seg_access(s, seg_reg, ACC_WRITE | OT_LONG); tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr)); gen_op_st_T0_A0(OT_LONG + s->mem_index); } Index: b/vl.c =================================================================== --- a/vl.c +++ b/vl.c @@ -198,6 +198,7 @@ CharDriverState *serial_hds[MAX_SERIAL_P CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; #ifdef TARGET_I386 int win2k_install_hack = 0; +int seg_checks = 0; #endif int usb_enabled = 0; static VLANState *first_vlan; @@ -7434,6 +7435,7 @@ static void help(int exitcode) "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" "-no-acpi disable ACPI\n" + "-seg-checks enable runtime segment access checks\n" #endif #ifdef CONFIG_CURSES "-curses use a curses/ncurses interface instead of SDL\n" @@ -7495,6 +7497,7 @@ enum { QEMU_OPTION_snapshot, #ifdef TARGET_I386 QEMU_OPTION_no_fd_bootchk, + QEMU_OPTION_seg_checks, #endif QEMU_OPTION_m, QEMU_OPTION_nographic, @@ -7588,6 +7591,7 @@ const QEMUOption qemu_options[] = { { "snapshot", 0, QEMU_OPTION_snapshot }, #ifdef TARGET_I386 { "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk }, + { "seg-checks", 0, QEMU_OPTION_seg_checks }, #endif { "m", HAS_ARG, QEMU_OPTION_m }, { "nographic", 0, QEMU_OPTION_nographic }, @@ -8383,6 +8387,9 @@ int main(int argc, char **argv) case QEMU_OPTION_kernel_kqemu: kqemu_allowed = 2; break; + case QEMU_OPTION_seg_checks: + seg_checks = 1; + break; #endif case QEMU_OPTION_usb: usb_enabled = 1; Index: b/target-i386/helper.h =================================================================== --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -218,4 +218,7 @@ DEF_HELPER(target_ulong, helper_rclq, (t DEF_HELPER(target_ulong, helper_rcrq, (target_ulong t0, target_ulong t1)) #endif +DEF_HELPER(void, helper_check_segmented_access, (target_ulong a0, + int seg_reg, int type, int size)) + #undef DEF_HELPER Index: b/target-i386/op_helper.c =================================================================== --- a/target-i386/op_helper.c +++ b/target-i386/op_helper.c @@ -2231,6 +2231,56 @@ void helper_load_seg(int seg_reg, int se } } +static void log_seg_violation(target_ulong a0, int seg_reg, int type, int size) +{ + static const char *seg_name[] = { "ES", "CS", "SS", "DS", "FS", "GS" }; + + fprintf(logfile, "segment violation: %s %d byte via %s from %x:" + TARGET_FMT_lx ", base " TARGET_FMT_lx ", limit %x, " + "flags %x\n", + (type & ACC_WRITE) ? "write" : "read", size, seg_name[seg_reg], + env->segs[seg_reg].selector, a0 - env->segs[seg_reg].base, + env->segs[seg_reg].base, env->segs[seg_reg].limit, + env->segs[seg_reg].flags); +} + +void helper_check_segmented_access(target_ulong a0, int seg_reg, int type, + int size) +{ + int seg_type = env->segs[seg_reg].flags & 0x1F00; + target_long addr = a0 - env->segs[seg_reg].base; + + if (!(seg_type & 0x1000)) { + if (loglevel & CPU_LOG_INT) + log_seg_violation(a0, seg_reg, type, size); + raise_exception(EXCP0D_GPF); + } + + if (type & ACC_WRITE) { + if (seg_type & 0x0800 || !(seg_type & 0x0200)) { + if (loglevel & CPU_LOG_INT) + log_seg_violation(a0, seg_reg, type, size); + raise_exception(EXCP0D_GPF); + } + } else { + if (seg_type & 0x0800 && !(seg_type & 0x0200)) { + if (loglevel & CPU_LOG_INT) + log_seg_violation(a0, seg_reg, type, size); + raise_exception(EXCP0D_GPF); + } + } + + if (((seg_type & 0x0C00) == 0x0400 + && (addr > (((env->segs[seg_reg].flags & 0x400000) ? + 0xFFFFFFFF : 0xFFFF) - (size - 1)) + || addr <= env->segs[seg_reg].limit)) + || addr > env->segs[seg_reg].limit - (size - 1)) { + if (loglevel & CPU_LOG_INT) + log_seg_violation(a0, seg_reg, type, size); + raise_exception(EXCP0D_GPF); + } +} + /* protected mode jump */ void helper_ljmp_protected(int new_cs, target_ulong new_eip, int next_eip_addend) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-14 10:34 ` [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 Jan Kiszka @ 2008-07-14 10:55 ` Jamie Lokier 2008-07-14 11:11 ` Paul Brook 2008-07-14 11:05 ` [Qemu-devel] " Daniel P. Berrange 1 sibling, 1 reply; 13+ messages in thread From: Jamie Lokier @ 2008-07-14 10:55 UTC (permalink / raw) To: qemu-devel Jan Kiszka wrote: > This is the second version of my segment type and register check. It > reduces the impact on the translator code significantly, and it also > fixes a bug of the "size" helper variant in the previous version. > > The idea of this patch is to generate calls to a check helper only in > case the user requested this support via "-seg-checks". This feature > remains off by default as most x86 OSes do not care about protection via > segmentation anymore (and it was even removed from 64-bit modes by the > CPU vendors). Moreover, checking the segment type and limit on every > memory access is nothing that makes QEMU faster, so you will only want > this if you are looking for very accurate emulation. > > On Fabrice's request I tried to find the conditions which allow enabling > -seg-checks by default but kicking it out most of the time during code > translation. That works for 64-bit mode, of course, but I still see no > clear indication for the case that 32-bit guests are not interested in > type checking specifically. If you see one, let me know. Some 32-bit guests effectively disable segment range calculations checks by setting the maximum limit and zero offset. Apparently, this is faster on some real CPUs too. Could type checking be done at translation time, including the segment types in the translation cache key? For guests like older Linux, with zero base and non-maximum limit in user mode, could limit checking be done by the MMU TLB instead? -- Jamie ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-14 10:55 ` Jamie Lokier @ 2008-07-14 11:11 ` Paul Brook 2008-07-14 14:02 ` Jamie Lokier 0 siblings, 1 reply; 13+ messages in thread From: Paul Brook @ 2008-07-14 11:11 UTC (permalink / raw) To: qemu-devel > Some 32-bit guests effectively disable segment range calculations > checks by setting the maximum limit and zero offset. Apparently, this > is faster on some real CPUs too. > > Could type checking be done at translation time, including the segment > types in the translation cache key? Maybe. If we have a spare hflags bit you could probably use that to indicate whether segment limit checks are needed. > For guests like older Linux, with zero base and non-maximum limit in > user mode, could limit checking be done by the MMU TLB instead? Not really. The only resonable way to do this would be to use a very large virtual address space, with the high bits being the segment descriptor. This might work for 32-bit targets on 64-bit hosts, but even then it's liable to be more pain than it's worth. Paul ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-14 11:11 ` Paul Brook @ 2008-07-14 14:02 ` Jamie Lokier 2008-07-14 17:50 ` Kevin O'Connor 0 siblings, 1 reply; 13+ messages in thread From: Jamie Lokier @ 2008-07-14 14:02 UTC (permalink / raw) To: Paul Brook; +Cc: qemu-devel Paul Brook wrote: > > For guests like older Linux, with zero base and non-maximum limit in > > user mode, could limit checking be done by the MMU TLB instead? > > Not really. The only resonable way to do this would be to use a very > large virtual address space, with the high bits being the segment > descriptor. This might work for 32-bit targets on 64-bit hosts, but > even then it's liable to be more pain than it's worth. I was thinking more like this, on any host: - All segment bases are zero, and all limits are LIMIT (3GiB for old Linux in user mode). - When filling the MMU TLB, if it's for an address >= LIMIT, treat as MMU exception. - Flush MMU TLB on any interesting segment change (limit gets smaller, etc.). - Count rate of interesting segment changes. When it's high, switch to including segment checks in translated code (same as non-zero bases) and not flushing TLB. When it's low, don't put segment checks into translated code, and use TLB flushes on segment changes. - Keep separate count for ring 0 and ring 3, or for "code which uses segment prefixes" vs "code which doesn't". This would suit old Linux, as kernel code uses segment to limit copy-from/to-user range, but user code has no segment changes normally, and the user limit check is equivalent to forcing all MMU pages above that virtual address to be supervisor-only. -- Jamie ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-14 14:02 ` Jamie Lokier @ 2008-07-14 17:50 ` Kevin O'Connor 2008-07-14 18:51 ` Jamie Lokier 0 siblings, 1 reply; 13+ messages in thread From: Kevin O'Connor @ 2008-07-14 17:50 UTC (permalink / raw) To: qemu-devel Hi Jamie, On Mon, Jul 14, 2008 at 03:02:38PM +0100, Jamie Lokier wrote: > Paul Brook wrote: > > > For guests like older Linux, with zero base and non-maximum limit in > > > user mode, could limit checking be done by the MMU TLB instead? > > > > Not really. The only resonable way to do this would be to use a very > > large virtual address space, with the high bits being the segment > > descriptor. This might work for 32-bit targets on 64-bit hosts, but > > even then it's liable to be more pain than it's worth. > > I was thinking more like this, on any host: > > - All segment bases are zero, and all limits are LIMIT > (3GiB for old Linux in user mode). > - When filling the MMU TLB, if it's for an address >= LIMIT, > treat as MMU exception. That's interesting. If I understand correctly, you're suggesting using segment checks in translated code if any segment has a non-zero base or a different size limit. Thus limiting the optimization to those (common) cases where the limits and bases are all the same. Presumably this would also require LIMIT to be page aligned. One could probably allow ES, FS, and GS to have different bases/limits as long as their ranges all fit within the primary range (0..LIMIT of CS, DS, and SS). It should be okay to always emit segment checks for accesses that use these segments as they should be pretty rare. Would this still work in 32bit flat mode? > - Flush MMU TLB on any interesting segment change (limit gets > smaller, etc.). > - Count rate of interesting segment changes. When it's high, > switch to including segment checks in translated code (same as > non-zero bases) and not flushing TLB. When it's low, don't put > segment checks into translated code, and use TLB flushes on > segment changes. > - Keep separate count for ring 0 and ring 3, or for > "code which uses segment prefixes" vs "code which doesn't". Why are the heuristics needed? I wonder if the tlb flush could just be optimized. One would only need to flush the tlb when transitioning from "segment checks in translated code" mode to "segment checks in mmu" mode, or when directly going to a new LIMIT. In these cases one could just flush NEWLIMIT..OLDLIMIT. -Kevin ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-14 17:50 ` Kevin O'Connor @ 2008-07-14 18:51 ` Jamie Lokier 2008-07-15 15:48 ` [Qemu-devel] " Jan Kiszka 0 siblings, 1 reply; 13+ messages in thread From: Jamie Lokier @ 2008-07-14 18:51 UTC (permalink / raw) To: Kevin O'Connor; +Cc: qemu-devel Kevin O'Connor wrote: > > - All segment bases are zero, and all limits are LIMIT > > (3GiB for old Linux in user mode). > > - When filling the MMU TLB, if it's for an address >= LIMIT, > > treat as MMU exception. > > That's interesting. > > If I understand correctly, you're suggesting using segment checks in > translated code if any segment has a non-zero base or a different size > limit. Thus limiting the optimization to those (common) cases where > the limits and bases are all the same. Presumably this would also > require LIMIT to be page aligned. Yes. I hadn't thought of non-zero bases, but that would work too. Base and limit have to be page aligned. The only code where that isn't true is likely 16 bit MS-DOS and Windows code, which being designed for much slower processes, should be fine with fully inlined segment checks anyway. > One could probably allow ES, FS, and GS to have different bases/limits > as long as their ranges all fit within the primary range (0..LIMIT of > CS, DS, and SS). You could also translate just the base offset adding, in cases where the limit covers the whole 4GiB. But that adds more translation key bits. It's probably worth including ES as a "primary" segment like DS. > It should be okay to always emit segment checks for > accesses that use these segments as they should be pretty rare. In Windows, and modern Linux, %fs or %gs are used in userspace code for thread-specific variables. In older Linux kernels, %fs is used to copy data to/from userspace memory. Maybe the translated checks for these are not enough overhead to matter? > Would this still work in 32bit flat mode? It will if QEMU's MMU TLB is always used, and uses an identity mapping. I'm not familiar with that part of QEMU, but I had the impression it's always used as it also traps memory-mapped I/O. In which case, it should work in 16 bit flat mode too :) > > - Flush MMU TLB on any interesting segment change (limit gets > > smaller, etc.). > > - Count rate of interesting segment changes. When it's high, > > switch to including segment checks in translated code (same as > > non-zero bases) and not flushing TLB. When it's low, don't put > > segment checks into translated code, and use TLB flushes on > > segment changes. > > - Keep separate count for ring 0 and ring 3, or for > > "code which uses segment prefixes" vs "code which doesn't". > > Why are the heuristics needed? I wonder if the tlb flush could just > be optimized. Even if TLB flush itself is fast, you need to refill the TLB entries on subsequent memory accesses. It's good to avoid TLB flushes for that reason. I'm thinking of code like this from Linux which does movl %fs:(%eax),%ebx movl %ebx,(%ecx) I.e. rapidly switching between segments with different limits, and the %ds accesses are to addresses forbidden by %fs. If you're inlining %fs segment checks, though, then no TLB flush will be needed. > One would only need to flush the tlb when transitioning from "segment > checks in translated code" mode to "segment checks in mmu" mode, or > when directly going to a new LIMIT. In these cases one could just > flush NEWLIMIT..OLDLIMIT. That's true, you could optimise the flush in other ways too, such as when changing protection ring, just flush certain types of TLB entry. Or even keep multiple TLBs on the go, hashed on mostly-constant values like the translation cache, and the TLB choice being a translation cache key so it can be inlined into translated code. I didn't want to overcomplicate the suggestion, but you seem to like funky optimisations :-) -- Jamie ^ permalink raw reply [flat|nested] 13+ messages in thread
* [Qemu-devel] Re: [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-14 18:51 ` Jamie Lokier @ 2008-07-15 15:48 ` Jan Kiszka 2008-07-15 16:12 ` Jamie Lokier 2008-07-16 1:20 ` Kevin O'Connor 0 siblings, 2 replies; 13+ messages in thread From: Jan Kiszka @ 2008-07-15 15:48 UTC (permalink / raw) To: qemu-devel Jamie Lokier wrote: > Kevin O'Connor wrote: >>> - All segment bases are zero, and all limits are LIMIT >>> (3GiB for old Linux in user mode). >>> - When filling the MMU TLB, if it's for an address >= LIMIT, >>> treat as MMU exception. >> That's interesting. >> >> If I understand correctly, you're suggesting using segment checks in >> translated code if any segment has a non-zero base or a different size >> limit. Thus limiting the optimization to those (common) cases where >> the limits and bases are all the same. Presumably this would also >> require LIMIT to be page aligned. > > Yes. I hadn't thought of non-zero bases, but that would work too. > Base and limit have to be page aligned. The only code where that > isn't true is likely 16 bit MS-DOS and Windows code, which being > designed for much slower processes, should be fine with fully inlined > segment checks anyway. > >> One could probably allow ES, FS, and GS to have different bases/limits >> as long as their ranges all fit within the primary range (0..LIMIT of >> CS, DS, and SS). > > You could also translate just the base offset adding, in cases where > the limit covers the whole 4GiB. But that adds more translation key > bits. > > It's probably worth including ES as a "primary" segment like DS. > >> It should be okay to always emit segment checks for >> accesses that use these segments as they should be pretty rare. > > In Windows, and modern Linux, %fs or %gs are used in userspace code > for thread-specific variables. In older Linux kernels, %fs is used to > copy data to/from userspace memory. Maybe the translated checks for > these are not enough overhead to matter? > >> Would this still work in 32bit flat mode? > > It will if QEMU's MMU TLB is always used, and uses an identity > mapping. I'm not familiar with that part of QEMU, but I had the > impression it's always used as it also traps memory-mapped I/O. > > In which case, it should work in 16 bit flat mode too :) > >>> - Flush MMU TLB on any interesting segment change (limit gets >>> smaller, etc.). >>> - Count rate of interesting segment changes. When it's high, >>> switch to including segment checks in translated code (same as >>> non-zero bases) and not flushing TLB. When it's low, don't put >>> segment checks into translated code, and use TLB flushes on >>> segment changes. >>> - Keep separate count for ring 0 and ring 3, or for >>> "code which uses segment prefixes" vs "code which doesn't". >> Why are the heuristics needed? I wonder if the tlb flush could just >> be optimized. > > Even if TLB flush itself is fast, you need to refill the TLB entries > on subsequent memory accesses. It's good to avoid TLB flushes for > that reason. > > I'm thinking of code like this from Linux which does > > movl %fs:(%eax),%ebx > movl %ebx,(%ecx) > > I.e. rapidly switching between segments with different limits, and the > %ds accesses are to addresses forbidden by %fs. If you're inlining > %fs segment checks, though, then no TLB flush will be needed. > >> One would only need to flush the tlb when transitioning from "segment >> checks in translated code" mode to "segment checks in mmu" mode, or >> when directly going to a new LIMIT. In these cases one could just >> flush NEWLIMIT..OLDLIMIT. > > That's true, you could optimise the flush in other ways too, such as > when changing protection ring, just flush certain types of TLB entry. > Or even keep multiple TLBs on the go, hashed on mostly-constant values > like the translation cache, and the TLB choice being a translation > cache key so it can be inlined into translated code. I didn't want to > overcomplicate the suggestion, but you seem to like funky optimisations :-) Don't want to stop all your creativity, but just like Paul I'm also a bit skeptical about the TLB way of achieving range and type safety. My major concern once was that the TLB works on a global scope so that you cannot tell the original segments behind some address apart. And extending the virtual address space for this is a no-go on 32-bit hosts (which I unfortunately had and still have to support here :->). Jan -- Siemens AG, Corporate Technology, CT SE 2 Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] Re: [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-15 15:48 ` [Qemu-devel] " Jan Kiszka @ 2008-07-15 16:12 ` Jamie Lokier 2008-07-16 1:20 ` Kevin O'Connor 1 sibling, 0 replies; 13+ messages in thread From: Jamie Lokier @ 2008-07-15 16:12 UTC (permalink / raw) To: qemu-devel Jan Kiszka wrote: > Don't want to stop all your creativity, but just like Paul I'm also a > bit skeptical about the TLB way of achieving range and type safety. Sure, that's understandable. There has to be some "show me the code" - I wish I had the time. These are not simple optimisations, but they could make segment checks free for most guests, so it's worth considering them even if they're discarded. > My major concern once was that the TLB works on a global scope so that > you cannot tell the original segments behind some address apart. Yes. The only way around it is context - either having multiple TLBs, or inlining segments into translated code, so you tell the original segments apart at the call site. > And extending the virtual address space for this is a no-go on > 32-bit hosts (which I unfortunately had and still have to support > here :->). Definitely not increasing the virtual address space - I'm still using 32-bit hosts too :-) I'm not sure that would be safe even on 64-bit hosts - what if the guest has its own uses for the whole address space? Expanding the TLB key space (or equivalently, multiple TLBs) is different from expanding the virtual address space, though. -- Jamie ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] Re: [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-15 15:48 ` [Qemu-devel] " Jan Kiszka 2008-07-15 16:12 ` Jamie Lokier @ 2008-07-16 1:20 ` Kevin O'Connor 2008-07-16 2:43 ` Kevin O'Connor 1 sibling, 1 reply; 13+ messages in thread From: Kevin O'Connor @ 2008-07-16 1:20 UTC (permalink / raw) To: qemu-devel; +Cc: Jan Kiszka Hi Jan, On Tue, Jul 15, 2008 at 05:48:23PM +0200, Jan Kiszka wrote: > > Kevin O'Connor wrote: > >>Thus limiting the optimization to those (common) cases where > >> the limits and bases are all the same. > >> One could probably allow ES, FS, and GS to have different bases/limits > >> as long as their ranges all fit within the primary range (0..LIMIT of > >> CS, DS, and SS). > >> It should be okay to always emit segment checks for > >> accesses that use these segments as they should be pretty rare. [...] > Don't want to stop all your creativity, but just like Paul I'm also a > bit skeptical about the TLB way of achieving range and type safety. > > My major concern once was that the TLB works on a global scope so that > you cannot tell the original segments behind some address apart. If all five segments have the same base and limit (0..LIMIT) then I would think it would not matter what segment filled a TLB. (It should not be possible to fill a TLB outside of 0..LIMIT, and any access to a tlb in 0..LIMIT should be okay regardless of the segment used.) Of course, it's not uncommon for FS and GS to have a different base. In this case, it should still be safe as long as FS/GS don't allow access outside of 0..LIMIT (so that invalid TLBs don't get loaded) and one emits limit checks on each FS/GS use (so that the limits on FS/GS are enforced). Qemu already has an optimization (HF_ADDSEG_MASK) for the case where DS/ES/SS all have a zero base. I was thinking that an optimization could noticeably reduce the cost of limit checks for the common case where DS/ES/SS all have a zero base and the same limit. (I incorrectly stated CS/DS/SS above.) Of course, it would require a lot of work, and it would be hard to verify that all the corner cases were handled. So, I was more thinking out loud than proposing a solution. :-) >And > extending the virtual address space for this is a no-go on 32-bit hosts > (which I unfortunately had and still have to support here :->). Yeah - I wouldn't want to go there. Trying to maintain multiple TLBs or adding more bits to the TLB hash just seems silly to me. -Kevin ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] Re: [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-16 1:20 ` Kevin O'Connor @ 2008-07-16 2:43 ` Kevin O'Connor 0 siblings, 0 replies; 13+ messages in thread From: Kevin O'Connor @ 2008-07-16 2:43 UTC (permalink / raw) To: qemu-devel; +Cc: Jan Kiszka On Tue, Jul 15, 2008 at 09:20:39PM -0400, Kevin O'Connor wrote: > Qemu already has an optimization (HF_ADDSEG_MASK) for the case where > DS/ES/SS all have a zero base. I was thinking that an optimization > could noticeably reduce the cost of limit checks for the common case > where DS/ES/SS all have a zero base and the same limit. (I > incorrectly stated CS/DS/SS above.) > > Of course, it would require a lot of work, and it would be hard to > verify that all the corner cases were handled. So, I was more > thinking out loud than proposing a solution. :-) Just "thinking out loud" further - a simpler optimization would be to extend the existing HF_ADDSEG_MASK flag to the case where DS/ES/SS have a base a zero, a limit of 0xffffffff, and are read/writable. Then, one would only need to emit segment checks when one of the above conditions are not met or an explicit segment override to another segment is given. This simpler optimization would miss some opportunities, but it would be much easier. -Kevin ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-14 10:34 ` [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 Jan Kiszka 2008-07-14 10:55 ` Jamie Lokier @ 2008-07-14 11:05 ` Daniel P. Berrange 2008-07-15 15:43 ` [Qemu-devel] " Jan Kiszka 1 sibling, 1 reply; 13+ messages in thread From: Daniel P. Berrange @ 2008-07-14 11:05 UTC (permalink / raw) To: qemu-devel On Mon, Jul 14, 2008 at 12:34:48PM +0200, Jan Kiszka wrote: > This is the second version of my segment type and register check. It > reduces the impact on the translator code significantly, and it also > fixes a bug of the "size" helper variant in the previous version. > > The idea of this patch is to generate calls to a check helper only in > case the user requested this support via "-seg-checks". This feature > remains off by default as most x86 OSes do not care about protection via > segmentation anymore (and it was even removed from 64-bit modes by the > CPU vendors). Two current users of protection via segmentation I know of - 32-bit linux with the ExecShield capability will still use segmentation to split the address space into executable vs non-executable regions, if the CPU doesn't have NX bit support. - 32-bit Xen uses segmentation for protecting the hypervisor. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :| ^ permalink raw reply [flat|nested] 13+ messages in thread
* [Qemu-devel] Re: [RFC][PATCH] x86: Optional segment type and limit checks - v2 2008-07-14 11:05 ` [Qemu-devel] " Daniel P. Berrange @ 2008-07-15 15:43 ` Jan Kiszka 0 siblings, 0 replies; 13+ messages in thread From: Jan Kiszka @ 2008-07-15 15:43 UTC (permalink / raw) To: qemu-devel Daniel P. Berrange wrote: > On Mon, Jul 14, 2008 at 12:34:48PM +0200, Jan Kiszka wrote: >> This is the second version of my segment type and register check. It >> reduces the impact on the translator code significantly, and it also >> fixes a bug of the "size" helper variant in the previous version. >> >> The idea of this patch is to generate calls to a check helper only in >> case the user requested this support via "-seg-checks". This feature >> remains off by default as most x86 OSes do not care about protection via >> segmentation anymore (and it was even removed from 64-bit modes by the >> CPU vendors). > > Two current users of protection via segmentation I know of > > - 32-bit linux with the ExecShield capability will still use segmentation > to split the address space into executable vs non-executable regions, if > the CPU doesn't have NX bit support. > - 32-bit Xen uses segmentation for protecting the hypervisor. Ah, good to be reminded that we are not alone with our segmented OS here. ;) That makes me realize that my patch lacks range checks for code segments. I think I left it out as it is not that trivial... Jan -- Siemens AG, Corporate Technology, CT SE 2 Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2008-07-16 2:43 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-07-09 12:12 [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks Jan Kiszka 2008-07-14 10:34 ` [Qemu-devel] [RFC][PATCH] x86: Optional segment type and limit checks - v2 Jan Kiszka 2008-07-14 10:55 ` Jamie Lokier 2008-07-14 11:11 ` Paul Brook 2008-07-14 14:02 ` Jamie Lokier 2008-07-14 17:50 ` Kevin O'Connor 2008-07-14 18:51 ` Jamie Lokier 2008-07-15 15:48 ` [Qemu-devel] " Jan Kiszka 2008-07-15 16:12 ` Jamie Lokier 2008-07-16 1:20 ` Kevin O'Connor 2008-07-16 2:43 ` Kevin O'Connor 2008-07-14 11:05 ` [Qemu-devel] " Daniel P. Berrange 2008-07-15 15:43 ` [Qemu-devel] " Jan Kiszka
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).