>>> On 08.12.16 at 17:24, <andrew.coop...@citrix.com> wrote: > On 08/12/16 11:52, Jan Beulich wrote: >> @@ -1401,14 +1401,11 @@ protmode_load_seg( >> return rc; >> } >> >> - if ( !is_x86_user_segment(seg) ) >> - { >> - /* System segments must have S flag == 0. */ >> - if ( desc.b & (1u << 12) ) >> - goto raise_exn; >> - } >> + /* System segments must have S flag == 0. */ >> + if ( is_x86_system_segment(seg) && (desc.b & (1u << 12)) ) >> + goto raise_exn; >> /* User segments must have S flag == 1. */ >> - else if ( !(desc.b & (1u << 12)) ) >> + if ( is_x86_user_segment(seg) && !(desc.b & (1u << 12)) ) >> goto raise_exn; > > This might be clearer as (and is definitely shorter as) > > /* Check .S is correct for the type of segment. */ > if ( seg != x86_seg_none && > is_x86_user_segment(seg) != (desc.b & (1u << 12)) ) > goto raise_exn;
I had it that way first, and then thought the opposite (the explicit two if()-s being more clear). I'd prefer to keep it as is, but if you feel strongly about the other variant being better, I can change it. >> @@ -1470,10 +1467,17 @@ protmode_load_seg( >> ((dpl < cpl) || (dpl < rpl)) ) >> goto raise_exn; >> break; >> + case x86_seg_none: >> + /* Non-conforming segment: check DPL against RPL and CPL. */ >> + if ( ((desc.b & (0x1c << 8)) != (0x1c << 8)) && >> + ((dpl < cpl) || (dpl < rpl)) ) >> + return X86EMUL_EXCEPTION; > > I realise it is no functional change, but it would be cleaner to have > this as a goto raise_exn, to avoid having one spurious early-exit in a > fucntion which otherwise always goes to raise_exn or done. That's a matter of taste I think - to me it seems better to make immediately obvious that no exception will be raised in this case (which "goto raise_exn" would suggest). >> /* Segment present in memory? */ >> - if ( !(desc.b & (1 << 15)) ) >> + if ( !(desc.b & (1 << 15)) && seg != x86_seg_none ) > > What is the purpose of this change, given that the raise_exn case is > always conditional on seg != x86_seg_none ? Well - we don't want to reach raise_exn in this case, i.e. we want to take the implicit "else" path. After all a clear P bit does not result in the instructions to fail. >> @@ -4424,6 +4430,28 @@ x86_emulate( >> if ( (rc = load_seg(seg, src.val, 0, NULL, ctxt, ops)) != 0 ) >> goto done; >> break; >> + case 4: /* verr / verw */ > > This looks wrong, but I see it isn't actually. Whether this patch or a > subsequent one, it would be clearer to alter the switch statement not to > mask off the bottom bit, and have individual case labels for the > instructions. Again a case where I think the masking off of the low bit is the better approach. I wouldn't object to a patch altering it, but I'm not convinced enough to put one together myself. And no, I don't think this should be done in this patch. >> + _regs.eflags &= ~EFLG_ZF; >> + switch ( rc = protmode_load_seg(x86_seg_none, src.val, false, >> + &sreg, ctxt, ops) ) >> + { >> + case X86EMUL_OKAY: >> + if ( sreg.attr.fields.s && >> + ((modrm_reg & 1) ? ((sreg.attr.fields.type & 0xa) == >> 0x2) >> + : ((sreg.attr.fields.type & 0xa) != >> 0x8)) ) >> + _regs.eflags |= EFLG_ZF; >> + break; >> + case X86EMUL_EXCEPTION: > > Could we please annotate the areas where we selectively passing > exceptions? I can see this pattern getting confusing if we don't. > Something like: > > /* #PF needs to escape. #GP should have been squashed already. */ Hmm, we're not selectively passing exceptions here; we pass any which have got raised, and #GP/#SS/#NP aren't among them. So I think the comment may rather want to be "Only #PF can come here", which then we could as well ASSERT() ... >> + if ( ctxt->event_pending ) >> + { ... here (and that would then serve as a de-facto comment). What do you think? >> @@ -4621,6 +4649,96 @@ x86_emulate( >> break; >> } >> >> + case X86EMUL_OPC(0x0f, 0x02): /* lar */ >> + generate_exception_if(!in_protmode(ctxt, ops), EXC_UD); > > As a tangential point, the distinction between the various in_*() > predicates is sufficiently subtle that I keep on having to look it up to > check. > > What do you think about replacing the current predicates with a single > mode_is() predicate which takes an or-able set of REAL|VM86|PROT|LONG > flags ? And you mean x86_decode() to set them once at its beginning? That would make e.g. read_msr() a required hook, which I don't think is a good idea (the more that x86_decode(), which in particular gets passed almost no hooks at all from x86_decode_insn(), doesn't need to know whether we're emulating long mode). If anything this would therefore need to be another input coming from the original callers (complementing addr_size and sp_size). >> + _regs.eflags &= ~EFLG_ZF; >> + switch ( rc = protmode_load_seg(x86_seg_none, src.val, false, &sreg, >> + ctxt, ops) ) >> + { >> + case X86EMUL_OKAY: >> + if ( !sreg.attr.fields.s ) >> + { >> + switch ( sreg.attr.fields.type ) >> + { >> + case 0x01: /* available 16-bit TSS */ >> + case 0x03: /* busy 16-bit TSS */ >> + case 0x04: /* 16-bit call gate */ >> + case 0x05: /* 16/32-bit task gate */ >> + if ( in_longmode(ctxt, ops) ) >> + break; >> + /* fall through */ >> + case 0x02: /* LDT */ > > According to the Intel manual, LDT is valid in protected mode, but not > valid in long mode. > > This appears to be a functional difference from AMD, who permit querying > LDT in long mode. > > I haven't checked what real hardware behaviour is. Given that Intel > documents LDT as valid for LSL, I wonder whether this is a documentation > error. I did check all this on hardware, so yes, looks to be a doc error. >> + case 0x09: /* available 32/64-bit TSS */ >> + case 0x0b: /* busy 32/64-bit TSS */ >> + case 0x0c: /* 32/64-bit call gate */ >> + _regs.eflags |= EFLG_ZF; >> + break; >> + } >> + } >> + else >> + _regs.eflags |= EFLG_ZF; >> + break; >> + case X86EMUL_EXCEPTION: >> + if ( ctxt->event_pending ) >> + { >> + default: >> + goto done; >> + } >> + /* Instead of the exception, ZF remains cleared. */ >> + rc = X86EMUL_OKAY; >> + break; >> + } >> + if ( _regs.eflags & EFLG_ZF ) >> + dst.val = ((sreg.attr.bytes & 0xff) << 8) | >> + ((sreg.limit >> (sreg.attr.fields.g ? 12 : 0)) & >> + 0xf0000) | >> + ((sreg.attr.bytes & 0xf00) << 12); > > Is this correct? The AMD manuals says for 16bit, attr & 0xff00, and for > 32 or 64bit, attr & 0xffff00. Well - as for all operations truncation to operand size will occur during writeback of dst.val to the destination register. Jan _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel