[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250228093024.114983-14-Neeraj.Upadhyay@amd.com>
Date: Fri, 28 Feb 2025 15:00:06 +0530
From: Neeraj Upadhyay <Neeraj.Upadhyay@....com>
To: <kvm@...r.kernel.org>, <seanjc@...gle.com>, <pbonzini@...hat.com>
CC: <linux-kernel@...r.kernel.org>, <Thomas.Lendacky@....com>,
<nikunj@....com>, <Santosh.Shukla@....com>, <Vasant.Hegde@....com>,
<Suravee.Suthikulpanit@....com>, <bp@...en8.de>, <David.Kaplan@....com>,
<huibo.wang@....com>, <naveen.rao@....com>, <pgonda@...gle.com>,
<linux-kselftest@...r.kernel.org>, <shuah@...nel.org>
Subject: [RFC PATCH 13/31] KVM: selftests: Add instruction decoding support
Update insn-eval.c to prototype instruction decoding for MMIO
VC exception exit.
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@....com>
---
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
Powered by blists - more mailing lists