[v6 PATCH 09/21] x86/insn-eval: Add functions to get default operand and address sizes

Ricardo Neri ricardo.neri-calderon at linux.intel.com
Wed Apr 26 20:07:40 CDT 2017


On Thu, 2017-04-20 at 15:06 +0200, Borislav Petkov wrote:
> On Tue, Mar 07, 2017 at 04:32:42PM -0800, Ricardo Neri wrote:
> > These functions read the default values of the address and operand sizes
> > as specified in the segment descriptor. This information is determined
> > from the D and L bits. Hence, it can be used for both IA-32e 64-bit and
> > 32-bit legacy modes. For virtual-8086 mode, the default address and
> > operand sizes are always 2 bytes.
> 
> Yeah, we tend to call that customarily 16-bit :)

I will call it like this.
> 
> > The D bit is only meaningful for code segments. Thus, these functions
> > always use the code segment selector contained in regs.
> > 
> > Cc: Dave Hansen <dave.hansen at linux.intel.com>
> > Cc: Adam Buchbinder <adam.buchbinder at gmail.com>
> > Cc: Colin Ian King <colin.king at canonical.com>
> > Cc: Lorenzo Stoakes <lstoakes at gmail.com>
> > Cc: Qiaowei Ren <qiaowei.ren at intel.com>
> > Cc: Arnaldo Carvalho de Melo <acme at redhat.com>
> > Cc: Masami Hiramatsu <mhiramat at kernel.org>
> > Cc: Adrian Hunter <adrian.hunter at intel.com>
> > Cc: Kees Cook <keescook at chromium.org>
> > Cc: Thomas Garnier <thgarnie at google.com>
> > Cc: Peter Zijlstra <peterz at infradead.org>
> > Cc: Borislav Petkov <bp at suse.de>
> > Cc: Dmitry Vyukov <dvyukov at google.com>
> > Cc: Ravi V. Shankar <ravi.v.shankar at intel.com>
> > Cc: x86 at kernel.org
> > Signed-off-by: Ricardo Neri <ricardo.neri-calderon at linux.intel.com>
> > ---
> >  arch/x86/include/asm/insn-eval.h |  2 +
> >  arch/x86/lib/insn-eval.c         | 80 ++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 82 insertions(+)
> > 
> > diff --git a/arch/x86/include/asm/insn-eval.h b/arch/x86/include/asm/insn-eval.h
> > index b201742..a0d81fc 100644
> > --- a/arch/x86/include/asm/insn-eval.h
> > +++ b/arch/x86/include/asm/insn-eval.h
> > @@ -15,6 +15,8 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs);
> >  int insn_get_reg_offset_modrm_rm(struct insn *insn, struct pt_regs *regs);
> >  int insn_get_reg_offset_sib_base(struct insn *insn, struct pt_regs *regs);
> >  int insn_get_reg_offset_sib_base(struct insn *insn, struct pt_regs *regs);
> > +unsigned char insn_get_seg_default_address_bytes(struct pt_regs *regs);
> > +unsigned char insn_get_seg_default_operand_bytes(struct pt_regs *regs);
> >  unsigned long insn_get_seg_base(struct pt_regs *regs, struct insn *insn,
> >  				int regoff, bool use_default_seg);
> >  
> > diff --git a/arch/x86/lib/insn-eval.c b/arch/x86/lib/insn-eval.c
> > index 383ca83..cda6c71 100644
> > --- a/arch/x86/lib/insn-eval.c
> > +++ b/arch/x86/lib/insn-eval.c
> > @@ -421,6 +421,86 @@ unsigned long insn_get_seg_base(struct pt_regs *regs, struct insn *insn,
> >  }
> >  
> >  /**
> > + * insn_get_seg_default_address_bytes - Obtain default address size of segment
> > + * @regs:	Set of registers containing the segment selector
> > + *
> > + * Obtain the default address size as indicated in the segment descriptor
> > + * selected in regs' code segment selector. In protected mode, the default
> > + * address is determined by inspecting the L and D bits of the segment
> > + * descriptor. In virtual-8086 mode, the default is always two bytes.
> > + *
> > + * Return: Default address size of segment
> 
> 		0 on error.
> 
> > + */
> > +unsigned char insn_get_seg_default_address_bytes(struct pt_regs *regs)
> > +{
> > +	struct desc_struct *desc;
> > +	unsigned short seg;
> > +	int ret;
> > +
> > +	if (v8086_mode(regs))
> > +		return 2;
> > +
> > +	seg = (unsigned short)regs->cs;
> > +
> > +	ret = get_desc(seg, &desc);
> > +	if (ret)
> > +		return 0;
> > +
> > +	switch ((desc->l << 1) | desc->d) {
> > +	case 0: /* Legacy mode. 16-bit addresses. CS.L=0, CS.D=0 */
> > +		return 2;
> > +	case 1: /* Legacy mode. 32-bit addresses. CS.L=0, CS.D=1 */
> > +		return 4;
> > +	case 2: /* IA-32e 64-bit mode. 64-bit addresses. CS.L=1, CS.D=0 */
> > +		return 8;
> > +	case 3: /* Invalid setting. CS.L=1, CS.D=1 */
> > +		/* fall through */
> > +	default:
> > +		return 0;
> > +	}
> > +}
> > +
> > +/**
> > + * insn_get_seg_default_operand_bytes - Obtain default operand size of segment
> > + * @regs:	Set of registers containing the segment selector
> > + *
> > + * Obtain the default operand size as indicated in the segment descriptor
> > + * selected in regs' code segment selector. In protected mode, the default
> > + * operand size is determined by inspecting the L and D bits of the segment
> > + * descriptor. In virtual-8086 mode, the default is always two bytes.
> > + *
> > + * Return: Default operand size of segment
> > + */
> > +unsigned char insn_get_seg_default_operand_bytes(struct pt_regs *regs)
> 
> Right, so default address and operand size always go together so I don't
> think you need two separate functions.
> 
> So what I'd suggest - provided this pans out (I still haven't reviewed
> the whole thing) - is to determine the operating mode of the segment:
> long, legacy, etc and then return both address and operand sizes. Patch
> 17/21 needs them both at the same time AFAICT.

It makes sense to me. So far these two functions are used in the same
place.

Thanks and BR,
Ricardo





More information about the wine-devel mailing list