Update insn-eval.c to prototype instruction decoding for MMIO VC exception exit. Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@xxxxxxx> --- tools/testing/selftests/kvm/Makefile.kvm | 12 + .../selftests/kvm/include/x86/ex_regs.h | 21 ++ .../selftests/kvm/include/x86/insn-eval.h | 48 ++++ .../selftests/kvm/include/x86/processor.h | 12 +- .../testing/selftests/kvm/lib/x86/insn-eval.c | 268 +++++++++++------- 5 files changed, 240 insertions(+), 121 deletions(-) create mode 100644 tools/testing/selftests/kvm/include/x86/ex_regs.h create mode 100644 tools/testing/selftests/kvm/include/x86/insn-eval.h diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index b4894cb56861..5a67e79ae848 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -21,6 +21,7 @@ LIBKVM_STRING += lib/string_override.c LIBKVM_x86 += lib/x86/apic.c LIBKVM_x86 += lib/x86/handlers.S LIBKVM_x86 += lib/x86/hyperv.c +LIBKVM_x86 += lib/x86/insn-eval.c LIBKVM_x86 += lib/x86/memstress.c LIBKVM_x86 += lib/x86/pmu.c LIBKVM_x86 += lib/x86/processor.c @@ -238,6 +239,17 @@ ifeq ($(ARCH),x86) ifeq ($(shell echo "void foo(void) { }" | $(CC) -march=x86-64-v2 -x c - -c -o /dev/null 2>/dev/null; echo "$$?"),0) CFLAGS += -march=x86-64-v2 endif + +tools_lib_dir := $(top_srcdir)/tools/arch/x86/lib +inat_tables_script = $(top_srcdir)/tools/arch/x86/tools/gen-insn-attr-x86.awk +inat_tables_maps = $(top_srcdir)/tools/arch/x86/lib/x86-opcode-map.txt +$(shell awk -f $(inat_tables_script) $(inat_tables_maps) > $(tools_lib_dir)/inat-tables.c) +LIBKVM_x86 += $(tools_lib_dir)/insn.c +LIBKVM_x86 += $(tools_lib_dir)/inat.c +EXTRA_CLEAN += $(tools_lib_dir)/inat-tables.c +EXTRA_CLEAN += $(tools_lib_dir)/insn.o +EXTRA_CLEAN += $(tools_lib_dir)/inat.o + endif ifeq ($(ARCH),arm64) tools_dir := $(top_srcdir)/tools diff --git a/tools/testing/selftests/kvm/include/x86/ex_regs.h b/tools/testing/selftests/kvm/include/x86/ex_regs.h new file mode 100644 index 000000000000..172cfbb0a2d0 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86/ex_regs.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2018, Google LLC. + */ + +#ifndef SELFTEST_KVM_EX_REGS_H +#define SELFTEST_KVM_EX_REG_H + +struct ex_regs { + uint64_t rax, rcx, rdx, rbx; + uint64_t rbp, rsi, rdi; + uint64_t r8, r9, r10, r11; + uint64_t r12, r13, r14, r15; + uint64_t vector; + uint64_t error_code; + uint64_t rip; + uint64_t cs; + uint64_t rflags; +}; + +#endif diff --git a/tools/testing/selftests/kvm/include/x86/insn-eval.h b/tools/testing/selftests/kvm/include/x86/insn-eval.h new file mode 100644 index 000000000000..0c7bad1c9215 --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86/insn-eval.h @@ -0,0 +1,48 @@ +#ifndef _ASM_X86_INSN_EVAL_H +#define _ASM_X86_INSN_EVAL_H +/* + * A collection of utility functions for x86 instruction analysis to be + * used in a kernel context. Useful when, for instance, making sense + * of the registers indicated by operands. + */ + +#include <stdbool.h> + +#include "ex_regs.h" + +#define INSN_CODE_SEG_ADDR_SZ(params) ((params >> 4) & 0xf) +#define INSN_CODE_SEG_OPND_SZ(params) (params & 0xf) +#define INSN_CODE_SEG_PARAMS(oper_sz, addr_sz) (oper_sz | (addr_sz << 4)) + +int ex_regs_offset(struct ex_regs *regs, int regno); + +bool insn_has_rep_prefix(struct insn *insn); +void *insn_get_addr_ref(struct insn *insn, struct ex_regs *regs); +int insn_get_modrm_rm_off(struct insn *insn, struct ex_regs *regs); +int insn_get_modrm_reg_off(struct insn *insn, struct ex_regs *regs); +unsigned long *insn_get_modrm_reg_ptr(struct insn *insn, struct ex_regs *regs); +unsigned long insn_get_seg_base(struct ex_regs *regs, int seg_reg_idx); +int insn_get_code_seg_params(struct ex_regs *regs); +int insn_get_effective_ip(struct ex_regs *regs, unsigned long *ip); +int insn_fetch_from_user(struct ex_regs *regs, + unsigned char buf[MAX_INSN_SIZE]); +int insn_fetch_from_user_inatomic(struct ex_regs *regs, + unsigned char buf[MAX_INSN_SIZE]); +bool insn_decode_from_regs(struct insn *insn, struct ex_regs *regs, + unsigned char buf[MAX_INSN_SIZE], int buf_size); + +enum insn_mmio_type { + INSN_MMIO_DECODE_FAILED, + INSN_MMIO_WRITE, + INSN_MMIO_WRITE_IMM, + INSN_MMIO_WRITE_MOV_ABS, + INSN_MMIO_READ, + INSN_MMIO_READ_ZERO_EXTEND, + INSN_MMIO_READ_SIGN_EXTEND, + INSN_MMIO_MOVS, + INSN_MMIO_READ_MOV_ABS, +}; + +enum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes); + +#endif /* _ASM_X86_INSN_EVAL_H */ diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index 56029d07680a..3f9369644962 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -1145,17 +1145,7 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits); void kvm_init_vm_address_properties(struct kvm_vm *vm); bool vm_is_unrestricted_guest(struct kvm_vm *vm); -struct ex_regs { - uint64_t rax, rcx, rdx, rbx; - uint64_t rbp, rsi, rdi; - uint64_t r8, r9, r10, r11; - uint64_t r12, r13, r14, r15; - uint64_t vector; - uint64_t error_code; - uint64_t rip; - uint64_t cs; - uint64_t rflags; -}; +#include "ex_regs.h" struct idt_entry { uint16_t offset0; diff --git a/tools/testing/selftests/kvm/lib/x86/insn-eval.c b/tools/testing/selftests/kvm/lib/x86/insn-eval.c index 98631c0e7a11..efa4d3fde504 100644 --- a/tools/testing/selftests/kvm/lib/x86/insn-eval.c +++ b/tools/testing/selftests/kvm/lib/x86/insn-eval.c @@ -3,20 +3,29 @@ * * Copyright (C) Intel Corporation 2017 */ +#ifdef __KERNEL__ #include <linux/kernel.h> #include <linux/string.h> #include <linux/ratelimit.h> #include <linux/mmu_context.h> #include <asm/desc_defs.h> #include <asm/desc.h> -#include <asm/inat.h> -#include <asm/insn.h> -#include <asm/insn-eval.h> #include <asm/ldt.h> #include <asm/vm86.h> +#else +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <errno.h> +#endif + +#include "kselftest.h" +#include "ucall_common.h" +#include <asm/inat.h> +#include <asm/insn.h> +#include "insn-eval.h" -#undef pr_fmt -#define pr_fmt(fmt) "insn: " fmt +#define CONFIG_X86_64 enum reg_type { REG_TYPE_RM = 0, @@ -140,7 +149,7 @@ static int get_seg_reg_override_idx(struct insn *insn) /** * check_seg_overrides() - check if segment override prefixes are allowed * @insn: Valid instruction with segment override prefixes - * @regoff: Operand offset, in pt_regs, for which the check is performed + * @regoff: Operand offset, in ex_regs, for which the check is performed * * For a particular register used in register-indirect addressing, determine if * segment override prefixes can be used. Specifically, no overrides are allowed @@ -153,17 +162,22 @@ static int get_seg_reg_override_idx(struct insn *insn) */ static bool check_seg_overrides(struct insn *insn, int regoff) { - if (regoff == offsetof(struct pt_regs, di) && is_string_insn(insn)) + if (regoff == offsetof(struct ex_regs, rdi) && is_string_insn(insn)) return false; return true; } +static bool any_64bit_mode(struct ex_regs *regs) +{ + return true; +} + /** * resolve_default_seg() - resolve default segment register index for an operand * @insn: Instruction with opcode and address size. Must be valid. * @regs: Register values as seen when entering kernel mode - * @off: Operand offset, in pt_regs, for which resolution is needed + * @off: Operand offset, in ex_regs, for which resolution is needed * * Resolve the default segment register index associated with the instruction * operand register indicated by @off. Such index is resolved based on defaults @@ -176,10 +190,11 @@ static bool check_seg_overrides(struct insn *insn, int regoff) * * -EINVAL in case of error. */ -static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off) +static int resolve_default_seg(struct insn *insn, struct ex_regs *regs, int off) { if (any_64bit_mode(regs)) return INAT_SEG_REG_IGNORE; +#ifndef CONFIG_X86_64 /* * Resolve the default segment register as described in Section 3.7.4 * of the Intel Software Development Manual Vol. 1: @@ -195,9 +210,9 @@ static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off) */ switch (off) { - case offsetof(struct pt_regs, ax): - case offsetof(struct pt_regs, cx): - case offsetof(struct pt_regs, dx): + case offsetof(struct ex_regs, ax): + case offsetof(struct ex_regs, cx): + case offsetof(struct ex_regs, dx): /* Need insn to verify address size. */ if (insn->addr_bytes == 2) return -EINVAL; @@ -205,32 +220,34 @@ static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off) fallthrough; case -EDOM: - case offsetof(struct pt_regs, bx): - case offsetof(struct pt_regs, si): + case offsetof(struct ex_regs, bx): + case offsetof(struct ex_regs, si): return INAT_SEG_REG_DS; - case offsetof(struct pt_regs, di): + case offsetof(struct ex_regs, di): if (is_string_insn(insn)) return INAT_SEG_REG_ES; return INAT_SEG_REG_DS; - case offsetof(struct pt_regs, bp): - case offsetof(struct pt_regs, sp): + case offsetof(struct ex_regs, bp): + case offsetof(struct ex_regs, sp): return INAT_SEG_REG_SS; - case offsetof(struct pt_regs, ip): + case offsetof(struct ex_regs, ip): return INAT_SEG_REG_CS; default: return -EINVAL; } +#endif + return -EINVAL; } /** * resolve_seg_reg() - obtain segment register index * @insn: Instruction with operands * @regs: Register values as seen when entering kernel mode - * @regoff: Operand offset, in pt_regs, used to determine segment register + * @regoff: Operand offset, in ex_regs, used to determine segment register * * Determine the segment register associated with the operands and, if * applicable, prefixes and the instruction pointed by @insn. @@ -258,7 +275,7 @@ static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off) * are done using helper functions. * * The operand register, @regoff, is represented as the offset from the base of - * pt_regs. + * ex_regs. * * As stated, the main use of this function is to determine the segment register * index based on the instruction, its operands and prefixes. Hence, @insn @@ -278,7 +295,7 @@ static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off) * * -EINVAL in case of error. */ -static int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff) +static int resolve_seg_reg(struct insn *insn, struct ex_regs *regs, int regoff) { int idx; @@ -288,7 +305,7 @@ static int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff) * be used. Hence, it is not necessary to inspect the instruction, * which may be invalid at this point. */ - if (regoff == offsetof(struct pt_regs, ip)) { + if (regoff == offsetof(struct ex_regs, rip)) { if (any_64bit_mode(regs)) return INAT_SEG_REG_IGNORE; else @@ -327,9 +344,9 @@ static int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff) * @seg_reg_idx: Segment register index to use * * Obtain the segment selector from any of the CS, SS, DS, ES, FS, GS segment - * registers. In CONFIG_X86_32, the segment is obtained from either pt_regs or + * registers. In CONFIG_X86_32, the segment is obtained from either ex_regs or * kernel_vm86_regs as applicable. In CONFIG_X86_64, CS and SS are obtained - * from pt_regs. DS, ES, FS and GS are obtained by reading the actual CPU + * from ex_regs. DS, ES, FS and GS are obtained by reading the actual CPU * registers. This done for only for completeness as in CONFIG_X86_64 segment * registers are ignored. * @@ -340,9 +357,9 @@ static int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff) * * -EINVAL on error. */ -static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx) +static short get_segment_selector(struct ex_regs *regs, int seg_reg_idx) { - unsigned short sel; + //unsigned short sel; #ifdef CONFIG_X86_64 switch (seg_reg_idx) { @@ -350,8 +367,9 @@ static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx) return 0; case INAT_SEG_REG_CS: return (unsigned short)(regs->cs & 0xffff); +#if 0 case INAT_SEG_REG_SS: - return (unsigned short)(regs->ss & 0xffff); + return (unsigned short)(regs->cs & 0xffff); case INAT_SEG_REG_DS: savesegment(ds, sel); return sel; @@ -364,6 +382,7 @@ static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx) case INAT_SEG_REG_GS: savesegment(gs, sel); return sel; +#endif default: return -EINVAL; } @@ -412,32 +431,32 @@ static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx) } static const int pt_regoff[] = { - offsetof(struct pt_regs, ax), - offsetof(struct pt_regs, cx), - offsetof(struct pt_regs, dx), - offsetof(struct pt_regs, bx), - offsetof(struct pt_regs, sp), - offsetof(struct pt_regs, bp), - offsetof(struct pt_regs, si), - offsetof(struct pt_regs, di), + offsetof(struct ex_regs, rax), + offsetof(struct ex_regs, rcx), + offsetof(struct ex_regs, rdx), + offsetof(struct ex_regs, rbx), + offsetof(struct ex_regs, rbx), // ex_regs->sp not declared + offsetof(struct ex_regs, rbp), + offsetof(struct ex_regs, rsi), + offsetof(struct ex_regs, rdi), #ifdef CONFIG_X86_64 - offsetof(struct pt_regs, r8), - offsetof(struct pt_regs, r9), - offsetof(struct pt_regs, r10), - offsetof(struct pt_regs, r11), - offsetof(struct pt_regs, r12), - offsetof(struct pt_regs, r13), - offsetof(struct pt_regs, r14), - offsetof(struct pt_regs, r15), + offsetof(struct ex_regs, r8), + offsetof(struct ex_regs, r9), + offsetof(struct ex_regs, r10), + offsetof(struct ex_regs, r11), + offsetof(struct ex_regs, r12), + offsetof(struct ex_regs, r13), + offsetof(struct ex_regs, r14), + offsetof(struct ex_regs, r15), #else - offsetof(struct pt_regs, ds), - offsetof(struct pt_regs, es), - offsetof(struct pt_regs, fs), - offsetof(struct pt_regs, gs), + offsetof(struct ex_regs, ds), + offsetof(struct ex_regs, es), + offsetof(struct ex_regs, fs), + offsetof(struct ex_regs, gs), #endif }; -int pt_regs_offset(struct pt_regs *regs, int regno) +int ex_regs_offset(struct ex_regs *regs, int regno) { if ((unsigned)regno < ARRAY_SIZE(pt_regoff)) return pt_regoff[regno]; @@ -453,8 +472,10 @@ static int get_regno(struct insn *insn, enum reg_type type) * Don't possibly decode a 32-bit instructions as * reading a 64-bit-only register. */ +#if 0 if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64) nr_registers -= 8; +#endif switch (type) { case REG_TYPE_RM: @@ -508,18 +529,18 @@ static int get_regno(struct insn *insn, enum reg_type type) break; default: - pr_err_ratelimited("invalid register type: %d\n", type); + __GUEST_ASSERT(0, "invalid register type: %d\n", type); return -EINVAL; } if (regno >= nr_registers) { - WARN_ONCE(1, "decoded an instruction with an invalid register"); + __GUEST_ASSERT(0, "decoded an instruction with an invalid register"); return -EINVAL; } return regno; } -static int get_reg_offset(struct insn *insn, struct pt_regs *regs, +static int get_reg_offset(struct insn *insn, struct ex_regs *regs, enum reg_type type) { int regno = get_regno(insn, type); @@ -527,7 +548,7 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, if (regno < 0) return regno; - return pt_regs_offset(regs, regno); + return ex_regs_offset(regs, regno); } /** @@ -537,7 +558,7 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, * @offs1: Offset of the first operand register * @offs2: Offset of the second operand register, if applicable * - * Obtain the offset, in pt_regs, of the registers indicated by the ModRM byte + * Obtain the offset, in ex_regs, of the registers indicated by the ModRM byte * in @insn. This function is to be used with 16-bit address encodings. The * @offs1 and @offs2 will be written with the offset of the two registers * indicated by the instruction. In cases where any of the registers is not @@ -547,7 +568,7 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, * * 0 on success, -EINVAL on error. */ -static int get_reg_offset_16(struct insn *insn, struct pt_regs *regs, +static int get_reg_offset_16(struct insn *insn, struct ex_regs *regs, int *offs1, int *offs2) { /* @@ -556,21 +577,21 @@ static int get_reg_offset_16(struct insn *insn, struct pt_regs *regs, * ModR/M Byte" of the Intel Software Development Manual. */ static const int regoff1[] = { - offsetof(struct pt_regs, bx), - offsetof(struct pt_regs, bx), - offsetof(struct pt_regs, bp), - offsetof(struct pt_regs, bp), - offsetof(struct pt_regs, si), - offsetof(struct pt_regs, di), - offsetof(struct pt_regs, bp), - offsetof(struct pt_regs, bx), + offsetof(struct ex_regs, rbx), + offsetof(struct ex_regs, rbx), + offsetof(struct ex_regs, rbp), + offsetof(struct ex_regs, rbp), + offsetof(struct ex_regs, rsi), + offsetof(struct ex_regs, rdi), + offsetof(struct ex_regs, rbp), + offsetof(struct ex_regs, rbx), }; static const int regoff2[] = { - offsetof(struct pt_regs, si), - offsetof(struct pt_regs, di), - offsetof(struct pt_regs, si), - offsetof(struct pt_regs, di), + offsetof(struct ex_regs, rsi), + offsetof(struct ex_regs, rdi), + offsetof(struct ex_regs, rsi), + offsetof(struct ex_regs, rdi), -EDOM, -EDOM, -EDOM, @@ -604,6 +625,7 @@ static int get_reg_offset_16(struct insn *insn, struct pt_regs *regs, return 0; } +#ifndef CONFIG_X86_64 /** * get_desc() - Obtain contents of a segment descriptor * @out: Segment descriptor contents on success @@ -660,6 +682,7 @@ static bool get_desc(struct desc_struct *out, unsigned short sel) *out = *(struct desc_struct *)(gdt_desc.address + desc_base); return true; } +#endif /** * insn_get_seg_base() - Obtain base address of segment descriptor. @@ -678,21 +701,23 @@ static bool get_desc(struct desc_struct *out, unsigned short sel) * * -1L in case of error. */ -unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) +unsigned long insn_get_seg_base(struct ex_regs *regs, int seg_reg_idx) { - struct desc_struct desc; + // struct desc_struct desc; short sel; sel = get_segment_selector(regs, seg_reg_idx); if (sel < 0) return -1L; +#ifndef CONFIG_X86_64 if (v8086_mode(regs)) /* * Base is simply the segment selector shifted 4 * bits to the right. */ return (unsigned long)(sel << 4); +#endif if (any_64bit_mode(regs)) { /* @@ -701,6 +726,7 @@ unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) */ unsigned long base; +#ifndef CONFIG_X86_64 if (seg_reg_idx == INAT_SEG_REG_FS) { rdmsrl(MSR_FS_BASE, base); } else if (seg_reg_idx == INAT_SEG_REG_GS) { @@ -713,11 +739,15 @@ unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) else rdmsrl(MSR_GS_BASE, base); } else { +#endif base = 0; +#ifndef CONFIG_X86_64 } +#endif return base; } +#ifndef CONFIG_X86_64 /* In protected mode the segment selector cannot be null. */ if (!sel) return -1L; @@ -726,6 +756,8 @@ unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) return -1L; return get_desc_base(&desc); +#endif + return -1L; } /** @@ -745,9 +777,13 @@ unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) * * Zero is returned on error. */ -static unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx) +static unsigned long get_seg_limit(struct ex_regs *regs, int seg_reg_idx) { + if (any_64bit_mode(regs)) + return -1L; +#ifndef CONFIG_X86_64 struct desc_struct desc; + unsigned long limit; short sel; @@ -775,8 +811,11 @@ static unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx) limit = (limit << 12) + 0xfff; return limit; +#endif + return -1L; } +#ifndef CONFIG_X86_64 /** * insn_get_code_seg_params() - Obtain code segment parameters * @regs: Structure with register values as seen when entering kernel mode @@ -793,7 +832,7 @@ static unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx) * * -EINVAL on error. */ -int insn_get_code_seg_params(struct pt_regs *regs) +int insn_get_code_seg_params(struct ex_regs *regs) { struct desc_struct desc; short sel; @@ -834,11 +873,11 @@ int insn_get_code_seg_params(struct pt_regs *regs) */ return INSN_CODE_SEG_PARAMS(4, 8); case 3: /* Invalid setting. CS.L=1, CS.D=1 */ - fallthrough; default: return -EINVAL; } } +#endif /** * insn_get_modrm_rm_off() - Obtain register in r/m part of the ModRM byte @@ -848,11 +887,11 @@ int insn_get_code_seg_params(struct pt_regs *regs) * Returns: * * The register indicated by the r/m part of the ModRM byte. The - * register is obtained as an offset from the base of pt_regs. In specific + * register is obtained as an offset from the base of ex_regs. In specific * cases, the returned value can be -EDOM to indicate that the particular value * of ModRM does not refer to a register and shall be ignored. */ -int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs) +int insn_get_modrm_rm_off(struct insn *insn, struct ex_regs *regs) { return get_reg_offset(insn, regs, REG_TYPE_RM); } @@ -865,9 +904,9 @@ int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs) * Returns: * * The register indicated by the reg part of the ModRM byte. The - * register is obtained as an offset from the base of pt_regs. + * register is obtained as an offset from the base of ex_regs. */ -int insn_get_modrm_reg_off(struct insn *insn, struct pt_regs *regs) +int insn_get_modrm_reg_off(struct insn *insn, struct ex_regs *regs) { return get_reg_offset(insn, regs, REG_TYPE_REG); } @@ -880,9 +919,9 @@ int insn_get_modrm_reg_off(struct insn *insn, struct pt_regs *regs) * Returns: * * The register indicated by the reg part of the ModRM byte. - * The register is obtained as a pointer within pt_regs. + * The register is obtained as a pointer within ex_regs. */ -unsigned long *insn_get_modrm_reg_ptr(struct insn *insn, struct pt_regs *regs) +unsigned long *insn_get_modrm_reg_ptr(struct insn *insn, struct ex_regs *regs) { int offset; @@ -896,7 +935,7 @@ unsigned long *insn_get_modrm_reg_ptr(struct insn *insn, struct pt_regs *regs) * get_seg_base_limit() - obtain base address and limit of a segment * @insn: Instruction. Must be valid. * @regs: Register values as seen when entering kernel mode - * @regoff: Operand offset, in pt_regs, used to resolve segment descriptor + * @regoff: Operand offset, in ex_regs, used to resolve segment descriptor * @base: Obtained segment base * @limit: Obtained segment limit * @@ -913,7 +952,7 @@ unsigned long *insn_get_modrm_reg_ptr(struct insn *insn, struct pt_regs *regs) * * -EINVAL on error. */ -static int get_seg_base_limit(struct insn *insn, struct pt_regs *regs, +static int get_seg_base_limit(struct insn *insn, struct ex_regs *regs, int regoff, unsigned long *base, unsigned long *limit) { @@ -940,17 +979,23 @@ static int get_seg_base_limit(struct insn *insn, struct pt_regs *regs, return 0; } +static inline unsigned long regs_get_register(struct ex_regs *regs, + unsigned int offset) +{ + return *(unsigned long *)((unsigned long)regs + offset); +} + /** * get_eff_addr_reg() - Obtain effective address from register operand * @insn: Instruction. Must be valid. * @regs: Register values as seen when entering kernel mode - * @regoff: Obtained operand offset, in pt_regs, with the effective address + * @regoff: Obtained operand offset, in ex_regs, with the effective address * @eff_addr: Obtained effective address * * Obtain the effective address stored in the register operand as indicated by * the ModRM byte. This function is to be used only with register addressing * (i.e., ModRM.mod is 3). The effective address is saved in @eff_addr. The - * register operand, as an offset from the base of pt_regs, is saved in @regoff; + * register operand, as an offset from the base of ex_regs, is saved in @regoff; * such offset can then be used to resolve the segment associated with the * operand. This function can be used with any of the supported address sizes * in x86. @@ -959,11 +1004,11 @@ static int get_seg_base_limit(struct insn *insn, struct pt_regs *regs, * * 0 on success. @eff_addr will have the effective address stored in the * operand indicated by ModRM. @regoff will have such operand as an offset from - * the base of pt_regs. + * the base of ex_regs. * * -EINVAL on error. */ -static int get_eff_addr_reg(struct insn *insn, struct pt_regs *regs, +static int get_eff_addr_reg(struct insn *insn, struct ex_regs *regs, int *regoff, long *eff_addr) { int ret; @@ -994,7 +1039,7 @@ static int get_eff_addr_reg(struct insn *insn, struct pt_regs *regs, * get_eff_addr_modrm() - Obtain referenced effective address via ModRM * @insn: Instruction. Must be valid. * @regs: Register values as seen when entering kernel mode - * @regoff: Obtained operand offset, in pt_regs, associated with segment + * @regoff: Obtained operand offset, in ex_regs, associated with segment * @eff_addr: Obtained effective address * * Obtain the effective address referenced by the ModRM byte of @insn. After @@ -1007,12 +1052,12 @@ static int get_eff_addr_reg(struct insn *insn, struct pt_regs *regs, * Returns: * * 0 on success. @eff_addr will have the referenced effective address. @regoff - * will have a register, as an offset from the base of pt_regs, that can be used + * will have a register, as an offset from the base of ex_regs, that can be used * to resolve the associated segment. * * -EINVAL on error. */ -static int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs, +static int get_eff_addr_modrm(struct insn *insn, struct ex_regs *regs, int *regoff, long *eff_addr) { long tmp; @@ -1037,7 +1082,7 @@ static int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs, */ if (*regoff == -EDOM) { if (any_64bit_mode(regs)) - tmp = regs->ip + insn->length; + tmp = regs->rip + insn->length; else tmp = 0; } else if (*regoff < 0) { @@ -1061,7 +1106,7 @@ static int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs, * get_eff_addr_modrm_16() - Obtain referenced effective address via ModRM * @insn: Instruction. Must be valid. * @regs: Register values as seen when entering kernel mode - * @regoff: Obtained operand offset, in pt_regs, associated with segment + * @regoff: Obtained operand offset, in ex_regs, associated with segment * @eff_addr: Obtained effective address * * Obtain the 16-bit effective address referenced by the ModRM byte of @insn. @@ -1074,12 +1119,12 @@ static int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs, * Returns: * * 0 on success. @eff_addr will have the referenced effective address. @regoff - * will have a register, as an offset from the base of pt_regs, that can be used + * will have a register, as an offset from the base of ex_regs, that can be used * to resolve the associated segment. * * -EINVAL on error. */ -static int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs, +static int get_eff_addr_modrm_16(struct insn *insn, struct ex_regs *regs, int *regoff, short *eff_addr) { int addr_offset1, addr_offset2, ret; @@ -1129,7 +1174,7 @@ static int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs, * get_eff_addr_sib() - Obtain referenced effective address via SIB * @insn: Instruction. Must be valid. * @regs: Register values as seen when entering kernel mode - * @base_offset: Obtained operand offset, in pt_regs, associated with segment + * @base_offset: Obtained operand offset, in ex_regs, associated with segment * @eff_addr: Obtained effective address * * Obtain the effective address referenced by the SIB byte of @insn. After @@ -1142,12 +1187,12 @@ static int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs, * Returns: * * 0 on success. @eff_addr will have the referenced effective address. - * @base_offset will have a register, as an offset from the base of pt_regs, + * @base_offset will have a register, as an offset from the base of ex_regs, * that can be used to resolve the associated segment. * * Negative value on error. */ -static int get_eff_addr_sib(struct insn *insn, struct pt_regs *regs, +static int get_eff_addr_sib(struct insn *insn, struct ex_regs *regs, int *base_offset, long *eff_addr) { long base, indx; @@ -1231,7 +1276,7 @@ static int get_eff_addr_sib(struct insn *insn, struct pt_regs *regs, * * -1L on error. */ -static void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs) +static void __user *get_addr_ref_16(struct insn *insn, struct ex_regs *regs) { unsigned long linear_addr = -1L, seg_base, seg_limit; int ret, regoff; @@ -1271,9 +1316,11 @@ static void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs) linear_addr = (unsigned long)(eff_addr & 0xffff) + seg_base; +#ifndef CONFIG_X86_64 /* Limit linear address to 20 bits */ if (v8086_mode(regs)) linear_addr &= 0xfffff; +#endif out: return (void __user *)linear_addr; @@ -1295,7 +1342,7 @@ static void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs) * * -1L on error. */ -static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs) +static void __user *get_addr_ref_32(struct insn *insn, struct ex_regs *regs) { unsigned long linear_addr = -1L, seg_base, seg_limit; int eff_addr, regoff; @@ -1346,12 +1393,14 @@ static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs) if (!any_64bit_mode(regs) && ((unsigned int)eff_addr > seg_limit)) goto out; +#ifndef CONFIG_X86_64 /* * Even though 32-bit address encodings are allowed in virtual-8086 * mode, the address range is still limited to [0x-0xffff]. */ if (v8086_mode(regs) && (eff_addr & ~0xffff)) goto out; +#endif /* * Data type long could be 64 bits in size. Ensure that our 32-bit @@ -1361,8 +1410,10 @@ static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs) linear_addr = (unsigned long)(eff_addr & 0xffffffff) + seg_base; /* Limit linear address to 20 bits */ +#ifndef CONFIG_X86_64 if (v8086_mode(regs)) linear_addr &= 0xfffff; +#endif out: return (void __user *)linear_addr; @@ -1384,12 +1435,12 @@ static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs) * -1L on error. */ #ifndef CONFIG_X86_64 -static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) +static void __user *get_addr_ref_64(struct insn *insn, struct ex_regs *regs) { return (void __user *)-1L; } #else -static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) +static void __user *get_addr_ref_64(struct insn *insn, struct ex_regs *regs) { unsigned long linear_addr = -1L, seg_base; int regoff, ret; @@ -1442,7 +1493,7 @@ static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) * * -1L on error. */ -void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) +void __user *insn_get_addr_ref(struct insn *insn, struct ex_regs *regs) { if (!insn || !regs) return (void __user *)-1L; @@ -1462,7 +1513,7 @@ void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) } } -int insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip) +int insn_get_effective_ip(struct ex_regs *regs, unsigned long *ip) { unsigned long seg_base = 0; @@ -1472,17 +1523,18 @@ int insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip) * descriptor table), or virtual-8086 mode. In most of the cases * seg_base will be zero as in USER_CS. */ - if (!user_64bit_mode(regs)) { + if (0) { //(!user_64bit_mode(regs)) { seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS); if (seg_base == -1L) return -EINVAL; } - *ip = seg_base + regs->ip; + *ip = seg_base + regs->rip; return 0; } +#if 0 /** * insn_fetch_from_user() - Copy instruction bytes from user-space memory * @regs: Structure with register values as seen when entering kernel mode @@ -1497,7 +1549,7 @@ int insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip) * - 0 if nothing was copied. * - -EINVAL if the linear address of the instruction could not be calculated */ -int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) +int insn_fetch_from_user(struct ex_regs *regs, unsigned char buf[MAX_INSN_SIZE]) { unsigned long ip; int not_copied; @@ -1525,7 +1577,7 @@ int insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) * - 0 if nothing was copied. * - -EINVAL if the linear address of the instruction could not be calculated. */ -int insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) +int insn_fetch_from_user_inatomic(struct ex_regs *regs, unsigned char buf[MAX_INSN_SIZE]) { unsigned long ip; int not_copied; @@ -1537,7 +1589,6 @@ int insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_IN return MAX_INSN_SIZE - not_copied; } - /** * insn_decode_from_regs() - Decode an instruction * @insn: Structure to store decoded instruction @@ -1552,12 +1603,12 @@ int insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_IN * * True if instruction was decoded, False otherwise. */ -bool insn_decode_from_regs(struct insn *insn, struct pt_regs *regs, +bool insn_decode_from_regs(struct insn *insn, struct ex_regs *regs, unsigned char buf[MAX_INSN_SIZE], int buf_size) { int seg_defs; - insn_init(insn, buf, buf_size, user_64bit_mode(regs)); + insn_init(insn, buf, buf_size, 1); //user_64bit_mode(regs)); /* * Override the default operand and address sizes with what is specified @@ -1584,6 +1635,7 @@ bool insn_decode_from_regs(struct insn *insn, struct pt_regs *regs, return true; } +#endif /** * insn_decode_mmio() - Decode a MMIO instruction @@ -1609,7 +1661,6 @@ enum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes) switch (insn->opcode.bytes[0]) { case 0x88: /* MOV m8,r8 */ *bytes = 1; - fallthrough; case 0x89: /* MOV m16/m32/m64, r16/m32/m64 */ if (!*bytes) *bytes = insn->opnd_bytes; @@ -1618,7 +1669,6 @@ enum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes) case 0xc6: /* MOV m8, imm8 */ *bytes = 1; - fallthrough; case 0xc7: /* MOV m16/m32/m64, imm16/imm32/imm64 */ if (!*bytes) *bytes = insn->opnd_bytes; @@ -1627,7 +1677,6 @@ enum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes) case 0x8a: /* MOV r8, m8 */ *bytes = 1; - fallthrough; case 0x8b: /* MOV r16/r32/r64, m16/m32/m64 */ if (!*bytes) *bytes = insn->opnd_bytes; @@ -1636,7 +1685,6 @@ enum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes) case 0xa4: /* MOVS m8, m8 */ *bytes = 1; - fallthrough; case 0xa5: /* MOVS m16/m32/m64, m16/m32/m64 */ if (!*bytes) *bytes = insn->opnd_bytes; -- 2.34.1