summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2006-08-28 02:28:15 +0000
committerdavidxu <davidxu@FreeBSD.org>2006-08-28 02:28:15 +0000
commit87b5aa08ee93b317c4d88805ce8e361853411027 (patch)
tree7be2d51c02f47e64ee8dc4e4ec29bd1716dd3c70
parentf2ccfe95252579f4a77ff68a316f2f07850f0277 (diff)
downloadFreeBSD-src-87b5aa08ee93b317c4d88805ce8e361853411027.zip
FreeBSD-src-87b5aa08ee93b317c4d88805ce8e361853411027.tar.gz
Implement casuword32, compare and set user integer, thank Marcel Moolenarr
who wrote the IA64 version of casuword32.
-rw-r--r--sys/amd64/amd64/support.S28
-rw-r--r--sys/arm/arm/fusu.S1
-rw-r--r--sys/i386/i386/support.s2
-rw-r--r--sys/ia64/ia64/support.S50
-rw-r--r--sys/powerpc/aim/copyinout.c6
-rw-r--r--sys/powerpc/powerpc/copyinout.c6
-rw-r--r--sys/sparc64/sparc64/support.S2
-rw-r--r--sys/sys/systm.h3
8 files changed, 96 insertions, 2 deletions
diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S
index ea547f9..4e8efdf 100644
--- a/sys/amd64/amd64/support.S
+++ b/sys/amd64/amd64/support.S
@@ -314,6 +314,34 @@ copyin_fault:
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 095491a..f0d3688 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 c3ac173..aee43a4 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 95686b3..4a21274 100644
--- a/sys/ia64/ia64/support.S
+++ b/sys/ia64/ia64/support.S
@@ -242,6 +242,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)
* suword32(void *addr, int word)
diff --git a/sys/powerpc/aim/copyinout.c b/sys/powerpc/aim/copyinout.c
index 7fa91ce..4c19cbf 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 7fa91ce..4c19cbf 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 57ca637..d554f63 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 35872f4..bc2c65d 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 *);
OpenPOWER on IntegriCloud