x86emul: consolidate segment register handling Use a single set of variables throughout the huge switch() statement, allowing to funnel SLDT/STR into the mov-from-sreg code path. Signed-off-by: Jan Beulich --- a/xen/arch/x86/x86_emulate/x86_emulate.c +++ b/xen/arch/x86/x86_emulate/x86_emulate.c @@ -2494,7 +2494,8 @@ x86_emulate( switch ( ctxt->opcode ) { - struct segment_register cs; + enum x86_segment seg; + struct segment_register cs, sreg; case 0x00 ... 0x05: add: /* add */ emulate_2op_SrcV("add", src, dst, _regs.eflags); @@ -2530,22 +2531,20 @@ x86_emulate( dst.type = OP_NONE; break; - case 0x06: /* push %%es */ { - struct segment_register reg; + case 0x06: /* push %%es */ src.val = x86_seg_es; push_seg: generate_exception_if(mode_64bit() && !ext, EXC_UD, -1); fail_if(ops->read_segment == NULL); - if ( (rc = ops->read_segment(src.val, ®, ctxt)) != 0 ) + if ( (rc = ops->read_segment(src.val, &sreg, ctxt)) != 0 ) goto done; /* 64-bit mode: PUSH defaults to a 64-bit operand. */ if ( mode_64bit() && (op_bytes == 4) ) op_bytes = 8; if ( (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes), - ®.sel, op_bytes, ctxt)) != 0 ) + &sreg.sel, op_bytes, ctxt)) != 0 ) goto done; break; - } case 0x07: /* pop %%es */ src.val = x86_seg_es; @@ -2861,21 +2860,20 @@ x86_emulate( dst.val = src.val; break; - case 0x8c: /* mov Sreg,r/m */ { - struct segment_register reg; - enum x86_segment seg = decode_segment(modrm_reg); + case 0x8c: /* mov Sreg,r/m */ + seg = decode_segment(modrm_reg); generate_exception_if(seg == decode_segment_failed, EXC_UD, -1); + store_seg: fail_if(ops->read_segment == NULL); - if ( (rc = ops->read_segment(seg, ®, ctxt)) != 0 ) + if ( (rc = ops->read_segment(seg, &sreg, ctxt)) != 0 ) goto done; - dst.val = reg.sel; + dst.val = sreg.sel; if ( dst.type == OP_MEM ) dst.bytes = 2; break; - } - case 0x8e: /* mov r/m,Sreg */ { - enum x86_segment seg = decode_segment(modrm_reg); + case 0x8e: /* mov r/m,Sreg */ + seg = decode_segment(modrm_reg); generate_exception_if(seg == decode_segment_failed, EXC_UD, -1); generate_exception_if(seg == x86_seg_cs, EXC_UD, -1); if ( (rc = load_seg(seg, src.val, 0, NULL, ctxt, ops)) != 0 ) @@ -2884,7 +2882,6 @@ x86_emulate( ctxt->retire.flags.mov_ss = 1; dst.type = OP_NONE; break; - } case 0x8d: /* lea */ generate_exception_if(ea.type != OP_MEM, EXC_UD, -1); @@ -2941,17 +2938,15 @@ x86_emulate( } break; - case 0x9a: /* call (far, absolute) */ { - struct segment_register reg; - + case 0x9a: /* call (far, absolute) */ ASSERT(!mode_64bit()); fail_if(ops->read_segment == NULL); - if ( (rc = ops->read_segment(x86_seg_cs, ®, ctxt)) || + if ( (rc = ops->read_segment(x86_seg_cs, &sreg, ctxt)) || (rc = load_seg(x86_seg_cs, imm2, 0, &cs, ctxt, ops)) || (validate_far_branch(&cs, imm1), rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes), - ®.sel, op_bytes, ctxt)) || + &sreg.sel, op_bytes, ctxt)) || (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes), &_regs.eip, op_bytes, ctxt)) || (rc = ops->write_segment(x86_seg_cs, &cs, ctxt)) ) @@ -2959,7 +2954,6 @@ x86_emulate( _regs.eip = imm1; break; - } case 0x9b: /* wait/fwait */ host_and_vcpu_must_have(fpu); @@ -4178,13 +4172,12 @@ x86_emulate( if ( (modrm_reg & 7) == 3 ) /* call */ { - struct segment_register reg; fail_if(ops->read_segment == NULL); - if ( (rc = ops->read_segment(x86_seg_cs, ®, ctxt)) || + if ( (rc = ops->read_segment(x86_seg_cs, &sreg, ctxt)) || (rc = load_seg(x86_seg_cs, sel, 0, &cs, ctxt, ops)) || (validate_far_branch(&cs, src.val), rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes), - ®.sel, op_bytes, ctxt)) || + &sreg.sel, op_bytes, ctxt)) || (rc = ops->write(x86_seg_ss, sp_pre_dec(op_bytes), &_regs.eip, op_bytes, ctxt)) || (rc = ops->write_segment(x86_seg_cs, &cs, ctxt)) ) @@ -4205,34 +4198,24 @@ x86_emulate( } break; - case X86EMUL_OPC(0x0f, 0x00): /* Grp6 */ { - enum x86_segment seg = (modrm_reg & 1) ? x86_seg_tr : x86_seg_ldtr; - + case X86EMUL_OPC(0x0f, 0x00): /* Grp6 */ + seg = (modrm_reg & 1) ? x86_seg_tr : x86_seg_ldtr; fail_if(modrm_reg & 4); generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1); - if ( modrm_reg & 2 ) + if ( modrm_reg & 2 ) /* lldt / ltr */ { generate_exception_if(!mode_ring0(), EXC_GP, 0); if ( (rc = load_seg(seg, src.val, 0, NULL, ctxt, ops)) != 0 ) goto done; } - else + else /* sldt / str */ { - struct segment_register reg; - generate_exception_if(is_umip(ctxt, ops), EXC_GP, 0); - fail_if(!ops->read_segment); - if ( (rc = ops->read_segment(seg, ®, ctxt)) != 0 ) - goto done; - dst.val = reg.sel; - if ( dst.type == OP_MEM ) - dst.bytes = 2; + goto store_seg; } break; - } case X86EMUL_OPC(0x0f, 0x01): /* Grp7 */ { - struct segment_register reg; unsigned long base, limit, cr0, cr0w; switch( modrm ) @@ -4322,6 +4305,8 @@ x86_emulate( } } + seg = (modrm_reg & 1) ? x86_seg_idtr : x86_seg_gdtr; + switch ( modrm_reg & 7 ) { case 0: /* sgdt */ @@ -4329,16 +4314,14 @@ x86_emulate( generate_exception_if(ea.type != OP_MEM, EXC_UD, -1); generate_exception_if(is_umip(ctxt, ops), EXC_GP, 0); fail_if(ops->read_segment == NULL); - if ( (rc = ops->read_segment((modrm_reg & 1) ? - x86_seg_idtr : x86_seg_gdtr, - ®, ctxt)) ) + if ( (rc = ops->read_segment(seg, &sreg, ctxt)) ) goto done; if ( op_bytes == 2 ) - reg.base &= 0xffffff; + sreg.base &= 0xffffff; if ( (rc = ops->write(ea.mem.seg, ea.mem.off+0, - ®.limit, 2, ctxt)) || + &sreg.limit, 2, ctxt)) || (rc = ops->write(ea.mem.seg, ea.mem.off+2, - ®.base, mode_64bit() ? 8 : 4, ctxt)) ) + &sreg.base, mode_64bit() ? 8 : 4, ctxt)) ) goto done; break; case 2: /* lgdt */ @@ -4346,19 +4329,17 @@ x86_emulate( generate_exception_if(!mode_ring0(), EXC_GP, 0); generate_exception_if(ea.type != OP_MEM, EXC_UD, -1); fail_if(ops->write_segment == NULL); - memset(®, 0, sizeof(reg)); + memset(&sreg, 0, sizeof(sreg)); if ( (rc = read_ulong(ea.mem.seg, ea.mem.off+0, &limit, 2, ctxt, ops)) || (rc = read_ulong(ea.mem.seg, ea.mem.off+2, &base, mode_64bit() ? 8 : 4, ctxt, ops)) ) goto done; - reg.base = base; - reg.limit = limit; + sreg.base = base; + sreg.limit = limit; if ( op_bytes == 2 ) - reg.base &= 0xffffff; - if ( (rc = ops->write_segment((modrm_reg & 1) ? - x86_seg_idtr : x86_seg_gdtr, - ®, ctxt)) ) + sreg.base &= 0xffffff; + if ( (rc = ops->write_segment(seg, &sreg, ctxt)) ) goto done; break; case 4: /* smsw */ @@ -4401,7 +4382,6 @@ x86_emulate( case X86EMUL_OPC(0x0f, 0x05): /* syscall */ { uint64_t msr_content; - struct segment_register cs, ss; generate_exception_if(!in_protmode(ctxt, ops), EXC_UD, -1); @@ -4415,11 +4395,11 @@ x86_emulate( goto done; cs.sel = (msr_content >> 32) & ~3; /* SELECTOR_RPL_MASK */ - ss.sel = cs.sel + 8; + sreg.sel = cs.sel + 8; - cs.base = ss.base = 0; /* flat segment */ - cs.limit = ss.limit = ~0u; /* 4GB limit */ - ss.attr.bytes = 0xc93; /* G+DB+P+S+Data */ + cs.base = sreg.base = 0; /* flat segment */ + cs.limit = sreg.limit = ~0u; /* 4GB limit */ + sreg.attr.bytes = 0xc93; /* G+DB+P+S+Data */ #ifdef __x86_64__ rc = in_longmode(ctxt, ops); @@ -4453,7 +4433,7 @@ x86_emulate( fail_if(ops->write_segment == NULL); if ( (rc = ops->write_segment(x86_seg_cs, &cs, ctxt)) || - (rc = ops->write_segment(x86_seg_ss, &ss, ctxt)) ) + (rc = ops->write_segment(x86_seg_ss, &sreg, ctxt)) ) goto done; break; @@ -4672,7 +4652,6 @@ x86_emulate( case X86EMUL_OPC(0x0f, 0x34): /* sysenter */ { uint64_t msr_content; - struct segment_register cs, ss; int lm; generate_exception_if(mode_ring0(), EXC_GP, 0); @@ -4697,14 +4676,14 @@ x86_emulate( cs.attr.bytes = lm ? 0xa9b /* L+DB+P+S+Code */ : 0xc9b; /* G+DB+P+S+Code */ - ss.sel = cs.sel + 8; - ss.base = 0; /* flat segment */ - ss.limit = ~0u; /* 4GB limit */ - ss.attr.bytes = 0xc93; /* G+DB+P+S+Data */ + sreg.sel = cs.sel + 8; + sreg.base = 0; /* flat segment */ + sreg.limit = ~0u; /* 4GB limit */ + sreg.attr.bytes = 0xc93; /* G+DB+P+S+Data */ fail_if(ops->write_segment == NULL); if ( (rc = ops->write_segment(x86_seg_cs, &cs, ctxt)) != 0 || - (rc = ops->write_segment(x86_seg_ss, &ss, ctxt)) != 0 ) + (rc = ops->write_segment(x86_seg_ss, &sreg, ctxt)) != 0 ) goto done; if ( (rc = ops->read_msr(MSR_SYSENTER_EIP, &msr_content, ctxt)) != 0 ) @@ -4720,7 +4699,6 @@ x86_emulate( case X86EMUL_OPC(0x0f, 0x35): /* sysexit */ { uint64_t msr_content; - struct segment_register cs, ss; bool_t user64 = !!(rex_prefix & REX_W); generate_exception_if(!mode_ring0(), EXC_GP, 0); @@ -4742,14 +4720,14 @@ x86_emulate( cs.attr.bytes = user64 ? 0xafb /* L+DB+P+DPL3+S+Code */ : 0xcfb; /* G+DB+P+DPL3+S+Code */ - ss.sel = cs.sel + 8; - ss.base = 0; /* flat segment */ - ss.limit = ~0u; /* 4GB limit */ - ss.attr.bytes = 0xcf3; /* G+DB+P+DPL3+S+Data */ + sreg.sel = cs.sel + 8; + sreg.base = 0; /* flat segment */ + sreg.limit = ~0u; /* 4GB limit */ + sreg.attr.bytes = 0xcf3; /* G+DB+P+DPL3+S+Data */ fail_if(ops->write_segment == NULL); if ( (rc = ops->write_segment(x86_seg_cs, &cs, ctxt)) != 0 || - (rc = ops->write_segment(x86_seg_ss, &ss, ctxt)) != 0 ) + (rc = ops->write_segment(x86_seg_ss, &sreg, ctxt)) != 0 ) goto done; _regs.eip = user64 ? _regs.edx : (uint32_t)_regs.edx;