# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1172087938 0
# Node ID b010e556fe2c1e7cf73d3f279113ba1f4eac6a11
# Parent ad3ee81cc8c4bf44edc01404782c7a197f8764fc
x86: Extend emulator return codes.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
tools/tests/test_x86_emulator.c | 48 +++++++++++++++++++-------------------
xen/arch/x86/mm.c | 17 +++++++------
xen/arch/x86/mm/shadow/common.c | 16 ++++++------
xen/arch/x86/mm/shadow/multi.c | 19 ++++++++-------
xen/arch/x86/x86_emulate.c | 16 ++++++------
xen/include/asm-x86/x86_emulate.h | 24 +++++++++++--------
6 files changed, 76 insertions(+), 64 deletions(-)
diff -r ad3ee81cc8c4 -r b010e556fe2c tools/tests/test_x86_emulator.c
--- a/tools/tests/test_x86_emulator.c Wed Feb 21 11:42:04 2007 -0800
+++ b/tools/tests/test_x86_emulator.c Wed Feb 21 19:58:58 2007 +0000
@@ -43,7 +43,7 @@ static int read(
case 4: *val = *(u32 *)addr; break;
case 8: *val = *(unsigned long *)addr; break;
}
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int write(
@@ -61,7 +61,7 @@ static int write(
case 4: *(u32 *)addr = (u32)val; break;
case 8: *(unsigned long *)addr = val; break;
}
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int cmpxchg(
@@ -80,7 +80,7 @@ static int cmpxchg(
case 4: *(u32 *)addr = (u32)new; break;
case 8: *(unsigned long *)addr = new; break;
}
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int cmpxchg8b(
@@ -95,7 +95,7 @@ static int cmpxchg8b(
unsigned long addr = offset;
((unsigned long *)addr)[0] = new_lo;
((unsigned long *)addr)[1] = new_hi;
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static struct x86_emulate_ops emulops = {
@@ -138,7 +138,7 @@ int main(int argc, char **argv)
regs.eax = (unsigned long)res;
*res = 0x7FFFFFFF;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x92345677) ||
(regs.eflags != 0xa94) ||
(regs.eip != (unsigned long)&instr[2]) )
@@ -152,7 +152,7 @@ int main(int argc, char **argv)
regs.ecx = 0x12345678;
regs.eax = 0x7FFFFFFF;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(regs.ecx != 0x12345678) ||
(regs.eax != 0x92345677) ||
(regs.eflags != 0xa94) ||
@@ -171,7 +171,7 @@ int main(int argc, char **argv)
#endif
regs.eax = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x92345677) ||
(regs.ecx != 0x8000000FUL) ||
(regs.eip != (unsigned long)&instr[2]) )
@@ -185,7 +185,7 @@ int main(int argc, char **argv)
regs.ecx = ~0UL;
regs.eax = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x92345677) ||
(regs.ecx != 0x92345677UL) ||
(regs.eip != (unsigned long)&instr[2]) )
@@ -200,7 +200,7 @@ int main(int argc, char **argv)
regs.ecx = 0xAA;
regs.ebx = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x923456AA) ||
(regs.eflags != 0x244) ||
(regs.eax != 0x92345677UL) ||
@@ -216,7 +216,7 @@ int main(int argc, char **argv)
regs.ecx = 0xFF;
regs.ebx = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x923456AA) ||
((regs.eflags&0x240) != 0x200) ||
(regs.eax != 0xAABBCCAA) ||
@@ -232,7 +232,7 @@ int main(int argc, char **argv)
regs.ecx = 0x12345678;
regs.eax = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x12345678) ||
(regs.eflags != 0x200) ||
(regs.ecx != 0x923456AA) ||
@@ -249,7 +249,7 @@ int main(int argc, char **argv)
regs.ecx = 0xDDEEFF00L;
regs.ebx = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0xDDEEFF00) ||
(regs.eflags != 0x244) ||
(regs.eax != 0x923456AAUL) ||
@@ -266,7 +266,7 @@ int main(int argc, char **argv)
regs.esi = (unsigned long)res + 0;
regs.edi = (unsigned long)res + 2;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x44554455) ||
(regs.eflags != 0x200) ||
(regs.ecx != 22) ||
@@ -283,7 +283,7 @@ int main(int argc, char **argv)
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x2233445D) ||
((regs.eflags&0x201) != 0x201) ||
(regs.eip != (unsigned long)&instr[4]) )
@@ -298,7 +298,7 @@ int main(int argc, char **argv)
regs.eax = -32;
regs.edi = (unsigned long)(res+1);
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x2233445E) ||
((regs.eflags&0x201) != 0x201) ||
(regs.eip != (unsigned long)&instr[3]) )
@@ -318,7 +318,7 @@ int main(int argc, char **argv)
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(res[0] != 0x9999AAAA) ||
(res[1] != 0xCCCCFFFF) ||
((regs.eflags&0x240) != 0x240) ||
@@ -332,7 +332,7 @@ int main(int argc, char **argv)
regs.eip = (unsigned long)&instr[0];
regs.edi = (unsigned long)res;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(res[0] != 0x9999AAAA) ||
(res[1] != 0xCCCCFFFF) ||
(regs.eax != 0x9999AAAA) ||
@@ -350,7 +350,7 @@ int main(int argc, char **argv)
regs.eax = (unsigned long)res;
*res = 0x82;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x82) ||
(regs.ecx != 0xFFFFFF82) ||
((regs.eflags&0x240) != 0x200) ||
@@ -366,7 +366,7 @@ int main(int argc, char **argv)
regs.eax = (unsigned long)res;
*res = 0x1234aa82;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x1234aa82) ||
(regs.ecx != 0xaa82) ||
((regs.eflags&0x240) != 0x200) ||
@@ -382,7 +382,7 @@ int main(int argc, char **argv)
regs.eax = 0x12345678;
*res = 0x11111111;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(*res != 0x11116789) ||
(regs.eax != 0x12341111) ||
((regs.eflags&0x240) != 0x200) ||
@@ -396,7 +396,7 @@ int main(int argc, char **argv)
regs.eip = (unsigned long)&instr[0];
regs.eax = 0x00000000;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(regs.eax != 0x0000ffff) ||
((regs.eflags&0x240) != 0x200) ||
(regs.eip != (unsigned long)&instr[2]) )
@@ -410,7 +410,7 @@ int main(int argc, char **argv)
regs.eax = 0x12345678;
regs.ebp = 0xaaaaaaaa;
rc = x86_emulate(&ctxt, &emulops);
- if ( (rc != 0) ||
+ if ( (rc != X86EMUL_OKAY) ||
(regs.eax != 0xaaaaaab2) ||
((regs.eflags&0x240) != 0x200) ||
(regs.eip != (unsigned long)&instr[3]) )
@@ -454,7 +454,7 @@ int main(int argc, char **argv)
bcdres_emul |= (regs.eflags & EFLG_SF) ? 0x400 : 0;
bcdres_emul |= (regs.eflags & EFLG_CF) ? 0x200 : 0;
bcdres_emul |= (regs.eflags & EFLG_AF) ? 0x100 : 0;
- if ( (rc != 0) || (regs.eax > 255) ||
+ if ( (rc != X86EMUL_OKAY) || (regs.eax > 255) ||
(regs.eip != (unsigned long)&instr[1]) )
goto fail;
@@ -501,7 +501,7 @@ int main(int argc, char **argv)
if ( (i++ & 8191) == 0 )
printf(".");
rc = x86_emulate(&ctxt, &emulops);
- if ( rc != 0 )
+ if ( rc != X86EMUL_OKAY )
{
printf("failed at %%eip == %08x\n", (unsigned int)regs.eip);
return 1;
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/arch/x86/mm.c Wed Feb 21 19:58:58 2007 +0000
@@ -3151,10 +3151,10 @@ static int ptwr_emulated_read(
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;
+ return X86EMUL_EXCEPTION;
+ }
+
+ return X86EMUL_OKAY;
}
static int ptwr_emulated_update(
@@ -3190,7 +3190,7 @@ static int ptwr_emulated_update(
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;
+ return X86EMUL_EXCEPTION;
}
/* Mask out bits provided by caller. */
full &= ~((((paddr_t)1 << (bytes*8)) - 1) << (offset*8));
@@ -3273,7 +3273,7 @@ static int ptwr_emulated_update(
/* Finally, drop the old PTE. */
put_page_from_l1e(gl1e_to_ml1e(d, ol1e), d);
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int ptwr_emulated_write(
@@ -3333,6 +3333,7 @@ int ptwr_do_page_fault(struct vcpu *v, u
struct page_info *page;
l1_pgentry_t pte;
struct ptwr_emulate_ctxt ptwr_ctxt;
+ int rc;
LOCK_BIGLOCK(d);
@@ -3357,7 +3358,9 @@ int ptwr_do_page_fault(struct vcpu *v, u
IS_COMPAT(d) ? 32 : BITS_PER_LONG;
ptwr_ctxt.cr2 = addr;
ptwr_ctxt.pte = pte;
- if ( x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops) )
+
+ rc = x86_emulate(&ptwr_ctxt.ctxt, &ptwr_emulate_ops);
+ if ( rc == X86EMUL_UNHANDLEABLE )
goto bail;
UNLOCK_BIGLOCK(d);
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/arch/x86/mm/shadow/common.c Wed Feb 21 19:58:58 2007 +0000
@@ -191,7 +191,7 @@ static int hvm_translate_linear_addr(
gpf:
/* Inject #GP(0). */
hvm_inject_exception(TRAP_gp_fault, 0, 0);
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
}
static int
@@ -216,7 +216,7 @@ hvm_read(enum x86_segment seg,
// In this case, that is only a user vs supervisor access check.
//
if ( (rc = hvm_copy_from_guest_virt(val, addr, bytes)) == 0 )
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
/* If we got here, there was nothing mapped here, or a bad GFN
* was mapped here. This should never happen: we're here because
@@ -226,7 +226,7 @@ hvm_read(enum x86_segment seg,
if ( access_type == hvm_access_insn_fetch )
errcode |= PFEC_insn_fetch;
hvm_inject_exception(TRAP_page_fault, errcode, addr + bytes - rc);
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
}
static int
@@ -259,7 +259,7 @@ hvm_emulate_insn_fetch(enum x86_segment
/* Hit the cache. Simple memcpy. */
*val = 0;
memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes);
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
static int
@@ -352,10 +352,10 @@ pv_emulate_read(enum x86_segment seg,
if ( (rc = copy_from_user((void *)val, (void *)offset, bytes)) != 0 )
{
propagate_page_fault(offset + bytes - rc, 0); /* read fault */
- return X86EMUL_PROPAGATE_FAULT;
- }
-
- return X86EMUL_CONTINUE;
+ return X86EMUL_EXCEPTION;
+ }
+
+ return X86EMUL_OKAY;
}
static int
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/arch/x86/mm/shadow/multi.c Wed Feb 21 19:58:58 2007 +0000
@@ -2911,8 +2911,11 @@ static int sh_page_fault(struct vcpu *v,
* page is no longer a page table. This behaviour differs from native, but
* it seems very unlikely that any OS grants user access to page tables.
*/
- if ( (regs->error_code & PFEC_user_mode) ||
- x86_emulate(&emul_ctxt.ctxt, emul_ops) )
+ r = X86EMUL_UNHANDLEABLE;
+ if ( !(regs->error_code & PFEC_user_mode) )
+ r = x86_emulate(&emul_ctxt.ctxt, emul_ops);
+
+ if ( (r == X86EMUL_UNHANDLEABLE) || (r == X86EMUL_EXCEPTION) )
{
SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n",
mfn_x(gmfn));
@@ -3956,7 +3959,7 @@ sh_x86_emulate_write(struct vcpu *v, uns
ASSERT(((vaddr & ~PAGE_MASK) + bytes) <= PAGE_SIZE);
if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
skip = safe_not_to_verify_write(mfn, addr, src, bytes);
memcpy(addr, src, bytes);
@@ -3968,7 +3971,7 @@ sh_x86_emulate_write(struct vcpu *v, uns
sh_unmap_domain_page(addr);
shadow_audit_tables(v);
- return X86EMUL_CONTINUE;
+ return X86EMUL_OKAY;
}
int
@@ -3979,7 +3982,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u
mfn_t mfn;
void *addr;
unsigned long prev;
- int rv = X86EMUL_CONTINUE, skip;
+ int rv = X86EMUL_OKAY, skip;
ASSERT(shadow_locked_by_me(v->domain));
ASSERT(bytes <= sizeof(unsigned long));
@@ -3988,7 +3991,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, u
return X86EMUL_UNHANDLEABLE;
if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
skip = safe_not_to_verify_write(mfn, &new, &old, bytes);
@@ -4032,7 +4035,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v,
mfn_t mfn;
void *addr;
u64 old, new, prev;
- int rv = X86EMUL_CONTINUE, skip;
+ int rv = X86EMUL_OKAY, skip;
ASSERT(shadow_locked_by_me(v->domain));
@@ -4040,7 +4043,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v,
return X86EMUL_UNHANDLEABLE;
if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
- return X86EMUL_PROPAGATE_FAULT;
+ return X86EMUL_EXCEPTION;
old = (((u64) old_hi) << 32) | (u64) old_lo;
new = (((u64) new_hi) << 32) | (u64) new_lo;
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/arch/x86/x86_emulate.c
--- a/xen/arch/x86/x86_emulate.c Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/arch/x86/x86_emulate.c Wed Feb 21 19:58:58 2007 +0000
@@ -464,10 +464,10 @@ do{ __asm__ __volatile__ (
#define mode_64bit() (def_ad_bytes == 8)
-#define fail_if(p) \
-do { \
- rc = (p) ? X86EMUL_UNHANDLEABLE : 0; \
- if ( rc ) goto done; \
+#define fail_if(p) \
+do { \
+ rc = (p) ? X86EMUL_UNHANDLEABLE : X86EMUL_OKAY; \
+ if ( rc ) goto done; \
} while (0)
/* In future we will be able to generate arbitrary exceptions. */
@@ -726,7 +726,7 @@ x86_emulate(
uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0;
unsigned int op_bytes, def_op_bytes, ad_bytes, def_ad_bytes;
unsigned int lock_prefix = 0, rep_prefix = 0;
- int rc = 0;
+ int rc = X86EMUL_OKAY;
struct operand src, dst;
/* Data operand effective address (usually computed from ModRM). */
@@ -742,7 +742,7 @@ x86_emulate(
{
op_bytes = def_op_bytes = 4;
#ifndef __x86_64__
- return -1;
+ return X86EMUL_UNHANDLEABLE;
#endif
}
@@ -1593,7 +1593,7 @@ x86_emulate(
*ctxt->regs = _regs;
done:
- return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+ return rc;
special_insn:
dst.type = OP_NONE;
@@ -2383,5 +2383,5 @@ x86_emulate(
}
printk("\n");
#endif
- return -1;
+ return X86EMUL_UNHANDLEABLE;
}
diff -r ad3ee81cc8c4 -r b010e556fe2c xen/include/asm-x86/x86_emulate.h
--- a/xen/include/asm-x86/x86_emulate.h Wed Feb 21 11:42:04 2007 -0800
+++ b/xen/include/asm-x86/x86_emulate.h Wed Feb 21 19:58:58 2007 +0000
@@ -46,26 +46,32 @@ enum x86_segment {
};
/*
+ * Return codes from state-accessor functions and from x86_emulate().
+ */
+ /* Completed successfully. State modified appropriately. */
+#define X86EMUL_OKAY 0
+ /* Unhandleable access or emulation. No state modified. */
+#define X86EMUL_UNHANDLEABLE 1
+ /* Exception raised and requires delivery. */
+#define X86EMUL_EXCEPTION 2
+ /* Retry the emulation for some reason. No state modified. */
+#define X86EMUL_RETRY 3
+ /* (cmpxchg accessor): CMPXCHG failed. Maps to X86EMUL_RETRY in caller. */
+#define X86EMUL_CMPXCHG_FAILED 3
+
+/*
* These operations represent the instruction emulator's interface to memory.
*
* NOTES:
* 1. If the access fails (cannot emulate, or a standard access faults) then
* it is up to the memop to propagate the fault to the guest VM via
* some out-of-band mechanism, unknown to the emulator. The memop signals
- * failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will
+ * failure by returning X86EMUL_EXCEPTION to the emulator, which will
* then immediately bail.
* 2. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
* cmpxchg8b_emulated need support 8-byte accesses.
* 3. The emulator cannot handle 64-bit mode emulation on an x86/32 system.
*/
-/* Access completed successfully: continue emulation as normal. */
-#define X86EMUL_CONTINUE 0
-/* Access is unhandleable: bail from emulation and return error to caller. */
-#define X86EMUL_UNHANDLEABLE 1
-/* Terminate emulation but return success to the caller. */
-#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */
-#define X86EMUL_RETRY_INSTR 2 /* retry the instruction for some reason */
-#define X86EMUL_CMPXCHG_FAILED 2 /* cmpxchg did not see expected value */
struct x86_emulate_ops
{
/*
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|