Add ucas (CAS for user-space address) support for i386 and amd64.

API provides ucas_int() and ucas_ptr() for now.

Reviewed by <ad>.
This commit is contained in:
rmind 2009-02-23 20:27:59 +00:00
parent 3f2d5fc9ad
commit f7d3fa20ef
3 changed files with 131 additions and 4 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: copy.S,v 1.12 2008/09/18 21:35:17 dsl Exp $ */
/* $NetBSD: copy.S,v 1.13 2009/02/23 20:27:59 rmind Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@ -515,4 +515,81 @@ ENTRY(fusuaddrfault)
movl $-1,%eax
ret
/*
* Compare-and-swap the 64-bit integer in the user-space.
*
* int ucas_64(volatile int64_t *uptr, int64_t old, int64_t new, int64_t *ret);
*/
ENTRY(ucas_64)
DEFERRED_SWITCH_CHECK
/* Fail if kernel-space */
movq $VM_MAXUSER_ADDRESS-8, %r8
cmpq %r8, %rdi
ja 1f
/* Set the fault handler */
GET_CURPCB(%r8)
leaq _C_LABEL(ucas_fault)(%rip), %r9
movq %r9, PCB_ONFAULT(%r8)
/* Perform the CAS */
lock
cmpxchgq %rdx, (%rdi)
/* Clear the fault handler */
movq %rax, PCB_ONFAULT(%r8)
/*
* Note: %rax is "old" value.
* Set the return values.
*/
movq %rax, (%rcx)
xorq %rax, %rax
/* Clear the fault handler */
movq %rax, PCB_ONFAULT(%r8)
1:
/* Failure case */
movq $EFAULT, %rax
ret
DEFERRED_SWITCH_CALL
/*
* int ucas_32(volatile int32_t *uptr, int32_t old, int32_t new, int32_t *ret);
*/
ENTRY(ucas_32)
DEFERRED_SWITCH_CHECK
/* Fail if kernel-space */
movq $VM_MAXUSER_ADDRESS-4, %r8
cmpq %r8, %rdi
ja 1f
/* Set the fault handler */
GET_CURPCB(%r8)
leaq _C_LABEL(ucas_fault)(%rip), %r9
movq %r9, PCB_ONFAULT(%r8)
/* Perform the CAS */
lock
cmpxchgl %edx, (%rdi)
/*
* Note: %eax is "old" value.
* Set the return values.
*/
movl %eax, (%rcx)
xorq %rax, %rax
1:
/* Failure case */
movq $EFAULT, %rax
ret
DEFERRED_SWITCH_CALL
/*
* Fault handler for ucas_32() and ucas_64().
* Unset the handler and return the failure.
*/
NENTRY(ucas_fault)
movq $0, PCB_ONFAULT(%r8)
movq $EFAULT, %rax
ret
/*
* int ucas_ptr(volatile void *uptr, void *old, void *new, void *ret);
*/
STRONG_ALIAS(ucas_ptr, ucas_64)
STRONG_ALIAS(ucas_int, ucas_32)
x86_copyfunc_end: .globl x86_copyfunc_end

View File

@ -1,4 +1,4 @@
/* $NetBSD: copy.S,v 1.16 2008/04/28 20:23:24 martin Exp $ */
/* $NetBSD: copy.S,v 1.17 2009/02/23 20:27:59 rmind Exp $ */
/* NetBSD: locore.S,v 1.34 2005/04/01 11:59:31 yamt Exp $ */
/*-
@ -65,7 +65,7 @@
*/
#include <machine/asm.h>
__KERNEL_RCSID(0, "$NetBSD: copy.S,v 1.16 2008/04/28 20:23:24 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: copy.S,v 1.17 2009/02/23 20:27:59 rmind Exp $");
#include "assym.h"
@ -644,6 +644,49 @@ ENTRY(subyte)
ret
DEFERRED_SWITCH_CALL
/*
* Compare-and-swap the 32-bit integer in the user-space.
*
* int ucas_32(volatile int32_t *uptr, int32_t old, int32_t new, int32_t *ret);
*/
ENTRY(ucas_32)
DEFERRED_SWITCH_CHECK
movl 4(%esp), %edx
movl 8(%esp), %eax
movl 12(%esp), %ecx
/* Fail if kernel-space */
cmpl $VM_MAXUSER_ADDRESS-4, %edx
ja _C_LABEL(ucas_fault)
/* Label for fault handler */
.Lucas32_start:
/* Perform the CAS */
lock
cmpxchgl %ecx, (%edx)
.Lucas32_end:
/*
* Note: %eax is "old" value.
* Set the return values.
*/
movl 16(%esp), %edx
movl %eax, (%edx)
xorl %eax, %eax
ret
DEFERRED_SWITCH_CALL
/*
* Fault handler for ucas_32().
* Unset the handler and return the failure.
*/
NENTRY(ucas_fault)
movl $EFAULT, %eax
ret
/*
* int ucas_int(volatile int *uptr, int old, int new, int *ret);
*/
STRONG_ALIAS(ucas_ptr, ucas_32)
STRONG_ALIAS(ucas_int, ucas_32)
/*
* copyin() optimised for bringing in syscall arguments.
*/
@ -731,6 +774,10 @@ _C_LABEL(onfault_table):
.long .Lcopyinstr_end
.long _C_LABEL(copystr_fault)
.long .Lucas32_start
.long .Lucas32_end
.long _C_LABEL(ucas_fault)
.long .Lx86_copyargs_start
.long .Lx86_copyargs_end
.long _C_LABEL(x86_copyargs_fault)

View File

@ -1,4 +1,4 @@
/* $NetBSD: systm.h,v 1.233 2009/02/12 18:24:18 christos Exp $ */
/* $NetBSD: systm.h,v 1.234 2009/02/23 20:27:59 rmind Exp $ */
/*-
* Copyright (c) 1982, 1988, 1991, 1993
@ -258,6 +258,9 @@ int copyout_vmspace(struct vmspace *, const void *, void *, size_t);
int ioctl_copyin(int ioctlflags, const void *src, void *dst, size_t len);
int ioctl_copyout(int ioctlflags, const void *src, void *dst, size_t len);
int ucas_ptr(volatile void *, void *, void *, void *);
int ucas_int(volatile int *, int, int, int *);
int subyte(void *, int);
int suibyte(void *, int);
int susword(void *, short);