Move futex support code from <arch>/support.s into linux compat directory.

Implement all futex atomic operations in assembler to not depend on the
fuword() that does not allow to distinguish between -1 and failure return.
Correctly return 0 from atomic operations on success.

In collaboration with:	rdivacky
Tested by:	Scot Hetzel <swhetzel gmail com>, Milos Vyletel <mvyletel mzm cz>
Sponsored by:	Google SoC 2007
This commit is contained in:
Konstantin Belousov 2007-05-23 08:33:06 +00:00
parent d75d56060e
commit 1c182de9a9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=169895
9 changed files with 302 additions and 165 deletions

View File

@ -671,49 +671,6 @@ ENTRY(longjmp)
incl %eax
ret
/*****************************************************************************/
/* linux_futex support */
/*****************************************************************************/
futex_fault:
movq $0,PCB_ONFAULT(%rcx)
movq $-EFAULT,%rax
ret
ENTRY(futex_xchgl)
movq PCPU(CURPCB),%rcx
movq $futex_fault,PCB_ONFAULT(%rcx)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rsi
ja futex_fault
#ifdef SMP
lock
#endif
xchgl %edi,(%rsi)
movl %edi,(%rdx)
xorl %eax,%eax
movq %rax,PCB_ONFAULT(%rcx)
ret
ENTRY(futex_addl)
movq PCPU(CURPCB),%rcx
movq $futex_fault,PCB_ONFAULT(%rcx)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rsi
ja futex_fault
#ifdef SMP
lock
#endif
xaddl %edi,(%rsi)
movl %edi,(%rdx)
xorl %eax,%eax
movq %rax,PCB_ONFAULT(%rcx)
ret
/*
* Support for BB-profiling (gcc -a). The kernbb program will extract
* the data from the kernel.

View File

@ -0,0 +1,124 @@
/*-
* Copyright (c) 2007 Konstantin Belousov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include "linux32_assym.h" /* system definitions */
#include <machine/asmacros.h> /* miscellaneous asm macros */
#include "assym.s"
futex_fault:
movq $0,PCB_ONFAULT(%r8)
movl $-EFAULT,%eax
ret
ENTRY(futex_xchgl)
movq PCPU(CURPCB),%r8
movq $futex_fault,PCB_ONFAULT(%r8)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rsi
ja futex_fault
xchgl %edi,(%rsi)
movl %edi,(%rdx)
xorl %eax,%eax
movq %rax,PCB_ONFAULT(%r8)
ret
ENTRY(futex_addl)
movq PCPU(CURPCB),%r8
movq $futex_fault,PCB_ONFAULT(%r8)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rsi
ja futex_fault
#ifdef SMP
lock
#endif
xaddl %edi,(%rsi)
movl %edi,(%rdx)
xorl %eax,%eax
movq %rax,PCB_ONFAULT(%r8)
ret
ENTRY(futex_orl)
movq PCPU(CURPCB),%r8
movq $futex_fault,PCB_ONFAULT(%r8)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rsi
ja futex_fault
movl (%rsi),%eax
1: movl %eax,%ecx
orl %edi,%ecx
#ifdef SMP
lock
#endif
cmpxchgl %ecx,(%rsi)
jnz 1b
movl %eax,(%rdx)
xorl %eax,%eax
movq %rax,PCB_ONFAULT(%r8)
ret
ENTRY(futex_andl)
movq PCPU(CURPCB),%r8
movq $futex_fault,PCB_ONFAULT(%r8)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rsi
ja futex_fault
movl (%rsi),%eax
1: movl %eax,%ecx
andl %edi,%ecx
#ifdef SMP
lock
#endif
cmpxchgl %ecx,(%rsi)
jnz 1b
movl %eax,(%rdx)
xorl %eax,%eax
movq %rax,PCB_ONFAULT(%r8)
ret
ENTRY(futex_xorl)
movq PCPU(CURPCB),%r8
movq $futex_fault,PCB_ONFAULT(%r8)
movq $VM_MAXUSER_ADDRESS-4,%rax
cmpq %rax,%rsi
ja futex_fault
movl (%rsi),%eax
1: movl %eax,%ecx
xorl %edi,%ecx
#ifdef SMP
lock
#endif
cmpxchgl %ecx,(%rsi)
jnz 1b
movl %eax,(%rdx)
xorl %eax,%eax
movq %rax,PCB_ONFAULT(%r8)
ret

View File

