diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S index ea547f90973..4e8efdfa590 100644 --- a/sys/amd64/amd64/support.S +++ b/sys/amd64/amd64/support.S @@ -313,6 +313,34 @@ copyin_fault: movq $EFAULT,%rax ret +/* + * casuword32. Compare and set user integer. Returns -1 or the current value. + * dst = %rdi, old = %rsi, new = %rdx + */ +ENTRY(casuword32) + movq PCPU(CURPCB),%rcx + movq $fusufault,PCB_ONFAULT(%rcx) + + movq $VM_MAXUSER_ADDRESS-4,%rax + cmpq %rax,%rdi /* verify address is valid */ + ja fusufault + + movl %esi,%eax /* old */ +#ifdef SMP + lock +#endif + cmpxchgl %edx,(%rdi) /* new = %edx */ + + /* + * The old value is in %eax. If the store succeeded it will be the + * value we expected (old) from before the store, otherwise it will + * be the current value. + */ + + movq PCPU(CURPCB),%rcx + movq $0,PCB_ONFAULT(%rcx) + ret + /* * casuptr. Compare and set user pointer. Returns -1 or the current value. * dst = %rdi, old = %rsi, new = %rdx diff --git a/sys/arm/arm/fusu.S b/sys/arm/arm/fusu.S index 095491aa96a..f0d3688bb9f 100644 --- a/sys/arm/arm/fusu.S +++ b/sys/arm/arm/fusu.S @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); * Fetch an int from the user's address space. */ +ALTENTRY(casuword32) ENTRY(casuptr) #ifdef MULTIPROCESSOR /* XXX Probably not appropriate for non-Hydra SMPs */ diff --git a/sys/i386/i386/support.s b/sys/i386/i386/support.s index c3ac1731401..aee43a4f02a 100644 --- a/sys/i386/i386/support.s +++ b/sys/i386/i386/support.s @@ -1142,6 +1142,8 @@ fastmove_tail_fault: /* * casuptr. Compare and set user pointer. Returns -1 or the current value. */ + +ALTENTRY(casuword32) ENTRY(casuptr) movl PCPU(CURPCB),%ecx movl $fusufault,PCB_ONFAULT(%ecx) diff --git a/sys/ia64/ia64/support.S b/sys/ia64/ia64/support.S index 95686b34bcb..4a212747307 100644 --- a/sys/ia64/ia64/support.S +++ b/sys/ia64/ia64/support.S @@ -241,6 +241,56 @@ ENTRY(casuptr, 3) } END(casuptr) +/* + * casuword32(int32_t *p, int32_t old, int32_t new) + * Perform a 32-bit compare-exchange in user space. + */ +ENTRY(casuword32, 3) +{ .mlx + add r15=PC_CURTHREAD,r13 + movl r14=VM_MAX_ADDRESS + ;; +} +{ .mib + ld8 r15=[r15] // r15 = curthread + cmp.geu p6,p0=in0,r14 +(p6) br.dpnt.few 1f + ;; +} +{ .mlx + add r15=TD_PCB,r15 + movl r14=fusufault + ;; +} +{ .mmi + ld8 r15=[r15] // r15 = PCB + ;; + mov ar.ccv=in1 + add r15=PCB_ONFAULT,r15 + ;; +} +{ .mmi + st8 [r15]=r14 // Set onfault + ;; + cmpxchg4.rel ret0=[in0],in2,ar.ccv + nop 0 + ;; +} +{ .mfb + st8.rel [r15]=r0 // Clear onfault + nop 0 + br.ret.sptk rp + ;; +} +1: +{ .mfb + add ret0=-1,r0 + nop 0 + br.ret.sptk rp + ;; +} +END(casuword32) + /* * subyte(void *addr, int byte) * suword16(void *addr, int word) diff --git a/sys/powerpc/aim/copyinout.c b/sys/powerpc/aim/copyinout.c index 7fa91ceaaf1..4c19cbfe925 100644 --- a/sys/powerpc/aim/copyinout.c +++ b/sys/powerpc/aim/copyinout.c @@ -322,6 +322,12 @@ fuword32(const void *addr) return ((int32_t)fuword(addr)); } +int32_t +casuword32(int32_t *base, int32_t oldval, int32_t newval) +{ + return (casuptr(base, oldval, newval)); +} + intptr_t casuptr(intptr_t *addr, intptr_t old, intptr_t new) { diff --git a/sys/powerpc/powerpc/copyinout.c b/sys/powerpc/powerpc/copyinout.c index 7fa91ceaaf1..4c19cbfe925 100644 --- a/sys/powerpc/powerpc/copyinout.c +++ b/sys/powerpc/powerpc/copyinout.c @@ -322,6 +322,12 @@ fuword32(const void *addr) return ((int32_t)fuword(addr)); } +int32_t +casuword32(int32_t *base, int32_t oldval, int32_t newval) +{ + return (casuptr(base, oldval, newval)); +} + intptr_t casuptr(intptr_t *addr, intptr_t old, intptr_t new) { diff --git a/sys/sparc64/sparc64/support.S b/sys/sparc64/sparc64/support.S index 57ca6379242..d554f63f796 100644 --- a/sys/sparc64/sparc64/support.S +++ b/sys/sparc64/sparc64/support.S @@ -402,7 +402,7 @@ fs_nofault_begin: .set susword, suword16 .set suword, suword64 - .globl casuptr, fuptr, suptr + .globl casuword32, casuptr, fuptr, suptr .set casuptr, casuword64 .set fuptr, fuword64 .set suptr, suword64 diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 35872f4a84e..bc2c65d7c5b 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -203,7 +203,8 @@ int suword(void *base, long word); int suword16(void *base, int word); int suword32(void *base, int32_t word); int suword64(void *base, int64_t word); -intptr_t casuptr(intptr_t *p, intptr_t old, intptr_t new); +int32_t casuword32(int32_t *base, int32_t oldval, int32_t newval); +intptr_t casuptr(intptr_t *p, intptr_t oldval, intptr_t newval); void realitexpire(void *);