# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID e0db5a3a2ef613f61e1d873cd2749c75c1d0caa7
# Parent 807fbfb0a0dcf7c1e2c4c46f10f093d0905e49f3
[HVM] Use AMD's isntruction-length decoder for VMX as well as SVM
MMIO decode. The VMX-defined instruction-length info field is not
valid for use during most page faults. Hence we have to obtain the
instruction length the slow-and-stupid way.
This *will* go away when we throw away the wretched MMIO emulator.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/hvm/svm/instrlen.c | 479 --------------------------------------
xen/arch/x86/hvm/Makefile | 1
xen/arch/x86/hvm/instrlen.c | 474 +++++++++++++++++++++++++++++++++++++
xen/arch/x86/hvm/platform.c | 48 +--
xen/arch/x86/hvm/svm/Makefile | 1
xen/arch/x86/hvm/svm/svm.c | 27 --
xen/arch/x86/hvm/vmx/vmx.c | 40 ++-
xen/include/asm-x86/hvm/hvm.h | 18 -
xen/include/asm-x86/hvm/vmx/vmx.h | 26 --
9 files changed, 548 insertions(+), 566 deletions(-)
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Mon Sep 25 09:36:11 2006 +0100
+++ b/xen/arch/x86/hvm/Makefile Mon Sep 25 10:22:17 2006 +0100
@@ -4,6 +4,7 @@ obj-y += hvm.o
obj-y += hvm.o
obj-y += i8254.o
obj-y += i8259.o
+obj-y += instrlen.o
obj-y += intercept.o
obj-y += io.o
obj-y += platform.o
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/platform.c
--- a/xen/arch/x86/hvm/platform.c Mon Sep 25 09:36:11 2006 +0100
+++ b/xen/arch/x86/hvm/platform.c Mon Sep 25 10:22:17 2006 +0100
@@ -52,7 +52,7 @@ static inline long __get_reg_value(unsig
case QUAD:
return (long)(reg);
default:
- printf("Error: (__get_reg_value) Invalid reg size\n");
+ printk("Error: (__get_reg_value) Invalid reg size\n");
domain_crash_synchronous();
}
}
@@ -78,7 +78,7 @@ long get_reg_value(int size, int index,
case 7: /* %bh */
return (char)((regs->rbx & 0xFF00) >> 8);
default:
- printf("Error: (get_reg_value) Invalid index value\n");
+ printk("Error: (get_reg_value) Invalid index value\n");
domain_crash_synchronous();
}
/* NOTREACHED */
@@ -102,7 +102,7 @@ long get_reg_value(int size, int index,
case 14: return __get_reg_value(regs->r14, size);
case 15: return __get_reg_value(regs->r15, size);
default:
- printf("Error: (get_reg_value) Invalid index value\n");
+ printk("Error: (get_reg_value) Invalid index value\n");
domain_crash_synchronous();
}
}
@@ -115,7 +115,7 @@ static inline long __get_reg_value(unsig
case LONG:
return (int)(reg & 0xFFFFFFFF);
default:
- printf("Error: (__get_reg_value) Invalid reg size\n");
+ printk("Error: (__get_reg_value) Invalid reg size\n");
domain_crash_synchronous();
}
}
@@ -141,7 +141,7 @@ long get_reg_value(int size, int index,
case 7: /* %bh */
return (char)((regs->ebx & 0xFF00) >> 8);
default:
- printf("Error: (get_reg_value) Invalid index value\n");
+ printk("Error: (get_reg_value) Invalid index value\n");
domain_crash_synchronous();
}
}
@@ -156,7 +156,7 @@ long get_reg_value(int size, int index,
case 6: return __get_reg_value(regs->esi, size);
case 7: return __get_reg_value(regs->edi, size);
default:
- printf("Error: (get_reg_value) Invalid index value\n");
+ printk("Error: (get_reg_value) Invalid index value\n");
domain_crash_synchronous();
}
}
@@ -464,7 +464,7 @@ static int hvm_decode(int realmode, unsi
return DECODE_success;
default:
- printf("%x/%x, This opcode isn't handled yet!\n",
+ printk("%x/%x, This opcode isn't handled yet!\n",
*opcode, ins_subtype);
return DECODE_failure;
}
@@ -614,7 +614,7 @@ static int hvm_decode(int realmode, unsi
break;
default:
- printf("%x, This opcode isn't handled yet!\n", *opcode);
+ printk("%x, This opcode isn't handled yet!\n", *opcode);
return DECODE_failure;
}
@@ -675,12 +675,12 @@ static int hvm_decode(int realmode, unsi
}
else
{
- printf("0f %x, This opcode subtype isn't handled yet\n", *opcode);
+ printk("0f %x, This opcode subtype isn't handled yet\n", *opcode);
return DECODE_failure;
}
default:
- printf("0f %x, This opcode isn't handled yet\n", *opcode);
+ printk("0f %x, This opcode isn't handled yet\n", *opcode);
return DECODE_failure;
}
}
@@ -702,7 +702,7 @@ static void hvm_send_assist_req(struct v
if ( unlikely(p->state != STATE_INVALID) ) {
/* This indicates a bug in the device model. Crash the
domain. */
- printf("Device model set bad IO state %d.\n", p->state);
+ printk("Device model set bad IO state %d.\n", p->state);
domain_crash(v->domain);
return;
}
@@ -733,7 +733,7 @@ void send_pio_req(struct cpu_user_regs *
p = &vio->vp_ioreq;
if ( p->state != STATE_INVALID )
- printf("WARNING: send pio with something already pending (%d)?\n",
+ printk("WARNING: send pio with something already pending (%d)?\n",
p->state);
p->dir = dir;
p->pdata_valid = pvalid;
@@ -776,14 +776,14 @@ void send_mmio_req(
vio = get_vio(v->domain, v->vcpu_id);
if (vio == NULL) {
- printf("bad shared page\n");
+ printk("bad shared page\n");
domain_crash_synchronous();
}
p = &vio->vp_ioreq;
if ( p->state != STATE_INVALID )
- printf("WARNING: send mmio with something already pending (%d)?\n",
+ printk("WARNING: send mmio with something already pending (%d)?\n",
p->state);
p->dir = dir;
p->pdata_valid = pvalid;
@@ -841,7 +841,7 @@ static void mmio_operands(int type, unsi
else
send_mmio_req(type, gpa, 1, inst->op_size, 0, IOREQ_READ, 0);
} else {
- printf("mmio_operands: invalid operand\n");
+ printk("mmio_operands: invalid operand\n");
domain_crash_synchronous();
}
}
@@ -866,8 +866,10 @@ void handle_mmio(unsigned long va, unsig
memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES);
hvm_store_cpu_guest_regs(v, regs, NULL);
- if ((inst_len = hvm_instruction_length(v)) <= 0) {
- printf("handle_mmio: failed to get instruction length\n");
+ inst_len = hvm_instruction_length(regs, hvm_guest_x86_mode(v));
+ if ( inst_len <= 0 )
+ {
+ printk("handle_mmio: failed to get instruction length\n");
domain_crash_synchronous();
}
@@ -880,19 +882,19 @@ void handle_mmio(unsigned long va, unsig
memset(inst, 0, MAX_INST_LEN);
ret = inst_copy_from_guest(inst, inst_addr, inst_len);
if (ret != inst_len) {
- printf("handle_mmio: failed to copy instruction\n");
+ printk("handle_mmio: failed to copy instruction\n");
domain_crash_synchronous();
}
init_instruction(&mmio_inst);
if (hvm_decode(realmode, inst, &mmio_inst) == DECODE_failure) {
- printf("handle_mmio: failed to decode instruction\n");
- printf("mmio opcode: va 0x%lx, gpa 0x%lx, len %d:",
+ printk("handle_mmio: failed to decode instruction\n");
+ printk("mmio opcode: va 0x%lx, gpa 0x%lx, len %d:",
va, gpa, inst_len);
for (i = 0; i < inst_len; i++)
- printf(" %02x", inst[i] & 0xFF);
- printf("\n");
+ printk(" %02x", inst[i] & 0xFF);
+ printk("\n");
domain_crash_synchronous();
}
@@ -1073,7 +1075,7 @@ void handle_mmio(unsigned long va, unsig
break;
default:
- printf("Unhandled MMIO instruction\n");
+ printk("Unhandled MMIO instruction\n");
domain_crash_synchronous();
}
}
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/svm/Makefile
--- a/xen/arch/x86/hvm/svm/Makefile Mon Sep 25 09:36:11 2006 +0100
+++ b/xen/arch/x86/hvm/svm/Makefile Mon Sep 25 10:22:17 2006 +0100
@@ -2,7 +2,6 @@ subdir-$(x86_64) += x86_64
subdir-$(x86_64) += x86_64
obj-y += emulate.o
-obj-y += instrlen.o
obj-y += intr.o
obj-y += svm.o
obj-y += vmcb.o
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Mon Sep 25 09:36:11 2006 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c Mon Sep 25 10:22:17 2006 +0100
@@ -44,6 +44,7 @@
#include <asm/hvm/svm/emulate.h>
#include <asm/hvm/svm/vmmcall.h>
#include <asm/hvm/svm/intr.h>
+#include <asm/x86_emulate.h>
#include <public/sched.h>
#define SVM_EXTRA_DEBUG
@@ -60,7 +61,6 @@ extern asmlinkage void do_IRQ(struct cpu
extern asmlinkage void do_IRQ(struct cpu_user_regs *);
extern void send_pio_req(struct cpu_user_regs *regs, unsigned long port,
unsigned long count, int size, long value, int dir,
int pvalid);
-extern int svm_instrlen(struct cpu_user_regs *regs, int mode);
extern void svm_dump_inst(unsigned long eip);
extern int svm_dbg_on;
void svm_dump_regs(const char *from, struct cpu_user_regs *regs);
@@ -468,21 +468,19 @@ static int svm_realmode(struct vcpu *v)
return (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE);
}
-int svm_guest_x86_mode(struct vcpu *v)
+static int svm_guest_x86_mode(struct vcpu *v)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- unsigned long cr0 = vmcb->cr0, eflags = vmcb->rflags, mode;
- /* check which operating mode the guest is running */
- if( vmcb->efer & EFER_LMA )
- mode = vmcb->cs.attributes.fields.l ? 8 : 4;
- else
- mode = (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE) ? 2 : 4;
- return mode;
-}
-
-int svm_instruction_length(struct vcpu *v)
-{
- return svm_instrlen(guest_cpu_user_regs(), svm_guest_x86_mode(v));
+
+ if ( vmcb->efer & EFER_LMA )
+ return (vmcb->cs.attributes.fields.l ?
+ X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32);
+
+ if ( svm_realmode(v) )
+ return X86EMUL_MODE_REAL;
+
+ return (vmcb->cs.attributes.fields.db ?
+ X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16);
}
void svm_update_host_cr3(struct vcpu *v)
@@ -878,7 +876,6 @@ int start_svm(void)
hvm_funcs.long_mode_enabled = svm_long_mode_enabled;
hvm_funcs.pae_enabled = svm_pae_enabled;
hvm_funcs.guest_x86_mode = svm_guest_x86_mode;
- hvm_funcs.instruction_length = svm_instruction_length;
hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg;
hvm_funcs.update_host_cr3 = svm_update_host_cr3;
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Mon Sep 25 09:36:11 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c Mon Sep 25 10:22:17 2006 +0100
@@ -45,6 +45,7 @@
#include <public/hvm/ioreq.h>
#include <asm/hvm/vpic.h>
#include <asm/hvm/vlapic.h>
+#include <asm/x86_emulate.h>
extern uint32_t vlapic_update_ppr(struct vlapic *vlapic);
@@ -593,15 +594,6 @@ static void vmx_load_cpu_guest_regs(stru
vmx_vmcs_exit(v);
}
-static int vmx_instruction_length(struct vcpu *v)
-{
- unsigned long inst_len;
-
- if ( __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len) ) /* XXX Unsafe XXX */
- return 0;
- return inst_len;
-}
-
static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num)
{
switch ( num )
@@ -729,6 +721,35 @@ static void vmx_init_hypercall_page(stru
*(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */
}
+static int vmx_realmode(struct vcpu *v)
+{
+ unsigned long rflags;
+
+ ASSERT(v == current);
+
+ __vmread(GUEST_RFLAGS, &rflags);
+ return rflags & X86_EFLAGS_VM;
+}
+
+static int vmx_guest_x86_mode(struct vcpu *v)
+{
+ unsigned long cs_ar_bytes;
+
+ ASSERT(v == current);
+
+ __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes);
+
+ if ( vmx_long_mode_enabled(v) )
+ return ((cs_ar_bytes & (1u<<13)) ?
+ X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32);
+
+ if ( vmx_realmode(v) )
+ return X86EMUL_MODE_REAL;
+
+ return ((cs_ar_bytes & (1u<<14)) ?
+ X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16);
+}
+
/* Setup HVM interfaces */
static void vmx_setup_hvm_funcs(void)
{
@@ -748,7 +769,6 @@ static void vmx_setup_hvm_funcs(void)
hvm_funcs.long_mode_enabled = vmx_long_mode_enabled;
hvm_funcs.pae_enabled = vmx_pae_enabled;
hvm_funcs.guest_x86_mode = vmx_guest_x86_mode;
- hvm_funcs.instruction_length = vmx_instruction_length;
hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg;
hvm_funcs.update_host_cr3 = vmx_update_host_cr3;
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h Mon Sep 25 09:36:11 2006 +0100
+++ b/xen/include/asm-x86/hvm/hvm.h Mon Sep 25 10:22:17 2006 +0100
@@ -51,15 +51,13 @@ struct hvm_function_table {
* Examine specifics of the guest state:
* 1) determine whether the guest is in real or vm8086 mode,
* 2) determine whether paging is enabled,
- * 3) return the length of the instruction that caused an exit.
- * 4) return the current guest control-register value
+ * 3) return the current guest control-register value
*/
int (*realmode)(struct vcpu *v);
int (*paging_enabled)(struct vcpu *v);
int (*long_mode_enabled)(struct vcpu *v);
int (*pae_enabled)(struct vcpu *v);
int (*guest_x86_mode)(struct vcpu *v);
- int (*instruction_length)(struct vcpu *v);
unsigned long (*get_guest_ctrl_reg)(struct vcpu *v, unsigned int num);
/*
@@ -159,11 +157,7 @@ hvm_guest_x86_mode(struct vcpu *v)
return hvm_funcs.guest_x86_mode(v);
}
-static inline int
-hvm_instruction_length(struct vcpu *v)
-{
- return hvm_funcs.instruction_length(v);
-}
+int hvm_instruction_length(struct cpu_user_regs *regs, int mode);
static inline void
hvm_update_host_cr3(struct vcpu *v)
@@ -182,9 +176,9 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, u
return 0; /* force to fail */
}
-extern void hvm_stts(struct vcpu *v);
-extern void hvm_set_guest_time(struct vcpu *v, u64 gtime);
-extern void hvm_do_resume(struct vcpu *v);
+void hvm_stts(struct vcpu *v);
+void hvm_set_guest_time(struct vcpu *v, u64 gtime);
+void hvm_do_resume(struct vcpu *v);
static inline void
hvm_init_ap_context(struct vcpu_guest_context *ctxt,
@@ -193,6 +187,6 @@ hvm_init_ap_context(struct vcpu_guest_co
return hvm_funcs.init_ap_context(ctxt, vcpuid, trampoline_vector);
}
-extern int hvm_bringup_ap(int vcpuid, int trampoline_vector);
+int hvm_bringup_ap(int vcpuid, int trampoline_vector);
#endif /* __ASM_X86_HVM_HVM_H__ */
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Mon Sep 25 09:36:11 2006 +0100
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Mon Sep 25 10:22:17 2006 +0100
@@ -425,36 +425,10 @@ static inline int vmx_pae_enabled(struct
}
/* Works only for vcpu == current */
-static inline int vmx_realmode(struct vcpu *v)
-{
- unsigned long rflags;
- ASSERT(v == current);
-
- __vmread(GUEST_RFLAGS, &rflags);
- return rflags & X86_EFLAGS_VM;
-}
-
-/* Works only for vcpu == current */
static inline void vmx_update_host_cr3(struct vcpu *v)
{
ASSERT(v == current);
__vmwrite(HOST_CR3, v->arch.cr3);
-}
-
-static inline int vmx_guest_x86_mode(struct vcpu *v)
-{
- unsigned long cs_ar_bytes;
- ASSERT(v == current);
-
- if ( vmx_long_mode_enabled(v) )
- {
- __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes);
- return (cs_ar_bytes & (1u<<13)) ? 8 : 4;
- }
- if ( vmx_realmode(v) )
- return 2;
- __vmread(GUEST_CS_AR_BYTES, &cs_ar_bytes);
- return (cs_ar_bytes & (1u<<14)) ? 4 : 2;
}
static inline int vmx_pgbit_test(struct vcpu *v)
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/instrlen.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/instrlen.c Mon Sep 25 10:22:17 2006 +0100
@@ -0,0 +1,474 @@
+/*
+ * instrlen.c - calculates the instruction length for all operating modes
+ *
+ * Travis Betak, travis.betak@xxxxxxx
+ * Copyright (c) 2005,2006 AMD
+ * Copyright (c) 2005 Keir Fraser
+ *
+ * Essentially a very, very stripped version of Keir Fraser's work in
+ * x86_emulate.c. Used for MMIO.
+ */
+
+/*
+ * TODO: The way in which we use hvm_instruction_length is very inefficient as
+ * it now stands. It will be worthwhile to return the actual instruction buffer
+ * along with the instruction length since one of the reasons we are getting
+ * the instruction length is to know how many instruction bytes we need to
+ * fetch.
+ */
+
+#include <xen/config.h>
+#include <xen/sched.h>
+#include <xen/mm.h>
+#include <asm/regs.h>
+#include <asm-x86/x86_emulate.h>
+
+/* read from guest memory */
+extern int inst_copy_from_guest(unsigned char *buf, unsigned long eip,
+ int length);
+
+/*
+ * Opcode effective-address decode tables.
+ * Note that we only emulate instructions that have at least one memory
+ * operand (excluding implicit stack references). We assume that stack
+ * references and instruction fetches will never occur in special memory
+ * areas that require emulation. So, for example, 'mov <imm>,<reg>' need
+ * not be handled.
+ */
+
+/* Operand sizes: 8-bit operands or specified/overridden size. */
+#define ByteOp (1<<0) /* 8-bit operands. */
+/* Destination operand type. */
+#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
+#define DstReg (2<<1) /* Register operand. */
+#define DstMem (3<<1) /* Memory operand. */
+#define DstMask (3<<1)
+/* Source operand type. */
+#define SrcNone (0<<3) /* No source operand. */
+#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
+#define SrcReg (1<<3) /* Register operand. */
+#define SrcMem (2<<3) /* Memory operand. */
+#define SrcMem16 (3<<3) /* Memory operand (16-bit). */
+#define SrcMem32 (4<<3) /* Memory operand (32-bit). */
+#define SrcImm (5<<3) /* Immediate operand. */
+#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */
+#define SrcMask (7<<3)
+/* Generic ModRM decode. */
+#define ModRM (1<<6)
+/* Destination is only written; never read. */
+#define Mov (1<<7)
+
+static uint8_t opcode_table[256] = {
+ /* 0x00 - 0x07 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, 0,
+ /* 0x08 - 0x0F */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, 0,
+ /* 0x10 - 0x17 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, 0,
+ /* 0x18 - 0x1F */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, 0,
+ /* 0x20 - 0x27 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, 0,
+ /* 0x28 - 0x2F */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, 0,
+ /* 0x30 - 0x37 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, 0,
+ /* 0x38 - 0x3F */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, 0,
+ /* 0x40 - 0x4F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x50 - 0x5F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x60 - 0x6F */
+ 0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x70 - 0x7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x80 - 0x87 */
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ /* 0x88 - 0x8F */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
+ ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
+ 0, 0, 0, DstMem|SrcNone|ModRM|Mov,
+ /* 0x90 - 0x9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xA0 - 0xA7 */
+ ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov,
+ ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov,
+ ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
+ ByteOp|ImplicitOps, ImplicitOps,
+ /* 0xA8 - 0xAF */
+ 0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
+ ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
+ ByteOp|ImplicitOps, ImplicitOps,
+ /* 0xB0 - 0xBF */
+ SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
+ SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xC0 - 0xC7 */
+ ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0,
+ 0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
+ /* 0xC8 - 0xCF */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xD0 - 0xD7 */
+ ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
+ ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
+ 0, 0, 0, 0,
+ /* 0xD8 - 0xDF */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE0 - 0xEF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xF0 - 0xF7 */
+ 0, 0, 0, 0,
+ 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
+ /* 0xF8 - 0xFF */
+ 0, 0, 0, 0,
+ 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
+};
+
+static uint8_t twobyte_table[256] = {
+ /* 0x00 - 0x0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0,
+ /* 0x10 - 0x1F */
+ 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x20 - 0x2F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x30 - 0x3F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x40 - 0x47 */
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ /* 0x48 - 0x4F */
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
+ /* 0x50 - 0x5F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x60 - 0x6F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x70 - 0x7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x80 - 0x8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 - 0x9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xA0 - 0xA7 */
+ 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
+ /* 0xA8 - 0xAF */
+ 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
+ /* 0xB0 - 0xB7 */
+ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM,
+ 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
+ /* 0xB8 - 0xBF */
+ 0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM,
+ 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
+ /* 0xC0 - 0xCF */
+ 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xD0 - 0xDF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE0 - 0xEF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xF0 - 0xFF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * insn_fetch - fetch the next 1 to 4 bytes from instruction stream
+ *
+ * @_type: u8, u16, u32, s8, s16, or s32
+ * @_size: 1, 2, or 4 bytes
+ * @_eip: address to fetch from guest memory
+ * @_length: increments the current instruction length counter by _size
+ *
+ * This is used internally by hvm_instruction_length to fetch the next byte,
+ * word, or dword from guest memory at location _eip. we currently use a local
+ * unsigned long as the storage buffer since the most bytes we're gonna get
+ * is limited to 4.
+ */
+#define insn_fetch(_type, _size, _eip, _length) \
+({ unsigned long _x; \
+ if ((rc = inst_copy_from_guest((unsigned char *)(&(_x)), \
+ (unsigned long)(_eip), _size)) \
+ != _size) \
+ goto done; \
+ (_eip) += (_size); \
+ (_length) += (_size); \
+ (_type)_x; \
+})
+
+/**
+ * hvm_instruction_length - returns the current instructions length
+ *
+ * @regs: guest register state
+ * @mode: guest operating mode
+ *
+ * EXTERNAL this routine calculates the length of the current instruction
+ * pointed to by eip. The guest state is _not_ changed by this routine.
+ */
+int hvm_instruction_length(struct cpu_user_regs *regs, int mode)
+{
+ uint8_t b, d, twobyte = 0, rex_prefix = 0;
+ uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
+ unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
+ int rc = 0;
+ int length = 0;
+ unsigned int tmp;
+
+ /* Shadow copy of register state. Committed on successful emulation. */
+ struct cpu_user_regs _regs = *regs;
+
+ /* include CS for 16-bit modes */
+ if (mode == X86EMUL_MODE_REAL || mode == X86EMUL_MODE_PROT16)
+ _regs.eip += (_regs.cs << 4);
+
+ switch ( mode )
+ {
+ case X86EMUL_MODE_REAL:
+ case X86EMUL_MODE_PROT16:
+ op_bytes = ad_bytes = 2;
+ break;
+ case X86EMUL_MODE_PROT32:
+ op_bytes = ad_bytes = 4;
+ break;
+#ifdef __x86_64__
+ case X86EMUL_MODE_PROT64:
+ op_bytes = 4;
+ ad_bytes = 8;
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ /* Legacy prefixes. */
+ for ( i = 0; i < 8; i++ )
+ {
+ switch ( b = insn_fetch(uint8_t, 1, _regs.eip, length) )
+ {
+ case 0x66: /* operand-size override */
+ op_bytes ^= 6; /* switch between 2/4 bytes */
+ break;
+ case 0x67: /* address-size override */
+ if ( mode == X86EMUL_MODE_PROT64 )
+ ad_bytes ^= 12; /* switch between 4/8 bytes */
+ else
+ ad_bytes ^= 6; /* switch between 2/4 bytes */
+ break;
+ case 0x2e: /* CS override */
+ case 0x3e: /* DS override */
+ case 0x26: /* ES override */
+ case 0x64: /* FS override */
+ case 0x65: /* GS override */
+ case 0x36: /* SS override */
+ break;
+ case 0xf0: /* LOCK */
+ lock_prefix = 1;
+ break;
+ case 0xf3: /* REP/REPE/REPZ */
+ rep_prefix = 1;
+ break;
+ case 0xf2: /* REPNE/REPNZ */
+ break;
+ default:
+ goto done_prefixes;
+ }
+ }
+done_prefixes:
+
+ /* Note quite the same as 80386 real mode, but hopefully good enough. */
+ if ( (mode == X86EMUL_MODE_REAL) && (ad_bytes != 2) ) {
+ printf("sonofabitch!! we don't support 32-bit addresses in
realmode\n");
+ goto cannot_emulate;
+ }
+
+ /* REX prefix. */
+ if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
+ {
+ rex_prefix = b;
+ if ( b & 8 )
+ op_bytes = 8; /* REX.W */
+ modrm_reg = (b & 4) << 1; /* REX.R */
+ /* REX.B and REX.X do not need to be decoded. */
+ b = insn_fetch(uint8_t, 1, _regs.eip, length);
+ }
+
+ /* Opcode byte(s). */
+ d = opcode_table[b];
+ if ( d == 0 )
+ {
+ /* Two-byte opcode? */
+ if ( b == 0x0f )
+ {
+ twobyte = 1;
+ b = insn_fetch(uint8_t, 1, _regs.eip, length);
+ d = twobyte_table[b];
+ }
+
+ /* Unrecognised? */
+ if ( d == 0 )
+ goto cannot_emulate;
+ }
+
+ /* ModRM and SIB bytes. */
+ if ( d & ModRM )
+ {
+ modrm = insn_fetch(uint8_t, 1, _regs.eip, length);
+ modrm_mod |= (modrm & 0xc0) >> 6;
+ modrm_reg |= (modrm & 0x38) >> 3;
+ modrm_rm |= (modrm & 0x07);
+
+ if ( modrm_mod == 3 )
+ {
+ DPRINTK("Cannot parse ModRM.mod == 3.\n");
+ goto cannot_emulate;
+ }
+
+ if ( ad_bytes == 2 )
+ {
+ /* 16-bit ModR/M decode. */
+ switch ( modrm_mod )
+ {
+ case 0:
+ if ( modrm_rm == 6 )
+ {
+ length += 2;
+ _regs.eip += 2; /* skip disp16 */
+ }
+ break;
+ case 1:
+ length += 1;
+ _regs.eip += 1; /* skip disp8 */
+ break;
+ case 2:
+ length += 2;
+ _regs.eip += 2; /* skip disp16 */
+ break;
+ }
+ }
+ else
+ {
+ /* 32/64-bit ModR/M decode. */
+ switch ( modrm_mod )
+ {
+ case 0:
+ if ( (modrm_rm == 4) &&
+ (((insn_fetch(uint8_t, 1, _regs.eip, length)) & 7)
+ == 5) )
+ {
+ length += 4;
+ _regs.eip += 4; /* skip disp32 specified by SIB.base */
+ }
+ else if ( modrm_rm == 5 )
+ {
+ length += 4;
+ _regs.eip += 4; /* skip disp32 */
+ }
+ break;
+ case 1:
+ if ( modrm_rm == 4 )
+ {
+ insn_fetch(uint8_t, 1, _regs.eip, length);
+ }
+ length += 1;
+ _regs.eip += 1; /* skip disp8 */
+ break;
+ case 2:
+ if ( modrm_rm == 4 )
+ {
+ insn_fetch(uint8_t, 1, _regs.eip, length);
+ }
+ length += 4;
+ _regs.eip += 4; /* skip disp32 */
+ break;
+ }
+ }
+ }
+
+ /* Decode and fetch the destination operand: register or memory. */
+ switch ( d & DstMask )
+ {
+ case ImplicitOps:
+ /* Special instructions do their own operand decoding. */
+ goto done;
+ }
+
+ /* Decode and fetch the source operand: register, memory or immediate. */
+ switch ( d & SrcMask )
+ {
+ case SrcImm:
+ tmp = (d & ByteOp) ? 1 : op_bytes;
+ if ( tmp == 8 ) tmp = 4;
+ /* NB. Immediates are sign-extended as necessary. */
+ switch ( tmp )
+ {
+ case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
+ case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
+ case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
+ }
+ break;
+ case SrcImmByte:
+ insn_fetch(int8_t, 1, _regs.eip, length);
+ break;
+ }
+
+ if ( twobyte )
+ goto done;
+
+ switch ( b )
+ {
+ case 0xa0 ... 0xa1: /* mov */
+ length += ad_bytes;
+ _regs.eip += ad_bytes; /* skip src displacement */
+ break;
+ case 0xa2 ... 0xa3: /* mov */
+ length += ad_bytes;
+ _regs.eip += ad_bytes; /* skip dst displacement */
+ break;
+ case 0xf6 ... 0xf7: /* Grp3 */
+ switch ( modrm_reg )
+ {
+ case 0 ... 1: /* test */
+ /* Special case in Grp3: test has an immediate source operand. */
+ tmp = (d & ByteOp) ? 1 : op_bytes;
+ if ( tmp == 8 ) tmp = 4;
+ switch ( tmp )
+ {
+ case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
+ case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
+ case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
+ }
+ goto done;
+ }
+ break;
+ }
+
+done:
+ return length;
+
+cannot_emulate:
+ DPRINTK("Cannot emulate %02x at address %lx (eip %lx, mode %d)\n",
+ b, (unsigned long)_regs.eip, (unsigned long)regs->eip, mode);
+ return -1;
+}
diff -r 807fbfb0a0dc -r e0db5a3a2ef6 xen/arch/x86/hvm/svm/instrlen.c
--- a/xen/arch/x86/hvm/svm/instrlen.c Mon Sep 25 09:36:11 2006 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,479 +0,0 @@
-/*
- * instrlen.c - calculates the instruction length for all operating modes
- *
- * Travis Betak, travis.betak@xxxxxxx
- * Copyright (c) 2005,2006 AMD
- * Copyright (c) 2005 Keir Fraser
- *
- * Essentially a very, very stripped version of Keir Fraser's work in
- * x86_emulate.c. Used for MMIO.
- */
-
-/*
- * TODO: the way in which we use svm_instrlen is very inefficient as is now
- * stands. It will be worth while to return the actual instruction buffer
- * along with the instruction length since one of the reasons we are getting
- * the instruction length is to know how many instruction bytes we need to
- * fetch.
- */
-
-#include <xen/config.h>
-#include <xen/types.h>
-#include <xen/lib.h>
-#include <xen/mm.h>
-#include <asm/regs.h>
-#define DPRINTF DPRINTK
-#include <asm-x86/x86_emulate.h>
-
-/* read from guest memory */
-extern int inst_copy_from_guest(unsigned char *buf, unsigned long eip,
- int length);
-extern void svm_dump_inst(unsigned long eip);
-
-/*
- * Opcode effective-address decode tables.
- * Note that we only emulate instructions that have at least one memory
- * operand (excluding implicit stack references). We assume that stack
- * references and instruction fetches will never occur in special memory
- * areas that require emulation. So, for example, 'mov <imm>,<reg>' need
- * not be handled.
- */
-
-/* Operand sizes: 8-bit operands or specified/overridden size. */
-#define ByteOp (1<<0) /* 8-bit operands. */
-/* Destination operand type. */
-#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */
-#define DstReg (2<<1) /* Register operand. */
-#define DstMem (3<<1) /* Memory operand. */
-#define DstMask (3<<1)
-/* Source operand type. */
-#define SrcNone (0<<3) /* No source operand. */
-#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */
-#define SrcReg (1<<3) /* Register operand. */
-#define SrcMem (2<<3) /* Memory operand. */
-#define SrcMem16 (3<<3) /* Memory operand (16-bit). */
-#define SrcMem32 (4<<3) /* Memory operand (32-bit). */
-#define SrcImm (5<<3) /* Immediate operand. */
-#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */
-#define SrcMask (7<<3)
-/* Generic ModRM decode. */
-#define ModRM (1<<6)
-/* Destination is only written; never read. */
-#define Mov (1<<7)
-
-static uint8_t opcode_table[256] = {
- /* 0x00 - 0x07 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, 0,
- /* 0x08 - 0x0F */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, 0,
- /* 0x10 - 0x17 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, 0,
- /* 0x18 - 0x1F */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, 0,
- /* 0x20 - 0x27 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, 0,
- /* 0x28 - 0x2F */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, 0,
- /* 0x30 - 0x37 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, 0,
- /* 0x38 - 0x3F */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, 0,
- /* 0x40 - 0x4F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x50 - 0x5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x60 - 0x6F */
- 0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x70 - 0x7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x80 - 0x87 */
- ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
- ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM,
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- /* 0x88 - 0x8F */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
- ByteOp|DstReg|SrcMem|ModRM, DstReg|SrcMem|ModRM,
- 0, 0, 0, DstMem|SrcNone|ModRM|Mov,
- /* 0x90 - 0x9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xA0 - 0xA7 */
- ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov,
- ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov,
- ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
- ByteOp|ImplicitOps, ImplicitOps,
- /* 0xA8 - 0xAF */
- 0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
- ByteOp|ImplicitOps|Mov, ImplicitOps|Mov,
- ByteOp|ImplicitOps, ImplicitOps,
- /* 0xB0 - 0xBF */
- SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
- SrcImmByte, SrcImmByte, SrcImmByte, SrcImmByte,
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xC0 - 0xC7 */
- ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImmByte|ModRM, 0, 0,
- 0, 0, ByteOp|DstMem|SrcImm|ModRM, DstMem|SrcImm|ModRM,
- /* 0xC8 - 0xCF */
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xD0 - 0xD7 */
- ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
- ByteOp|DstMem|SrcImplicit|ModRM, DstMem|SrcImplicit|ModRM,
- 0, 0, 0, 0,
- /* 0xD8 - 0xDF */
- 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xE0 - 0xEF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xF0 - 0xF7 */
- 0, 0, 0, 0,
- 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM,
- /* 0xF8 - 0xFF */
- 0, 0, 0, 0,
- 0, 0, ByteOp|DstMem|SrcNone|ModRM, DstMem|SrcNone|ModRM
-};
-
-static uint8_t twobyte_table[256] = {
- /* 0x00 - 0x0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0,
- /* 0x10 - 0x1F */
- 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0,
- /* 0x20 - 0x2F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x30 - 0x3F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x40 - 0x47 */
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- /* 0x48 - 0x4F */
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem|ModRM|Mov,
- /* 0x50 - 0x5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x60 - 0x6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x70 - 0x7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x80 - 0x8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x90 - 0x9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xA0 - 0xA7 */
- 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
- /* 0xA8 - 0xAF */
- 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
- /* 0xB0 - 0xB7 */
- ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM,
- 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
- /* 0xB8 - 0xBF */
- 0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM,
- 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov,
- /* 0xC0 - 0xCF */
- 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xD0 - 0xDF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xE0 - 0xEF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xF0 - 0xFF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/*
- * insn_fetch - fetch the next 1 to 4 bytes from instruction stream
- *
- * @_type: u8, u16, u32, s8, s16, or s32
- * @_size: 1, 2, or 4 bytes
- * @_eip: address to fetch from guest memory
- * @_length: updated! increments the current instruction length counter by
_size
- *
- * INTERNAL this is used internally by svm_instrlen to fetch the next byte,
- * word, or dword from guest memory at location _eip. we currently use a local
- * unsigned long as the storage buffer since the most bytes we're gonna get
- * is limited to 4.
- */
-#define insn_fetch(_type, _size, _eip, _length) \
-({ unsigned long _x; \
- if ((rc = inst_copy_from_guest((unsigned char *)(&(_x)), \
- (unsigned long)(_eip), _size)) \
- != _size) \
- goto done; \
- (_eip) += (_size); \
- (_length) += (_size); \
- (_type)_x; \
-})
-
-
-/**
- * svn_instrlen - returns the current instructions length
- *
- * @regs: guest register state
- * @mode: guest operating mode
- *
- * EXTERNAL this routine calculates the length of the current instruction
- * pointed to by eip. The guest state is _not_ changed by this routine.
- */
-int svm_instrlen(struct cpu_user_regs *regs, int mode)
-{
- uint8_t b, d, twobyte = 0, rex_prefix = 0;
- uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
- unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i;
- int rc = 0;
- int length = 0;
- unsigned int tmp;
-
- /* Shadow copy of register state. Committed on successful emulation. */
- struct cpu_user_regs _regs = *regs;
-
- /* include CS for 16-bit modes */
- if (mode == X86EMUL_MODE_REAL || mode == X86EMUL_MODE_PROT16)
- _regs.eip += (_regs.cs << 4);
-
- switch ( mode )
- {
- case X86EMUL_MODE_REAL:
- case X86EMUL_MODE_PROT16:
- op_bytes = ad_bytes = 2;
- break;
- case X86EMUL_MODE_PROT32:
- op_bytes = ad_bytes = 4;
- break;
-#ifdef __x86_64__
- case X86EMUL_MODE_PROT64:
- op_bytes = 4;
- ad_bytes = 8;
- break;
-#endif
- default:
- return -1;
- }
-
- /* Legacy prefixes. */
- for ( i = 0; i < 8; i++ )
- {
- switch ( b = insn_fetch(uint8_t, 1, _regs.eip, length) )
- {
- case 0x66: /* operand-size override */
- op_bytes ^= 6; /* switch between 2/4 bytes */
- break;
- case 0x67: /* address-size override */
- if ( mode == X86EMUL_MODE_PROT64 )
- ad_bytes ^= 12; /* switch between 4/8 bytes */
- else
- ad_bytes ^= 6; /* switch between 2/4 bytes */
- break;
- case 0x2e: /* CS override */
- case 0x3e: /* DS override */
- case 0x26: /* ES override */
- case 0x64: /* FS override */
- case 0x65: /* GS override */
- case 0x36: /* SS override */
- break;
- case 0xf0: /* LOCK */
- lock_prefix = 1;
- break;
- case 0xf3: /* REP/REPE/REPZ */
- rep_prefix = 1;
- break;
- case 0xf2: /* REPNE/REPNZ */
- break;
- default:
- goto done_prefixes;
- }
- }
-done_prefixes:
-
- /* Note quite the same as 80386 real mode, but hopefully good enough. */
- if ( (mode == X86EMUL_MODE_REAL) && (ad_bytes != 2) ) {
- printf("sonofabitch!! we don't support 32-bit addresses in
realmode\n");
- goto cannot_emulate;
- }
-
- /* REX prefix. */
- if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
- {
- rex_prefix = b;
- if ( b & 8 )
- op_bytes = 8; /* REX.W */
- modrm_reg = (b & 4) << 1; /* REX.R */
- /* REX.B and REX.X do not need to be decoded. */
- b = insn_fetch(uint8_t, 1, _regs.eip, length);
- }
-
- /* Opcode byte(s). */
- d = opcode_table[b];
- if ( d == 0 )
- {
- /* Two-byte opcode? */
- if ( b == 0x0f )
- {
- twobyte = 1;
- b = insn_fetch(uint8_t, 1, _regs.eip, length);
- d = twobyte_table[b];
- }
-
- /* Unrecognised? */
- if ( d == 0 )
- goto cannot_emulate;
- }
-
- /* ModRM and SIB bytes. */
- if ( d & ModRM )
- {
- modrm = insn_fetch(uint8_t, 1, _regs.eip, length);
- modrm_mod |= (modrm & 0xc0) >> 6;
- modrm_reg |= (modrm & 0x38) >> 3;
- modrm_rm |= (modrm & 0x07);
-
- if ( modrm_mod == 3 )
- {
- DPRINTF("Cannot parse ModRM.mod == 3.\n");
- goto cannot_emulate;
- }
-
- if ( ad_bytes == 2 )
- {
- /* 16-bit ModR/M decode. */
- switch ( modrm_mod )
- {
- case 0:
- if ( modrm_rm == 6 )
- {
- length += 2;
- _regs.eip += 2; /* skip disp16 */
- }
- break;
- case 1:
- length += 1;
- _regs.eip += 1; /* skip disp8 */
- break;
- case 2:
- length += 2;
- _regs.eip += 2; /* skip disp16 */
- break;
- }
- }
- else
- {
- /* 32/64-bit ModR/M decode. */
- switch ( modrm_mod )
- {
- case 0:
- if ( (modrm_rm == 4) &&
- (((insn_fetch(uint8_t, 1, _regs.eip, length)) & 7)
- == 5) )
- {
- length += 4;
- _regs.eip += 4; /* skip disp32 specified by SIB.base */
- }
- else if ( modrm_rm == 5 )
- {
- length += 4;
- _regs.eip += 4; /* skip disp32 */
- }
- break;
- case 1:
- if ( modrm_rm == 4 )
- {
- insn_fetch(uint8_t, 1, _regs.eip, length);
- }
- length += 1;
- _regs.eip += 1; /* skip disp8 */
- break;
- case 2:
- if ( modrm_rm == 4 )
- {
- insn_fetch(uint8_t, 1, _regs.eip, length);
- }
- length += 4;
- _regs.eip += 4; /* skip disp32 */
- break;
- }
- }
- }
-
- /* Decode and fetch the destination operand: register or memory. */
- switch ( d & DstMask )
- {
- case ImplicitOps:
- /* Special instructions do their own operand decoding. */
- goto done;
- }
-
- /* Decode and fetch the source operand: register, memory or immediate. */
- switch ( d & SrcMask )
- {
- case SrcImm:
- tmp = (d & ByteOp) ? 1 : op_bytes;
- if ( tmp == 8 ) tmp = 4;
- /* NB. Immediates are sign-extended as necessary. */
- switch ( tmp )
- {
- case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
- case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
- case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
- }
- break;
- case SrcImmByte:
- insn_fetch(int8_t, 1, _regs.eip, length);
- break;
- }
-
- if ( twobyte )
- goto done;
-
- switch ( b )
- {
- case 0xa0 ... 0xa1: /* mov */
- length += ad_bytes;
- _regs.eip += ad_bytes; /* skip src displacement */
- break;
- case 0xa2 ... 0xa3: /* mov */
- length += ad_bytes;
- _regs.eip += ad_bytes; /* skip dst displacement */
- break;
- case 0xf6 ... 0xf7: /* Grp3 */
- switch ( modrm_reg )
- {
- case 0 ... 1: /* test */
- /* Special case in Grp3: test has an immediate source operand. */
- tmp = (d & ByteOp) ? 1 : op_bytes;
- if ( tmp == 8 ) tmp = 4;
- switch ( tmp )
- {
- case 1: insn_fetch(int8_t, 1, _regs.eip, length); break;
- case 2: insn_fetch(int16_t, 2, _regs.eip, length); break;
- case 4: insn_fetch(int32_t, 4, _regs.eip, length); break;
- }
- goto done;
- }
- break;
- }
-
-done:
- return length;
-
-cannot_emulate:
- DPRINTF("Cannot emulate %02x at address %lx (eip %lx, mode %d)\n",
- b, (unsigned long)_regs.eip, (unsigned long)regs->eip, mode);
- svm_dump_inst(_regs.eip);
- return -1;
-}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|