# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID af9809f51f81a3c43f276f00c81a52ef558afda4
# Parent a70c4f9657cc2a9606ea37650b351e222527d72f
[XEN] Clean up page-fault propagation when acessing guest addresses.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/mm.c | 8 ++--
xen/arch/x86/traps.c | 87 +++++++++++++++++++++++----------------------
xen/arch/x86/x86_emulate.c | 19 ++++++---
3 files changed, 63 insertions(+), 51 deletions(-)
diff -r a70c4f9657cc -r af9809f51f81 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Wed Jul 12 19:16:14 2006 +0100
+++ b/xen/arch/x86/mm.c Thu Jul 13 09:55:14 2006 +0100
@@ -3386,13 +3386,13 @@ static int ptwr_emulated_update(
if ( bytes != sizeof(paddr_t) )
{
paddr_t full;
- unsigned int offset = addr & (sizeof(paddr_t)-1);
+ unsigned int rc, offset = addr & (sizeof(paddr_t)-1);
/* Align address; read full word. */
addr &= ~(sizeof(paddr_t)-1);
- if ( copy_from_user(&full, (void *)addr, sizeof(paddr_t)) )
- {
- propagate_page_fault(addr, 0); /* read fault */
+ if ( (rc = copy_from_user(&full, (void *)addr, sizeof(paddr_t))) != 0 )
+ {
+ propagate_page_fault(addr+sizeof(paddr_t)-rc, 0); /* read fault */
return X86EMUL_PROPAGATE_FAULT;
}
/* Mask out bits provided by caller. */
diff -r a70c4f9657cc -r af9809f51f81 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Wed Jul 12 19:16:14 2006 +0100
+++ b/xen/arch/x86/traps.c Thu Jul 13 09:55:14 2006 +0100
@@ -403,16 +403,16 @@ static inline int do_trap(int trapnr, ch
return 0;
}
-#define DO_ERROR_NOCODE(trapnr, str, name) \
-asmlinkage int do_##name(struct cpu_user_regs *regs) \
-{ \
- return do_trap(trapnr, str, regs, 0); \
-}
-
-#define DO_ERROR(trapnr, str, name) \
-asmlinkage int do_##name(struct cpu_user_regs *regs) \
-{ \
- return do_trap(trapnr, str, regs, 1); \
+#define DO_ERROR_NOCODE(trapnr, str, name) \
+asmlinkage int do_##name(struct cpu_user_regs *regs) \
+{ \
+ return do_trap(trapnr, str, regs, 0); \
+}
+
+#define DO_ERROR(trapnr, str, name) \
+asmlinkage int do_##name(struct cpu_user_regs *regs) \
+{ \
+ return do_trap(trapnr, str, regs, 1); \
}
DO_ERROR_NOCODE( 0, "divide error", divide_error)
@@ -449,9 +449,9 @@ int cpuid_hypervisor_leaves(
static int emulate_forced_invalid_op(struct cpu_user_regs *regs)
{
- char signature[5], instr[2];
+ char sig[5], instr[2];
uint32_t a, b, c, d;
- unsigned long eip;
+ unsigned long eip, rc;
a = regs->eax;
b = regs->ebx;
@@ -460,14 +460,22 @@ static int emulate_forced_invalid_op(str
eip = regs->eip;
/* Check for forced emulation signature: ud2 ; .ascii "xen". */
- if ( copy_from_user(signature, (char *)eip, sizeof(signature)) ||
- memcmp(signature, "\xf\xbxen", sizeof(signature)) )
+ if ( (rc = copy_from_user(sig, (char *)eip, sizeof(sig))) != 0 )
+ {
+ propagate_page_fault(eip + sizeof(sig) - rc, 0);
+ return EXCRET_fault_fixed;
+ }
+ if ( memcmp(sig, "\xf\xbxen", sizeof(sig)) )
return 0;
- eip += sizeof(signature);
+ eip += sizeof(sig);
/* We only emulate CPUID. */
- if ( copy_from_user(instr, (char *)eip, sizeof(instr)) ||
- memcmp(instr, "\xf\xa2", sizeof(instr)) )
+ if ( ( rc = copy_from_user(instr, (char *)eip, sizeof(instr))) != 0 )
+ {
+ propagate_page_fault(eip + sizeof(instr) - rc, 0);
+ return EXCRET_fault_fixed;
+ }
+ if ( memcmp(instr, "\xf\xa2", sizeof(instr)) )
return 0;
eip += sizeof(instr);
@@ -923,17 +931,14 @@ static inline int admin_io_okay(
#define outl_user(_v, _p, _d, _r) \
(admin_io_okay(_p, 4, _d, _r) ? outl(_v, _p) : ((void)0))
-/* Propagate a fault back to the guest kernel. */
-#define PAGE_FAULT(_faultaddr, _errcode) \
-({ propagate_page_fault(_faultaddr, _errcode); \
- return EXCRET_fault_fixed; \
-})
-
-/* Isntruction fetch with error handling. */
-#define insn_fetch(_type, _size, _ptr) \
-({ unsigned long _x; \
- if ( get_user(_x, (_type *)eip) ) \
- PAGE_FAULT(eip, 0); /* read fault */ \
+/* Instruction fetch with error handling. */
+#define insn_fetch(_type, _size, _ptr) \
+({ unsigned long _rc, _x; \
+ if ( (_rc = copy_from_user(&_x, (_type *)eip, sizeof(_type))) != 0 ) \
+ { \
+ propagate_page_fault(eip + sizeof(_type) - _rc, 0); \
+ return EXCRET_fault_fixed; \
+ } \
eip += _size; (_type)_x; })
static int emulate_privileged_op(struct cpu_user_regs *regs)
@@ -941,7 +946,7 @@ static int emulate_privileged_op(struct
struct vcpu *v = current;
unsigned long *reg, eip = regs->eip, res;
u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0;
- unsigned int port, i, op_bytes = 4, data;
+ unsigned int port, i, op_bytes = 4, data, rc;
u32 l, h;
/* Legacy prefixes. */
@@ -1001,19 +1006,19 @@ static int emulate_privileged_op(struct
{
case 1:
data = (u8)inb_user((u16)regs->edx, v, regs);
- if ( put_user((u8)data, (u8 *)regs->edi) )
- PAGE_FAULT(regs->edi, PGERR_write_access);
break;
case 2:
data = (u16)inw_user((u16)regs->edx, v, regs);
- if ( put_user((u16)data, (u16 *)regs->edi) )
- PAGE_FAULT(regs->edi, PGERR_write_access);
break;
case 4:
data = (u32)inl_user((u16)regs->edx, v, regs);
- if ( put_user((u32)data, (u32 *)regs->edi) )
- PAGE_FAULT(regs->edi, PGERR_write_access);
break;
+ }
+ if ( (rc = copy_to_user((void *)regs->edi, &data, op_bytes)) != 0 )
+ {
+ propagate_page_fault(regs->edi + op_bytes - rc,
+ PGERR_write_access);
+ return EXCRET_fault_fixed;
}
regs->edi += (int)((regs->eflags & EF_DF) ? -op_bytes : op_bytes);
break;
@@ -1023,21 +1028,21 @@ static int emulate_privileged_op(struct
case 0x6f: /* OUTSW/OUTSL */
if ( !guest_io_okay((u16)regs->edx, op_bytes, v, regs) )
goto fail;
+ rc = copy_from_user(&data, (void *)regs->esi, op_bytes);
+ if ( rc != 0 )
+ {
+ propagate_page_fault(regs->esi + op_bytes - rc, 0);
+ return EXCRET_fault_fixed;
+ }
switch ( op_bytes )
{
case 1:
- if ( get_user(data, (u8 *)regs->esi) )
- PAGE_FAULT(regs->esi, 0); /* read fault */
outb_user((u8)data, (u16)regs->edx, v, regs);
break;
case 2:
- if ( get_user(data, (u16 *)regs->esi) )
- PAGE_FAULT(regs->esi, 0); /* read fault */
outw_user((u16)data, (u16)regs->edx, v, regs);
break;
case 4:
- if ( get_user(data, (u32 *)regs->esi) )
- PAGE_FAULT(regs->esi, 0); /* read fault */
outl_user((u32)data, (u16)regs->edx, v, regs);
break;
}
diff -r a70c4f9657cc -r af9809f51f81 xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c Wed Jul 12 19:16:14 2006 +0100
+++ b/xen/arch/x86/x86_emulate.c Thu Jul 13 09:55:14 2006 +0100
@@ -1138,12 +1138,16 @@ x86_emulate_read_std(
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
+ unsigned int rc;
+
*val = 0;
- if ( copy_from_user((void *)val, (void *)addr, bytes) )
- {
- propagate_page_fault(addr, 0); /* read fault */
+
+ if ( (rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0 )
+ {
+ propagate_page_fault(addr + bytes - rc, 0); /* read fault */
return X86EMUL_PROPAGATE_FAULT;
}
+
return X86EMUL_CONTINUE;
}
@@ -1154,11 +1158,14 @@ x86_emulate_write_std(
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
- if ( copy_to_user((void *)addr, (void *)&val, bytes) )
- {
- propagate_page_fault(addr, PGERR_write_access); /* write fault */
+ unsigned int rc;
+
+ if ( (rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0 )
+ {
+ propagate_page_fault(addr + bytes - rc, PGERR_write_access);
return X86EMUL_PROPAGATE_FAULT;
}
+
return X86EMUL_CONTINUE;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|