@ -90,13 +90,13 @@ static void futex_put(struct futex *);
static int futex_sleep(struct futex *, struct thread *, unsigned long);
static int futex_wake(struct futex *, int, struct futex *, int);
static int futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr);
static int futex_orl(int oparg, caddr_t uaddr, int *oldval);
static int futex_andl(int oparg, caddr_t uaddr, int *oldval);
static int futex_xorl(int oparg, caddr_t uaddr, int *oldval);
/* support.s */
int futex_xchgl(int oparg, caddr_t uaddr, int *oldval);
int futex_addl(int oparg, caddr_t uaddr, int *oldval);
int futex_orl(int oparg, caddr_t uaddr, int *oldval);
int futex_andl(int oparg, caddr_t uaddr, int *oldval);
int futex_xorl(int oparg, caddr_t uaddr, int *oldval);
int
linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
@ -114,8 +114,8 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
#ifdef DEBUG
if (ldebug(sys_futex))
printf(ARGS(futex, "%p, %i, %i"), args->uaddr, args->op,
args->val);
printf(ARGS(futex, "%p, %i, %i, *, %p, %i"), args->uaddr, args->op,
args->val, args->uaddr2, args->val3);
#endif
switch (args->op) {
@ -274,7 +274,7 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
#ifdef DEBUG
if (ldebug(sys_futex))
printf("FUTEX_WAKE_OP: %d: uaddr = %p, op = %d, "
"val = %d, uaddr2 = %p, val3 = %d\n",
"val = %x, uaddr2 = %p, val3 = %x\n",
td->td_proc->p_pid, args->uaddr, args->op,
args->val, args->uaddr2, args->val3);
#endif
@ -286,8 +286,11 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
* negative as errors
*/
op_ret = futex_atomic_op(td, args->val3, args->uaddr2);
#ifdef DEBUG
if (ldebug(sys_futex))
printf("futex_atomic_op ret %d\n", op_ret);
#endif
if (op_ret < 0) {
/* XXX: We don't handle the EFAULT yet. */
if (op_ret != -EFAULT) {
futex_put(f);
@ -301,7 +304,6 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
FUTEX_SYSTEM_UNLOCK;
return (EFAULT);
}
ret = futex_wake(f, args->val, NULL, 0);
@ -327,7 +329,7 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args)
args->op);
break;
}
return 0;
return (0);
}
static struct futex *
@ -401,9 +403,12 @@ futex_sleep(struct futex *f, struct thread *td, unsigned long timeout)
TAILQ_REMOVE(&f->f_waiting_proc, wp, wp_list);
FUTEX_UNLOCK;
/* if we got woken up in futex_wake */
if ((ret == 0) && (wp->wp_new_futex != NULL)) {
/* suspend us on the new futex */
ret = futex_sleep(wp->wp_new_futex, td, timeout);
futex_put(wp->wp_new_futex); /* futex_get called in wakeup */
/* and release the old one */
futex_put(wp->wp_new_futex);
}
free(wp, M_LINUX);
@ -458,8 +463,10 @@ futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
oparg = 1 << oparg;
#ifdef DEBUG
printf("futex_atomic_op: op = %d, cmp = %d, oparg = %d, cmparg = %d, "
"uaddr = %p\n", op, cmp, oparg, cmparg, uaddr);
if (ldebug(sys_futex))
printf("futex_atomic_op: op = %d, cmp = %d, oparg = %x, "
"cmparg = %x, uaddr = %p\n",
op, cmp, oparg, cmparg, uaddr);
#endif
/* XXX: linux verifies access here and returns EFAULT */
@ -481,70 +488,26 @@ futex_atomic_op(struct thread *td, int encoded_op, caddr_t uaddr)
break;
default:
ret = -ENOSYS;
break;
}
if (!ret)
switch (cmp) {
case FUTEX_OP_CMP_EQ:
ret = (oldval == cmparg);
break;
case FUTEX_OP_CMP_NE:
ret = (oldval != cmparg);
break;
case FUTEX_OP_CMP_LT:
ret = (oldval < cmparg);
break;
case FUTEX_OP_CMP_GE:
ret = (oldval >= cmparg);
break;
case FUTEX_OP_CMP_LE:
ret = (oldval <= cmparg);
break;
case FUTEX_OP_CMP_GT:
ret = (oldval > cmparg);
break;
default:
ret = -ENOSYS;
}
if (ret)
return (ret);
return (ret);
}
static int
futex_orl(int oparg, caddr_t uaddr, int *oldval)
{
uint32_t ua, ua_old;
for (;;) {
ua = ua_old = fuword32(uaddr);
ua |= oparg;
if (casuword32((void *)uaddr, ua_old, ua) == ua_old)
return ua_old;
}
}
static int
futex_andl(int oparg, caddr_t uaddr, int *oldval)
{
uint32_t ua, ua_old;
for (;;) {
ua = ua_old = fuword32(uaddr);
ua &= oparg;
if (casuword32((void *)uaddr, ua_old, ua) == ua_old)
return ua_old;
}
}
static int
futex_xorl(int oparg, caddr_t uaddr, int *oldval)
{
uint32_t ua, ua_old;
for (;;) {
ua = ua_old = fuword32(uaddr);
ua ^= oparg;
if (casuword32((void *)uaddr, ua_old, ua) == ua_old)
return ua_old;
switch (cmp) {
case FUTEX_OP_CMP_EQ:
return (oldval == cmparg);
case FUTEX_OP_CMP_NE:
return (oldval != cmparg);
case FUTEX_OP_CMP_LT:
return (oldval < cmparg);
case FUTEX_OP_CMP_GE:
return (oldval >= cmparg);
case FUTEX_OP_CMP_LE:
return (oldval <= cmparg);
case FUTEX_OP_CMP_GT:
return (oldval > cmparg);
default:
return (-ENOSYS);
}
}

View File

@ -231,9 +231,10 @@ amd64/linux32/linux32_dummy.c optional compat_linux32
amd64/linux32/linux32_locore.s optional compat_linux32 \
dependency "linux32_assym.h"
amd64/linux32/linux32_machdep.c optional compat_linux32
amd64/linux32/linux32_support.s optional compat_linux32
amd64/linux32/linux32_sysent.c optional compat_linux32
amd64/linux32/linux32_sysvec.c optional compat_linux32
compat/linux/linux_emul.c optional compat_linux32
compat/linux/linux_emul.c optional compat_linux32
compat/linux/linux_file.c optional compat_linux32
compat/linux/linux_futex.c optional compat_linux32
compat/linux/linux_getcwd.c optional compat_linux32

View File

@ -345,6 +345,7 @@ i386/linux/linux_locore.s optional compat_linux \
dependency "linux_assym.h"
i386/linux/linux_machdep.c optional compat_linux
i386/linux/linux_ptrace.c optional compat_linux
i386/linux/linux_support.s optional compat_linux
i386/linux/linux_sysent.c optional compat_linux
i386/linux/linux_sysvec.c optional compat_linux
i386/pci/pci_bus.c optional pci

View File

@ -221,6 +221,7 @@ i386/linux/linux_locore.s optional compat_linux \
dependency "linux_assym.h"
i386/linux/linux_machdep.c optional compat_linux
i386/linux/linux_ptrace.c optional compat_linux
i386/linux/linux_support.s optional compat_linux
i386/linux/linux_sysent.c optional compat_linux
i386/linux/linux_sysvec.c optional compat_linux
i386/pci/pci_bus.c optional pci

View File

@ -1513,51 +1513,6 @@ ENTRY(longjmp)
incl %eax
ret
/*****************************************************************************/
/* linux_futex support */
/*****************************************************************************/
futex_fault:
movl $0,PCB_ONFAULT(%ecx)
movl $-EFAULT,%eax
ret
ENTRY(futex_xchgl)
movl PCPU(CURPCB),%ecx
movl $futex_fault,PCB_ONFAULT(%ecx)
movl 4(%esp),%eax
movl 8(%esp),%edx
cmpl $VM_MAXUSER_ADDRESS-4,%edx
ja futex_fault
#ifdef SMP
lock
#endif
xchgl %eax,(%edx)
movl 12(%esp),%edx
movl %eax,(%edx)
xorl %eax,%eax
movl $0,PCB_ONFAULT(%ecx)
ret
ENTRY(futex_addl)
movl PCPU(CURPCB),%ecx
movl $futex_fault,PCB_ONFAULT(%ecx)
movl 4(%esp),%eax
movl 8(%esp),%edx
cmpl $VM_MAXUSER_ADDRESS-4,%edx
ja futex_fault
#ifdef SMP
lock
#endif
xaddl %eax,(%edx)
movl 12(%esp),%edx
movl %eax,(%edx)
xorl %eax,%eax
movl $0,PCB_ONFAULT(%ecx)
ret
/*
* Support for BB-profiling (gcc -a). The kernbb program will extract
* the data from the kernel.

View File

@ -0,0 +1,127 @@
/*-
* Copyright (c) 2006,2007 Konstantin Belousov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include "linux_assym.h" /* system definitions */
#include <machine/asmacros.h> /* miscellaneous asm macros */
#include "assym.s"
futex_fault_decx:
movl PCPU(CURPCB),%ecx
futex_fault:
movl $0,PCB_ONFAULT(%ecx)
movl $-EFAULT,%eax
ret
ENTRY(futex_xchgl)
movl PCPU(CURPCB),%ecx
movl $futex_fault,PCB_ONFAULT(%ecx)
movl 4(%esp),%eax
movl 8(%esp),%edx
cmpl $VM_MAXUSER_ADDRESS-4,%edx
ja futex_fault
xchgl %eax,(%edx)
movl 12(%esp),%edx
movl %eax,(%edx)
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx)
ret
ENTRY(futex_addl)
movl PCPU(CURPCB),%ecx
movl $futex_fault,PCB_ONFAULT(%ecx)
movl 4(%esp),%eax
movl 8(%esp),%edx
cmpl $VM_MAXUSER_ADDRESS-4,%edx
ja futex_fault
#ifdef SMP
lock
#endif
xaddl %eax,(%edx)
movl 12(%esp),%edx
movl %eax,(%edx)
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx)
ret
ENTRY(futex_orl)
movl PCPU(CURPCB),%ecx
movl $futex_fault_decx,PCB_ONFAULT(%ecx)
movl 8(%esp),%edx
cmpl $VM_MAXUSER_ADDRESS-4,%edx
ja futex_fault
movl (%edx),%eax
1: movl %eax,%ecx
orl 4(%esp),%ecx
#ifdef SMP
lock
#endif
cmpxchgl %ecx,(%edx)
jnz 1b
futex_tail:
movl 12(%esp),%edx
movl %eax,(%edx)
xorl %eax,%eax
movl PCPU(CURPCB),%ecx
movl %eax,PCB_ONFAULT(%ecx)
ret
ENTRY(futex_andl)
movl PCPU(CURPCB),%ecx
movl $futex_fault_decx,PCB_ONFAULT(%ecx)
movl 8(%esp),%edx
cmpl $VM_MAXUSER_ADDRESS-4,%edx
ja futex_fault
movl (%edx),%eax
1: movl %eax,%ecx
andl 4(%esp),%ecx
#ifdef SMP
lock
#endif
cmpxchgl %ecx,(%edx)
jnz 1b
jmp futex_tail
ENTRY(futex_xorl)
movl PCPU(CURPCB),%ecx
movl $futex_fault_decx,PCB_ONFAULT(%ecx)
movl 8(%esp),%edx
cmpl $VM_MAXUSER_ADDRESS-4,%edx
ja futex_fault
movl (%edx),%eax
1: movl %eax,%ecx
xorl 4(%esp),%ecx
#ifdef SMP
lock
#endif
cmpxchgl %ecx,(%edx)
jnz 1b
jmp futex_tail

