Hi,
Below is my very first attempt to write inline assembler, for atomic
updates of PAE pagetable entries using cmpxchg8b. It builds, but is
completely untested otherwise as I don't have a PAE-enabled guest kernel
yet ...
Can someone with more experience than me please have a look at it?
Thanks,
Gerd
--- xen.orig/arch/x86/mm.c 2005-04-19 11:56:20.000000000 +0200
+++ xen/arch/x86/mm.c 2005-04-19 15:29:01.000000000 +0200
@@ -834,12 +846,55 @@ static void free_l4_table(struct pfn_inf
#endif /* __x86_64__ */
+static inline int cmpxchg8b_user(u64 *ptr, u64 oval, u64 nval)
+{
+ u32 o_hi = oval >> 32;
+ u32 o_lo = oval & 0xffffffff;
+ u32 n_hi = nval >> 32;
+ u32 n_lo = nval & 0xffffffff;
+ u32 rc = 0;
+
+ __asm__ __volatile__ (
+ "1: " LOCK_PREFIX "cmpxchg8b %[ptr]\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "3: movl $1, %[rc]\n"
+ " jmp 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,3b\n"
+ ".previous"
+ : "=d" (o_hi), "=a" (o_lo), "=c" (n_hi), "=b" (n_lo),
+ [rc] "=r" (rc), [ptr] "m" (*__xg((volatile void *)ptr))
+ : "0" (o_hi), "1" (o_lo)
+ : "memory");
+ if ((o_hi != (oval >> 32)) ||
+ (o_lo != (oval & 0xffffffff)))
+ rc = 1;
+ return rc;
+}
static inline int update_l1e(l1_pgentry_t *pl1e,
l1_pgentry_t ol1e,
l1_pgentry_t nl1e)
{
- /* FIXME: breaks with PAE */
+#if defined(__i386__) && defined(CONFIG_X86_PAE)
+
+ int rc;
+
+ rc = cmpxchg8b_user(pl1e, l1e_get_value(ol1e),
+ l1e_get_value(nl1e));
+ if (unlikely(rc))
+ {
+ MEM_LOG("Failed to update %llx -> %llx [pae]\n",
+ l1e_get_value(ol1e), l1e_get_value(nl1e));
+ return 0;
+ }
+ return 1;
+
+#else
+
unsigned long o = l1e_get_value(ol1e);
unsigned long n = l1e_get_value(nl1e);
@@ -850,8 +905,9 @@ static inline int update_l1e(l1_pgentry_
l1e_get_value(ol1e), l1e_get_value(nl1e), o);
return 0;
}
-
return 1;
+
+#endif
}
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|