SHA256
1
0
forked from pool/xen
Files
xen/non-flat-pm.patch

462 lines
16 KiB
Diff

From: Jan Beulich
Bugzilla #214568
Index: xen-3.0.3-testing/xen/arch/x86/hvm/platform.c
===================================================================
--- xen-3.0.3-testing.orig/xen/arch/x86/hvm/platform.c
+++ xen-3.0.3-testing/xen/arch/x86/hvm/platform.c
@@ -883,19 +883,14 @@ 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);
- inst_len = hvm_instruction_length(regs, hvm_guest_x86_mode(v));
+ inst_addr = hvm_get_segment_base(current, seg_cs) + regs->eip;
+ inst_len = hvm_instruction_length(inst_addr, hvm_guest_x86_mode(v));
if ( inst_len <= 0 )
{
printk("handle_mmio: failed to get instruction length\n");
domain_crash_synchronous();
}
- realmode = hvm_realmode(v);
- if (realmode)
- inst_addr = (regs->cs << 4) + regs->eip;
- else
- inst_addr = regs->eip;
-
memset(inst, 0, MAX_INST_LEN);
ret = inst_copy_from_guest(inst, inst_addr, inst_len);
if (ret != inst_len) {
@@ -904,6 +899,7 @@ void handle_mmio(unsigned long va, unsig
}
init_instruction(&mmio_inst);
+ realmode = hvm_realmode(v);
if (hvm_decode(realmode, inst, &mmio_inst) == DECODE_failure) {
printk("handle_mmio: failed to decode instruction\n");
Index: xen-3.0.3-testing/xen/arch/x86/hvm/svm/svm.c
===================================================================
--- xen-3.0.3-testing.orig/xen/arch/x86/hvm/svm/svm.c
+++ xen-3.0.3-testing/xen/arch/x86/hvm/svm/svm.c
@@ -507,6 +507,24 @@ unsigned long svm_get_ctrl_reg(struct vc
return 0; /* dummy */
}
+static unsigned long svm_get_segment_base(struct vcpu *v, enum segment seg)
+{
+ switch ( seg )
+ {
+ case seg_cs: return v->arch.hvm_svm.vmcb->cs.base;
+ case seg_ds: return v->arch.hvm_svm.vmcb->ds.base;
+ case seg_es: return v->arch.hvm_svm.vmcb->es.base;
+ case seg_fs: return v->arch.hvm_svm.vmcb->fs.base;
+ case seg_gs: return v->arch.hvm_svm.vmcb->gs.base;
+ case seg_ss: return v->arch.hvm_svm.vmcb->ss.base;
+ case seg_tr: return v->arch.hvm_svm.vmcb->tr.base;
+ case seg_gdtr: return v->arch.hvm_svm.vmcb->gdtr.base;
+ case seg_idtr: return v->arch.hvm_svm.vmcb->idtr.base;
+ case seg_ldtr: return v->arch.hvm_svm.vmcb->ldtr.base;
+ }
+ BUG();
+ return 0;
+}
/* Make sure that xen intercepts any FP accesses from current */
static void svm_stts(struct vcpu *v)
@@ -887,6 +905,7 @@ int start_svm(void)
hvm_funcs.pae_enabled = svm_pae_enabled;
hvm_funcs.guest_x86_mode = svm_guest_x86_mode;
hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg;
+ hvm_funcs.get_segment_base = svm_get_segment_base;
hvm_funcs.update_host_cr3 = svm_update_host_cr3;
Index: xen-3.0.3-testing/xen/arch/x86/hvm/vmx/vmx.c
===================================================================
--- xen-3.0.3-testing.orig/xen/arch/x86/hvm/vmx/vmx.c
+++ xen-3.0.3-testing/xen/arch/x86/hvm/vmx/vmx.c
@@ -610,7 +610,27 @@ static unsigned long vmx_get_ctrl_reg(st
return 0; /* dummy */
}
+static unsigned long vmx_get_segment_base(struct vcpu *v, enum segment seg)
+{
+ unsigned long base;
+ BUG_ON(v != current);
+ switch ( seg )
+ {
+ case seg_cs: __vmread(GUEST_CS_BASE, &base); break;
+ case seg_ds: __vmread(GUEST_DS_BASE, &base); break;
+ case seg_es: __vmread(GUEST_ES_BASE, &base); break;
+ case seg_fs: __vmread(GUEST_FS_BASE, &base); break;
+ case seg_gs: __vmread(GUEST_GS_BASE, &base); break;
+ case seg_ss: __vmread(GUEST_SS_BASE, &base); break;
+ case seg_tr: __vmread(GUEST_TR_BASE, &base); break;
+ case seg_gdtr: __vmread(GUEST_GDTR_BASE, &base); break;
+ case seg_idtr: __vmread(GUEST_IDTR_BASE, &base); break;
+ case seg_ldtr: __vmread(GUEST_LDTR_BASE, &base); break;
+ default: BUG(); base = 0; break;
+ }
+ return base;
+}
/* Make sure that xen intercepts any FP accesses from current */
static void vmx_stts(struct vcpu *v)
@@ -753,6 +773,7 @@ static void vmx_setup_hvm_funcs(void)
hvm_funcs.pae_enabled = vmx_pae_enabled;
hvm_funcs.guest_x86_mode = vmx_guest_x86_mode;
hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg;
+ hvm_funcs.get_segment_base = vmx_get_segment_base;
hvm_funcs.update_host_cr3 = vmx_update_host_cr3;
Index: xen-3.0.3-testing/xen/include/asm-x86/hvm/hvm.h
===================================================================
--- xen-3.0.3-testing.orig/xen/include/asm-x86/hvm/hvm.h
+++ xen-3.0.3-testing/xen/include/asm-x86/hvm/hvm.h
@@ -20,6 +20,19 @@
#ifndef __ASM_X86_HVM_HVM_H__
#define __ASM_X86_HVM_HVM_H__
+enum segment {
+ seg_cs,
+ seg_ss,
+ seg_ds,
+ seg_es,
+ seg_fs,
+ seg_gs,
+ seg_tr,
+ seg_ldtr,
+ seg_gdtr,
+ seg_idtr
+};
+
/*
* The hardware virtual machine (HVM) interface abstracts away from the
* x86/x86_64 CPU virtualization assist specifics. Currently this interface
@@ -52,6 +65,7 @@ struct hvm_function_table {
* 1) determine whether the guest is in real or vm8086 mode,
* 2) determine whether paging is enabled,
* 3) return the current guest control-register value
+ * 4) return the current guest segment descriptor base
*/
int (*realmode)(struct vcpu *v);
int (*paging_enabled)(struct vcpu *v);
@@ -59,6 +73,7 @@ struct hvm_function_table {
int (*pae_enabled)(struct vcpu *v);
int (*guest_x86_mode)(struct vcpu *v);
unsigned long (*get_guest_ctrl_reg)(struct vcpu *v, unsigned int num);
+ unsigned long (*get_segment_base)(struct vcpu *v, enum segment seg);
/*
* Re-set the value of CR3 that Xen runs on when handling VM exits
@@ -157,7 +172,7 @@ hvm_guest_x86_mode(struct vcpu *v)
return hvm_funcs.guest_x86_mode(v);
}
-int hvm_instruction_length(struct cpu_user_regs *regs, int mode);
+int hvm_instruction_length(unsigned long pc, int mode);
static inline void
hvm_update_host_cr3(struct vcpu *v)
@@ -176,6 +191,12 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, u
return 0; /* force to fail */
}
+static inline unsigned long
+hvm_get_segment_base(struct vcpu *v, enum segment seg)
+{
+ return hvm_funcs.get_segment_base(v, seg);
+}
+
void hvm_stts(struct vcpu *v);
void hvm_set_guest_time(struct vcpu *v, u64 gtime);
void hvm_do_resume(struct vcpu *v);
Index: xen-3.0.3-testing/xen/arch/x86/hvm/instrlen.c
===================================================================
--- xen-3.0.3-testing.orig/xen/arch/x86/hvm/instrlen.c
+++ xen-3.0.3-testing/xen/arch/x86/hvm/instrlen.c
@@ -20,7 +20,6 @@
#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 */
@@ -195,54 +194,51 @@ static uint8_t twobyte_table[256] = {
};
/*
- * 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
+ * insn_fetch - fetch the next byte from instruction stream
*/
-#define insn_fetch(_type, _size) \
-({ unsigned long _x, _ptr = _regs.eip; \
- if ( mode == X86EMUL_MODE_REAL ) _ptr += _regs.cs << 4; \
- rc = inst_copy_from_guest((unsigned char *)(&(_x)), _ptr, _size); \
- if ( rc != _size ) goto done; \
- _regs.eip += (_size); \
- length += (_size); \
- (_type)_x; \
+#define insn_fetch() \
+({ uint8_t _x; \
+ if ( inst_copy_from_guest(&_x, pc, 1) != 1 ) { \
+ DPRINTK("Cannot read from address %lx (eip %lx, mode %d)\n", \
+ pc, org_pc, mode); \
+ return -1; \
+ } \
+ pc += 1; \
+ length += 1; \
+ _x; \
})
/**
* hvm_instruction_length - returns the current instructions length
*
- * @regs: guest register state
+ * @org_pc: guest instruction pointer
* @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.
+ * pointed to by org_pc. The guest state is _not_ changed by this routine.
*/
-int hvm_instruction_length(struct cpu_user_regs *regs, int mode)
+int hvm_instruction_length(unsigned long org_pc, 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, i;
- int rc = 0;
+ unsigned int op_default, op_bytes, ad_default, ad_bytes, i;
int length = 0;
unsigned int tmp;
-
- /* Shadow copy of register state. Committed on successful emulation. */
- struct cpu_user_regs _regs = *regs;
+ unsigned long pc = org_pc;
switch ( mode )
{
case X86EMUL_MODE_REAL:
case X86EMUL_MODE_PROT16:
- op_bytes = ad_bytes = 2;
+ op_bytes = op_default = ad_bytes = ad_default = 2;
break;
case X86EMUL_MODE_PROT32:
- op_bytes = ad_bytes = 4;
+ op_bytes = op_default = ad_bytes = ad_default = 4;
break;
#ifdef __x86_64__
case X86EMUL_MODE_PROT64:
- op_bytes = 4;
- ad_bytes = 8;
+ op_bytes = op_default = 4;
+ ad_bytes = ad_default = 8;
break;
#endif
default:
@@ -252,16 +248,16 @@ int hvm_instruction_length(struct cpu_us
/* Legacy prefixes. */
for ( i = 0; i < 8; i++ )
{
- switch ( b = insn_fetch(uint8_t, 1) )
+ switch ( b = insn_fetch() )
{
case 0x66: /* operand-size override */
- op_bytes ^= 6; /* switch between 2/4 bytes */
+ op_bytes = op_default ^ 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 */
+ ad_bytes = ad_default ^ 12; /* switch between 4/8 bytes */
else
- ad_bytes ^= 6; /* switch between 2/4 bytes */
+ ad_bytes = ad_default ^ 6; /* switch between 2/4 bytes */
break;
case 0x2e: /* CS override */
case 0x3e: /* DS override */
@@ -273,21 +269,30 @@ int hvm_instruction_length(struct cpu_us
case 0xf3: /* REP/REPE/REPZ */
case 0xf2: /* REPNE/REPNZ */
break;
+#ifdef __x86_64__
+ case 0x40 ... 0x4f:
+ if ( mode == X86EMUL_MODE_PROT64 )
+ {
+ rex_prefix = b;
+ continue;
+ }
+ /* FALLTHRU */
+#endif
default:
goto done_prefixes;
}
+ rex_prefix = 0;
}
done_prefixes:
/* REX prefix. */
- if ( (mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40) )
+ if ( rex_prefix )
{
- rex_prefix = b;
- if ( b & 8 )
- op_bytes = 8; /* REX.W */
- modrm_reg = (b & 4) << 1; /* REX.R */
+ if ( rex_prefix & 8 )
+ op_bytes = 8; /* REX.W */
+ modrm_reg = (rex_prefix & 4) << 1; /* REX.R */
/* REX.B and REX.X do not need to be decoded. */
- b = insn_fetch(uint8_t, 1);
+ b = insn_fetch();
}
/* Opcode byte(s). */
@@ -298,7 +303,7 @@ done_prefixes:
if ( b == 0x0f )
{
twobyte = 1;
- b = insn_fetch(uint8_t, 1);
+ b = insn_fetch();
d = twobyte_table[b];
}
@@ -310,7 +315,7 @@ done_prefixes:
/* ModRM and SIB bytes. */
if ( d & ModRM )
{
- modrm = insn_fetch(uint8_t, 1);
+ modrm = insn_fetch();
modrm_mod |= (modrm & 0xc0) >> 6;
modrm_reg |= (modrm & 0x38) >> 3;
modrm_rm |= (modrm & 0x07);
@@ -330,16 +335,16 @@ done_prefixes:
if ( modrm_rm == 6 )
{
length += 2;
- _regs.eip += 2; /* skip disp16 */
+ pc += 2; /* skip disp16 */
}
break;
case 1:
length += 1;
- _regs.eip += 1; /* skip disp8 */
+ pc += 1; /* skip disp8 */
break;
case 2:
length += 2;
- _regs.eip += 2; /* skip disp16 */
+ pc += 2; /* skip disp16 */
break;
}
}
@@ -350,33 +355,34 @@ done_prefixes:
{
case 0:
if ( (modrm_rm == 4) &&
- (((insn_fetch(uint8_t, 1)) & 7)
- == 5) )
+ ((insn_fetch() & 7) == 5) )
{
length += 4;
- _regs.eip += 4; /* skip disp32 specified by SIB.base */
+ pc += 4; /* skip disp32 specified by SIB.base */
}
else if ( modrm_rm == 5 )
{
length += 4;
- _regs.eip += 4; /* skip disp32 */
+ pc += 4; /* skip disp32 */
}
break;
case 1:
if ( modrm_rm == 4 )
{
- insn_fetch(uint8_t, 1);
+ length += 1;
+ pc += 1;
}
length += 1;
- _regs.eip += 1; /* skip disp8 */
+ pc += 1; /* skip disp8 */
break;
case 2:
if ( modrm_rm == 4 )
{
- insn_fetch(uint8_t, 1);
+ length += 1;
+ pc += 1;
}
length += 4;
- _regs.eip += 4; /* skip disp32 */
+ pc += 4; /* skip disp32 */
break;
}
}
@@ -397,15 +403,12 @@ done_prefixes:
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); break;
- case 2: insn_fetch(int16_t, 2); break;
- case 4: insn_fetch(int32_t, 4); break;
- }
+ length += tmp;
+ pc += tmp;
break;
case SrcImmByte:
- insn_fetch(int8_t, 1);
+ length += 1;
+ pc += 1;
break;
}
@@ -414,13 +417,9 @@ done_prefixes:
switch ( b )
{
- case 0xa0 ... 0xa1: /* mov */
- length += ad_bytes;
- _regs.eip += ad_bytes; /* skip src displacement */
- break;
- case 0xa2 ... 0xa3: /* mov */
+ case 0xa0 ... 0xa3: /* mov */
length += ad_bytes;
- _regs.eip += ad_bytes; /* skip dst displacement */
+ pc += ad_bytes; /* skip src/dst displacement */
break;
case 0xf6 ... 0xf7: /* Grp3 */
switch ( modrm_reg )
@@ -429,12 +428,8 @@ done_prefixes:
/* 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); break;
- case 2: insn_fetch(int16_t, 2); break;
- case 4: insn_fetch(int32_t, 4); break;
- }
+ length += tmp;
+ pc += tmp;
goto done;
}
break;
@@ -445,6 +440,6 @@ done:
cannot_emulate:
DPRINTK("Cannot emulate %02x at address %lx (eip %lx, mode %d)\n",
- b, (unsigned long)_regs.eip, (unsigned long)regs->eip, mode);
+ b, pc, org_pc, mode);
return -1;
}