View File

@ -14,8 +14,12 @@ SRCS= linux${SFX}_dummy.c linux_emul.c linux_file.c \
linux_socket.c linux_stats.c linux_sysctl.c linux${SFX}_sysent.c \
linux${SFX}_sysvec.c linux_uid16.c linux_util.c linux_time.c \
opt_inet6.h opt_mac.h opt_compat.h opt_posix.h vnode_if.h \
device_if.h bus_if.h
OBJS= linux${SFX}_locore.o
device_if.h bus_if.h assym.s
# XXX: for assym.s
SRCS+= opt_kstack_pages.h opt_nfs.h opt_apic.h opt_compat.h
OBJS= linux${SFX}_locore.o linux${SFX}_support.o
.if ${MACHINE_ARCH} == "i386"
SRCS+= linux_ptrace.c imgact_linux.c opt_cpu.h
@ -41,6 +45,10 @@ linux${SFX}_locore.o: linux${SFX}_locore.s linux${SFX}_assym.h
${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
${.IMPSRC} -o ${.TARGET}
linux${SFX}_support.o: linux${SFX}_support.s assym.s
${CC} -c -x assembler-with-cpp -DLOCORE ${CFLAGS} \
${.IMPSRC} -o ${.TARGET}
linux${SFX}_genassym.o: linux${SFX}_genassym.c linux.h @ machine
${CC} -c ${CFLAGS:N-fno-common} ${.IMPSRC}