#include typedef u_int64_t pt_entry_t; /* * CMPXHCH8B * This is a larger and more unwieldy version of CMPXCHG: it compares * the 64-bit (eight-byte) value stored at [mem] with the value in EDX:EAX. * If they are equal, it sets the zero flag and stores ECX:EBX into the * memory area. If they are unequal, it clears the zero flag and leaves * the memory area untouched. */ static __inline pt_entry_t __pmap_pte_set(pt_entry_t *ptep, u_int32_t newlo, u_int32_t newhi) { register u_int64_t old; __asm __volatile( "1: movl (%1), %%eax\n\t" "movl 4(%1), %%edx\n\t" "cmpxchg8b (%1)\n\t" "jnz 1b" : "=A,A"(old) : "D,S"(ptep), "b,b"(newlo), "c,c"(newhi) : "memory"); return old; } static __inline pt_entry_t __pmap_pte_set_constant(pt_entry_t *ptep, pt_entry_t newval) { return __pmap_pte_set(ptep, newval, newval >> 32); } static __inline pt_entry_t __pmap_pte_set_variable(pt_entry_t *ptep, pt_entry_t newval) { return __pmap_pte_set(ptep, ((u_int32_t *)&newval)[0], ((u_int32_t *)&newval)[1]); } static __inline pt_entry_t pmap_pte_set(pt_entry_t *ptep, pt_entry_t newval) { return __builtin_constant_p(newval) ? __pmap_pte_set_constant(ptep, newval) : __pmap_pte_set_variable(ptep, newval); } /* tests */ pt_entry_t pte[512]; /* test case for a variable set */ int foo(pt_entry_t new) { register int bar __asm("edi"); pmap_pte_set(&pte[2], new); return bar; } /* test case for a constant set */ void bar(void) { pmap_pte_set(&pte[1], 10); }