Commit cd9b594a authored by Ricardo Neri's avatar Ricardo Neri Committed by Ingo Molnar

x86/insn-eval: Add wrapper function for 32 and 64-bit addresses

The function insn_get_addr_ref() is capable of handling only 64-bit
addresses. A previous commit introduced a function to handle 32-bit
addresses. Invoke these two functions from a third wrapper function that
calls the appropriate routine based on the address size specified in the
instruction structure (obtained by looking at the code segment default
address size and the address override prefix, if present).

While doing this, rename the original function insn_get_addr_ref() with
the more appropriate name get_addr_ref_64(), ensure it is only used
for 64-bit addresses.

Also, since 64-bit addresses are not possible in 32-bit builds, provide
a dummy function such case.
Signed-off-by: default avatarRicardo Neri <ricardo.neri-calderon@linux.intel.com>
Reviewed-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Adam Buchbinder <adam.buchbinder@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Borislav Petkov <bp@suse.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Chen Yucong <slaoub@gmail.com>
Cc: Chris Metcalf <cmetcalf@mellanox.com>
Cc: Colin Ian King <colin.king@canonical.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Huang Rui <ray.huang@amd.com>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Lorenzo Stoakes <lstoakes@gmail.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Paul Gortmaker <paul.gortmaker@windriver.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Qiaowei Ren <qiaowei.ren@intel.com>
Cc: Ravi V. Shankar <ravi.v.shankar@intel.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Thomas Garnier <thgarnie@google.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: ricardo.neri@intel.com
Link: http://lkml.kernel.org/r/1509935277-22138-4-git-send-email-ricardo.neri-calderon@linux.intel.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 7a6daf79
...@@ -1052,17 +1052,36 @@ static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs) ...@@ -1052,17 +1052,36 @@ static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs)
return (void __user *)linear_addr; return (void __user *)linear_addr;
} }
/* /**
* return the address being referenced be instruction * get_addr_ref_64() - Obtain a 64-bit linear address
* for rm=3 returning the content of the rm reg * @insn: Instruction struct with ModRM and SIB bytes and displacement
* for rm!=3 calculates the address using SIB and Disp * @regs: Structure with register values as seen when entering kernel mode
*
* This function is to be used with 64-bit address encodings to obtain the
* linear memory address referred by the instruction's ModRM, SIB,
* displacement bytes and segment base address, as applicable.
*
* Returns:
*
* Linear address referenced by instruction and registers on success.
*
* -1L on error.
*/ */
void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) #ifndef CONFIG_X86_64
static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs)
{
return (void __user *)-1L;
}
#else
static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs)
{ {
unsigned long linear_addr = -1L, seg_base; unsigned long linear_addr = -1L, seg_base;
int regoff, ret; int regoff, ret;
long eff_addr; long eff_addr;
if (insn->addr_bytes != 8)
goto out;
if (X86_MODRM_MOD(insn->modrm.value) == 3) { if (X86_MODRM_MOD(insn->modrm.value) == 3) {
ret = get_eff_addr_reg(insn, regs, &regoff, &eff_addr); ret = get_eff_addr_reg(insn, regs, &regoff, &eff_addr);
if (ret) if (ret)
...@@ -1090,3 +1109,34 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) ...@@ -1090,3 +1109,34 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
out: out:
return (void __user *)linear_addr; return (void __user *)linear_addr;
} }
#endif /* CONFIG_X86_64 */
/**
* insn_get_addr_ref() - Obtain the linear address referred by instruction
* @insn: Instruction structure containing ModRM byte and displacement
* @regs: Structure with register values as seen when entering kernel mode
*
* Obtain the linear address referred by the instruction's ModRM, SIB and
* displacement bytes, and segment base, as applicable. In protected mode,
* segment limits are enforced.
*
* Returns:
*
* Linear address referenced by instruction and registers on success.
*
* -1L on error.
*/
void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
{
if (!insn || !regs)
return (void __user *)-1L;
switch (insn->addr_bytes) {
case 4:
return get_addr_ref_32(insn, regs);
case 8:
return get_addr_ref_64(insn, regs);
default:
return (void __user *)-1L;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment