# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxxx
# Node ID f5121d001d1ad66165d67c96a6e1f8f18375b1c3
# Parent 245f7ce8763e2f4968a4f0ce2ac7022b0eddb723
[XEN] Shadow-mode-refcount PTE update fix.
Add back in support for emulated PTE updates which is critical for
shdow_refcount operation.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/mm/shadow/common.c | 328 +++++++++++++++++++++----------------
xen/arch/x86/mm/shadow/multi.c | 20 +-
xen/arch/x86/mm/shadow/private.h | 11 -
xen/include/asm-x86/guest_access.h | 16 -
4 files changed, 217 insertions(+), 158 deletions(-)
diff -r 245f7ce8763e -r f5121d001d1a xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c Sat Dec 09 15:04:27 2006 +0000
+++ b/xen/arch/x86/mm/shadow/common.c Sat Dec 09 16:29:52 2006 +0000
@@ -185,15 +185,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 )
- {
-#if 0
- struct vcpu *v = current;
- SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n",
- v->domain->domain_id, v->vcpu_id,
- addr, *val, bytes);
-#endif
return X86EMUL_CONTINUE;
- }
/* If we got here, there was nothing mapped here, or a bad GFN
* was mapped here. This should never happen: we're here because
@@ -206,14 +198,202 @@ hvm_read(enum x86_segment seg,
return X86EMUL_PROPAGATE_FAULT;
}
-void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt,
- struct cpu_user_regs *regs)
+static int
+hvm_emulate_read(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ return hvm_read(seg, offset, val, bytes, hvm_access_read,
+ container_of(ctxt, struct sh_emulate_ctxt, ctxt));
+}
+
+static int
+hvm_emulate_insn_fetch(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct sh_emulate_ctxt *sh_ctxt =
+ container_of(ctxt, struct sh_emulate_ctxt, ctxt);
+ unsigned int insn_off = offset - ctxt->regs->eip;
+
+ /* Fall back if requested bytes are not in the prefetch cache. */
+ if ( unlikely((insn_off + bytes) > sh_ctxt->insn_buf_bytes) )
+ return hvm_read(seg, offset, val, bytes,
+ hvm_access_insn_fetch, sh_ctxt);
+
+ /* Hit the cache. Simple memcpy. */
+ *val = 0;
+ memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes);
+ return X86EMUL_CONTINUE;
+}
+
+static int
+hvm_emulate_write(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct sh_emulate_ctxt *sh_ctxt =
+ container_of(ctxt, struct sh_emulate_ctxt, ctxt);
+ struct vcpu *v = current;
+ unsigned long addr;
+ int rc;
+
+ rc = hvm_translate_linear_addr(
+ seg, offset, bytes, hvm_access_write, sh_ctxt, &addr);
+ if ( rc )
+ return rc;
+
+ return v->arch.shadow.mode->x86_emulate_write(
+ v, addr, &val, bytes, sh_ctxt);
+}
+
+static int
+hvm_emulate_cmpxchg(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long old,
+ unsigned long new,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct sh_emulate_ctxt *sh_ctxt =
+ container_of(ctxt, struct sh_emulate_ctxt, ctxt);
+ struct vcpu *v = current;
+ unsigned long addr;
+ int rc;
+
+ rc = hvm_translate_linear_addr(
+ seg, offset, bytes, hvm_access_write, sh_ctxt, &addr);
+ if ( rc )
+ return rc;
+
+ return v->arch.shadow.mode->x86_emulate_cmpxchg(
+ v, addr, old, new, bytes, sh_ctxt);
+}
+
+static int
+hvm_emulate_cmpxchg8b(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long old_lo,
+ unsigned long old_hi,
+ unsigned long new_lo,
+ unsigned long new_hi,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct sh_emulate_ctxt *sh_ctxt =
+ container_of(ctxt, struct sh_emulate_ctxt, ctxt);
+ struct vcpu *v = current;
+ unsigned long addr;
+ int rc;
+
+ rc = hvm_translate_linear_addr(
+ seg, offset, 8, hvm_access_write, sh_ctxt, &addr);
+ if ( rc )
+ return rc;
+
+ return v->arch.shadow.mode->x86_emulate_cmpxchg8b(
+ v, addr, old_lo, old_hi, new_lo, new_hi, sh_ctxt);
+}
+
+static struct x86_emulate_ops hvm_shadow_emulator_ops = {
+ .read = hvm_emulate_read,
+ .insn_fetch = hvm_emulate_insn_fetch,
+ .write = hvm_emulate_write,
+ .cmpxchg = hvm_emulate_cmpxchg,
+ .cmpxchg8b = hvm_emulate_cmpxchg8b,
+};
+
+static int
+pv_emulate_read(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long *val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ unsigned int rc;
+
+ *val = 0;
+ 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;
+}
+
+static int
+pv_emulate_write(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long val,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct sh_emulate_ctxt *sh_ctxt =
+ container_of(ctxt, struct sh_emulate_ctxt, ctxt);
+ struct vcpu *v = current;
+ return v->arch.shadow.mode->x86_emulate_write(
+ v, offset, &val, bytes, sh_ctxt);
+}
+
+static int
+pv_emulate_cmpxchg(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long old,
+ unsigned long new,
+ unsigned int bytes,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct sh_emulate_ctxt *sh_ctxt =
+ container_of(ctxt, struct sh_emulate_ctxt, ctxt);
+ struct vcpu *v = current;
+ return v->arch.shadow.mode->x86_emulate_cmpxchg(
+ v, offset, old, new, bytes, sh_ctxt);
+}
+
+static int
+pv_emulate_cmpxchg8b(enum x86_segment seg,
+ unsigned long offset,
+ unsigned long old_lo,
+ unsigned long old_hi,
+ unsigned long new_lo,
+ unsigned long new_hi,
+ struct x86_emulate_ctxt *ctxt)
+{
+ struct sh_emulate_ctxt *sh_ctxt =
+ container_of(ctxt, struct sh_emulate_ctxt, ctxt);
+ struct vcpu *v = current;
+ return v->arch.shadow.mode->x86_emulate_cmpxchg8b(
+ v, offset, old_lo, old_hi, new_lo, new_hi, sh_ctxt);
+}
+
+static struct x86_emulate_ops pv_shadow_emulator_ops = {
+ .read = pv_emulate_read,
+ .insn_fetch = pv_emulate_read,
+ .write = pv_emulate_write,
+ .cmpxchg = pv_emulate_cmpxchg,
+ .cmpxchg8b = pv_emulate_cmpxchg8b,
+};
+
+struct x86_emulate_ops *shadow_init_emulation(
+ struct sh_emulate_ctxt *sh_ctxt, struct cpu_user_regs *regs)
{
struct segment_register *creg;
struct vcpu *v = current;
unsigned long addr;
sh_ctxt->ctxt.regs = regs;
+
+ if ( !is_hvm_vcpu(v) )
+ {
+ sh_ctxt->ctxt.mode = X86EMUL_MODE_HOST;
+ return &pv_shadow_emulator_ops;
+ }
/* Segment cache initialisation. Primed with CS. */
sh_ctxt->valid_seg_regs = 0;
@@ -237,131 +417,9 @@ void shadow_init_emulation(struct sh_emu
!hvm_copy_from_guest_virt(
sh_ctxt->insn_buf, addr, sizeof(sh_ctxt->insn_buf)))
? sizeof(sh_ctxt->insn_buf) : 0;
-}
-
-static int
-sh_x86_emulate_read(enum x86_segment seg,
- unsigned long offset,
- unsigned long *val,
- unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
-{
- return hvm_read(seg, offset, val, bytes, hvm_access_read,
- container_of(ctxt, struct sh_emulate_ctxt, ctxt));
-}
-
-static int
-sh_x86_emulate_insn_fetch(enum x86_segment seg,
- unsigned long offset,
- unsigned long *val,
- unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
-{
- struct sh_emulate_ctxt *sh_ctxt =
- container_of(ctxt, struct sh_emulate_ctxt, ctxt);
- unsigned int insn_off = offset - ctxt->regs->eip;
-
- /* Fall back if requested bytes are not in the prefetch cache. */
- if ( unlikely((insn_off + bytes) > sh_ctxt->insn_buf_bytes) )
- return hvm_read(seg, offset, val, bytes,
- hvm_access_insn_fetch, sh_ctxt);
-
- /* Hit the cache. Simple memcpy. */
- *val = 0;
- memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes);
- return X86EMUL_CONTINUE;
-}
-
-static int
-sh_x86_emulate_write(enum x86_segment seg,
- unsigned long offset,
- unsigned long val,
- unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
-{
- struct sh_emulate_ctxt *sh_ctxt =
- container_of(ctxt, struct sh_emulate_ctxt, ctxt);
- struct vcpu *v = current;
- unsigned long addr;
- int rc;
-
- rc = hvm_translate_linear_addr(
- seg, offset, bytes, hvm_access_write, sh_ctxt, &addr);
- if ( rc )
- return rc;
-
-#if 0
- SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n",
- v->domain->domain_id, v->vcpu_id, addr, val, bytes);
-#endif
- return v->arch.shadow.mode->x86_emulate_write(
- v, addr, &val, bytes, sh_ctxt);
-}
-
-static int
-sh_x86_emulate_cmpxchg(enum x86_segment seg,
- unsigned long offset,
- unsigned long old,
- unsigned long new,
- unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
-{
- struct sh_emulate_ctxt *sh_ctxt =
- container_of(ctxt, struct sh_emulate_ctxt, ctxt);
- struct vcpu *v = current;
- unsigned long addr;
- int rc;
-
- rc = hvm_translate_linear_addr(
- seg, offset, bytes, hvm_access_write, sh_ctxt, &addr);
- if ( rc )
- return rc;
-
-#if 0
- SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx n:=%#lx bytes=%u\n",
- v->domain->domain_id, v->vcpu_id, addr, old, new, bytes);
-#endif
- return v->arch.shadow.mode->x86_emulate_cmpxchg(
- v, addr, old, new, bytes, sh_ctxt);
-}
-
-static int
-sh_x86_emulate_cmpxchg8b(enum x86_segment seg,
- unsigned long offset,
- unsigned long old_lo,
- unsigned long old_hi,
- unsigned long new_lo,
- unsigned long new_hi,
- struct x86_emulate_ctxt *ctxt)
-{
- struct sh_emulate_ctxt *sh_ctxt =
- container_of(ctxt, struct sh_emulate_ctxt, ctxt);
- struct vcpu *v = current;
- unsigned long addr;
- int rc;
-
- rc = hvm_translate_linear_addr(
- seg, offset, 8, hvm_access_write, sh_ctxt, &addr);
- if ( rc )
- return rc;
-
-#if 0
- SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx:%lx n:=%#lx:%lx\n",
- v->domain->domain_id, v->vcpu_id, addr, old_hi, old_lo,
- new_hi, new_lo, ctxt);
-#endif
- return v->arch.shadow.mode->x86_emulate_cmpxchg8b(
- v, addr, old_lo, old_hi, new_lo, new_hi, sh_ctxt);
-}
-
-
-struct x86_emulate_ops shadow_emulator_ops = {
- .read = sh_x86_emulate_read,
- .insn_fetch = sh_x86_emulate_insn_fetch,
- .write = sh_x86_emulate_write,
- .cmpxchg = sh_x86_emulate_cmpxchg,
- .cmpxchg8b = sh_x86_emulate_cmpxchg8b,
-};
+
+ return &hvm_shadow_emulator_ops;
+}
/**************************************************************************/
/* Code for "promoting" a guest page to the point where the shadow code is
diff -r 245f7ce8763e -r f5121d001d1a xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c Sat Dec 09 15:04:27 2006 +0000
+++ b/xen/arch/x86/mm/shadow/multi.c Sat Dec 09 16:29:52 2006 +0000
@@ -2585,6 +2585,7 @@ static int sh_page_fault(struct vcpu *v,
shadow_l1e_t sl1e, *ptr_sl1e;
paddr_t gpa;
struct sh_emulate_ctxt emul_ctxt;
+ struct x86_emulate_ops *emul_ops;
int r, mmio;
fetch_type_t ft = 0;
@@ -2811,13 +2812,14 @@ static int sh_page_fault(struct vcpu *v,
return EXCRET_fault_fixed;
emulate:
- if ( !is_hvm_domain(d) || !guest_mode(regs) )
+ if ( !shadow_mode_refcounts(d) || !guest_mode(regs) )
goto not_a_shadow_fault;
- hvm_store_cpu_guest_regs(v, regs, NULL);
+ if ( is_hvm_domain(d) )
+ hvm_store_cpu_guest_regs(v, regs, NULL);
SHADOW_PRINTK("emulate: eip=%#lx\n", regs->eip);
- shadow_init_emulation(&emul_ctxt, regs);
+ emul_ops = shadow_init_emulation(&emul_ctxt, regs);
/*
* We do not emulate user writes. Instead we use them as a hint that the
@@ -2825,7 +2827,7 @@ static int sh_page_fault(struct vcpu *v,
* it seems very unlikely that any OS grants user access to page tables.
*/
if ( (regs->error_code & PFEC_user_mode) ||
- x86_emulate_memop(&emul_ctxt.ctxt, &shadow_emulator_ops) )
+ x86_emulate_memop(&emul_ctxt.ctxt, emul_ops) )
{
SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n",
mfn_x(gmfn));
@@ -2837,7 +2839,8 @@ static int sh_page_fault(struct vcpu *v,
}
/* Emulator has changed the user registers: write back */
- hvm_load_cpu_guest_regs(v, regs);
+ if ( is_hvm_domain(d) )
+ hvm_load_cpu_guest_regs(v, regs);
goto done;
mmio:
@@ -3814,9 +3817,10 @@ static inline void * emulate_map_dest(st
page_fault:
errcode |= PFEC_write_access;
- if ( ring_3(sh_ctxt->ctxt.regs) )
- errcode |= PFEC_user_mode;
- hvm_inject_exception(TRAP_page_fault, errcode, vaddr);
+ if ( is_hvm_vcpu(v) )
+ hvm_inject_exception(TRAP_page_fault, errcode, vaddr);
+ else
+ propagate_page_fault(vaddr, errcode);
return NULL;
}
diff -r 245f7ce8763e -r f5121d001d1a xen/arch/x86/mm/shadow/private.h
--- a/xen/arch/x86/mm/shadow/private.h Sat Dec 09 15:04:27 2006 +0000
+++ b/xen/arch/x86/mm/shadow/private.h Sat Dec 09 16:29:52 2006 +0000
@@ -257,9 +257,6 @@ static inline int sh_type_is_pinnable(st
* Various function declarations
*/
-/* x86 emulator support */
-extern struct x86_emulate_ops shadow_emulator_ops;
-
/* Hash table functions */
mfn_t shadow_hash_lookup(struct vcpu *v, unsigned long n, unsigned int t);
void shadow_hash_insert(struct vcpu *v,
@@ -513,17 +510,17 @@ struct sh_emulate_ctxt {
struct sh_emulate_ctxt {
struct x86_emulate_ctxt ctxt;
- /* Cache of up to 15 bytes of instruction. */
+ /* [HVM] Cache of up to 15 bytes of instruction. */
uint8_t insn_buf[15];
uint8_t insn_buf_bytes;
- /* Cache of segment registers already gathered for this emulation. */
+ /* [HVM] Cache of segment registers already gathered for this emulation. */
unsigned int valid_seg_regs;
struct segment_register seg_reg[6];
};
-void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt,
- struct cpu_user_regs *regs);
+struct x86_emulate_ops *shadow_init_emulation(
+ struct sh_emulate_ctxt *sh_ctxt, struct cpu_user_regs *regs);
#endif /* _XEN_SHADOW_PRIVATE_H */
diff -r 245f7ce8763e -r f5121d001d1a xen/include/asm-x86/guest_access.h
--- a/xen/include/asm-x86/guest_access.h Sat Dec 09 15:04:27 2006 +0000
+++ b/xen/include/asm-x86/guest_access.h Sat Dec 09 16:29:52 2006 +0000
@@ -34,7 +34,7 @@
#define copy_to_guest_offset(hnd, off, ptr, nr) ({ \
const typeof(ptr) _x = (hnd).p; \
const typeof(ptr) _y = (ptr); \
- shadow_mode_translate(current->domain) ? \
+ is_hvm_vcpu(current) ? \
copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \
copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \
})
@@ -46,7 +46,7 @@
#define copy_from_guest_offset(ptr, hnd, off, nr) ({ \
const typeof(ptr) _x = (hnd).p; \
const typeof(ptr) _y = (ptr); \
- shadow_mode_translate(current->domain) ? \
+ is_hvm_vcpu(current) ? \
copy_from_user_hvm(_y, _x+(off), sizeof(*_x)*(nr)) :\
copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \
})
@@ -55,7 +55,7 @@
#define copy_field_to_guest(hnd, ptr, field) ({ \
const typeof(&(ptr)->field) _x = &(hnd).p->field; \
const typeof(&(ptr)->field) _y = &(ptr)->field; \
- shadow_mode_translate(current->domain) ? \
+ is_hvm_vcpu(current) ? \
copy_to_user_hvm(_x, _y, sizeof(*_x)) : \
copy_to_user(_x, _y, sizeof(*_x)); \
})
@@ -64,7 +64,7 @@
#define copy_field_from_guest(ptr, hnd, field) ({ \
const typeof(&(ptr)->field) _x = &(hnd).p->field; \
const typeof(&(ptr)->field) _y = &(ptr)->field; \
- shadow_mode_translate(current->domain) ? \
+ is_hvm_vcpu(current) ? \
copy_from_user_hvm(_y, _x, sizeof(*_x)) : \
copy_from_user(_y, _x, sizeof(*_x)); \
})
@@ -80,7 +80,7 @@
#define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \
const typeof(ptr) _x = (hnd).p; \
const typeof(ptr) _y = (ptr); \
- shadow_mode_translate(current->domain) ? \
+ is_hvm_vcpu(current) ? \
copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \
__copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \
})
@@ -88,7 +88,7 @@
#define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \
const typeof(ptr) _x = (hnd).p; \
const typeof(ptr) _y = (ptr); \
- shadow_mode_translate(current->domain) ? \
+ is_hvm_vcpu(current) ? \
copy_from_user_hvm(_y, _x+(off),sizeof(*_x)*(nr)) : \
__copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \
})
@@ -96,7 +96,7 @@
#define __copy_field_to_guest(hnd, ptr, field) ({ \
const typeof(&(ptr)->field) _x = &(hnd).p->field; \
const typeof(&(ptr)->field) _y = &(ptr)->field; \
- shadow_mode_translate(current->domain) ? \
+ is_hvm_vcpu(current) ? \
copy_to_user_hvm(_x, _y, sizeof(*_x)) : \
__copy_to_user(_x, _y, sizeof(*_x)); \
})
@@ -104,7 +104,7 @@
#define __copy_field_from_guest(ptr, hnd, field) ({ \
const typeof(&(ptr)->field) _x = &(hnd).p->field; \
const typeof(&(ptr)->field) _y = &(ptr)->field; \
- shadow_mode_translate(current->domain) ? \
+ is_hvm_vcpu(current) ? \
copy_from_user_hvm(_x, _y, sizeof(*_x)) : \
__copy_from_user(_y, _x, sizeof(*_x)); \
})
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|