From mboxrd@z Thu Jan 1 00:00:00 1970 From: Gerd Knorr Subject: [request for review] cmpxchg8b asm stuff Date: Tue, 19 Apr 2005 15:50:41 +0200 Message-ID: <20050419135041.GA19002@bytesex> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Return-path: Content-Disposition: inline List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: xen-devel@lists.xensource.com List-Id: xen-devel@lists.xenproject.org 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 }