summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
Diffstat (limited to 'libc')
-rw-r--r--libc/sysdeps/linux/common/Makefile.in1
-rw-r--r--libc/sysdeps/linux/metag/Makefile.arch4
-rw-r--r--libc/sysdeps/linux/metag/bits/atomic.h66
-rw-r--r--libc/sysdeps/linux/metag/bits/syscalls.h73
-rw-r--r--libc/sysdeps/linux/metag/clone.S50
-rw-r--r--libc/sysdeps/linux/metag/crt1.S3
-rw-r--r--libc/sysdeps/linux/metag/libc-metag_load_tp.S7
-rw-r--r--libc/sysdeps/linux/metag/sysdep.h59
-rw-r--r--libc/sysdeps/linux/metag/vfork.S67
9 files changed, 294 insertions, 36 deletions
diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in
index f7083a48b..dbf0b0fd4 100644
--- a/libc/sysdeps/linux/common/Makefile.in
+++ b/libc/sysdeps/linux/common/Makefile.in
@@ -69,6 +69,7 @@ CSRC- += fork.c getpid.c raise.c #open.c close.c read.c write.c
CSRC- += $(if $(findstring =arm=,=$(TARGET_ARCH)=),vfork.c)
CSRC- += $(if $(findstring =x86_64=,=$(TARGET_ARCH)=),vfork.c)
#CSRC- += $(if $(findstring =mips=y=,=$(TARGET_ARCH)=$(CONFIG_MIPS_O32_ABI)=),waitpid.c)
+CSRC- += $(if $(findstring =metag=,=$(TARGET_ARCH)=),vfork.c)
endif
ifneq ($(ARCH_HAS_DEPRECATED_SYSCALLS),y)
# No conversion is needed for new architectures
diff --git a/libc/sysdeps/linux/metag/Makefile.arch b/libc/sysdeps/linux/metag/Makefile.arch
index 0e6fbfe12..3f11d6da8 100644
--- a/libc/sysdeps/linux/metag/Makefile.arch
+++ b/libc/sysdeps/linux/metag/Makefile.arch
@@ -7,4 +7,6 @@
CSRC-y := brk.c syscall.c metag.c __syscall_error.c
-SSRC-y := _longjmp.S clone.S setjmp.S
+SSRC-y := _longjmp.S clone.S setjmp.S vfork.S
+
+SSRC-$(UCLIBC_HAS_THREADS_NATIVE) += libc-metag_load_tp.S
diff --git a/libc/sysdeps/linux/metag/bits/atomic.h b/libc/sysdeps/linux/metag/bits/atomic.h
new file mode 100644
index 000000000..64aa50bc4
--- /dev/null
+++ b/libc/sysdeps/linux/metag/bits/atomic.h
@@ -0,0 +1,66 @@
+/*
+ * Copyrith (C) 2013 Imagination Technologies Ltd.
+ *
+ * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ *
+ */
+
+#include <stdint.h>
+#include <sysdep.h>
+
+typedef int8_t atomic8_t;
+typedef uint8_t uatomic8_t;
+typedef int_fast8_t atomic_fast8_t;
+typedef uint_fast8_t uatomic_fast8_t;
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+void __metag_link_error (void);
+
+#define atomic_full_barrier() \
+ __asm__ __volatile__("": : :"memory")
+
+/* Atomic compare and exchange. This sequence relies on the kernel to
+ provide a compare and exchange operation which is atomic. */
+
+#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
+ ({ __metag_link_error (); oldval; })
+
+#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
+ ({ __metag_link_error (); oldval; })
+
+/* This code uses the kernel helper to do cmpxchg. It relies on the fact
+ the helper code only clobbers D0Re0. */
+#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
+ ({ register __typeof (oldval) a_current __asm__ ("D1Ar1"); \
+ register __typeof (oldval) a_newval __asm__ ("D0Ar2") = (newval); \
+ register __typeof (mem) a_ptr __asm__ ("D1Ar3") = (mem); \
+ register __typeof (oldval) a_oldval __asm__ ("D0Ar4") = (oldval); \
+ __asm__ __volatile__ \
+ ("0:\n\t" \
+ "GETD %[cur], [%[ptr]]\n\t" \
+ "CMP %[cur], %[old]\n\t" \
+ "BNE 1f\n\t" \
+ "MOVT D1RtP, #0x6fff\n\t" \
+ "ADD D1RtP, D1RtP, #0xf040\n\t" \
+ "SWAP D1RtP, PC\n\t" \
+ "MOV %[cur], %[old]\n\t" \
+ "CMP D0Re0, #0\n\t" \
+ "BNE 0b\n\t" \
+ "1:" \
+ : [cur] "=&r" (a_current) \
+ : [new] "r" (a_newval), [ptr] "r" (a_ptr), \
+ [old] "r" (a_oldval) \
+ : "D0Re0", "D1RtP", "cc", "memory"); \
+ a_current; })
+
+#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
+ ({ __metag_link_error (); oldval; })
diff --git a/libc/sysdeps/linux/metag/bits/syscalls.h b/libc/sysdeps/linux/metag/bits/syscalls.h
index b5c8fc58c..7ea09c2c3 100644
--- a/libc/sysdeps/linux/metag/bits/syscalls.h
+++ b/libc/sysdeps/linux/metag/bits/syscalls.h
@@ -49,8 +49,9 @@
(__extension__ \
({unsigned int __sys_result; \
{ \
+ PREP_ARGS_##nr (args); \
register int _result __asm__ ("D0Re0"), _nr __asm__ ("D1Re0"); \
- LOAD_ARGS_##nr (args); \
+ LOAD_ARGS_##nr; \
_nr = (name); \
__asm__ volatile ("SWITCH #0x440001 ! syscall " #name \
: "=r" (_result) \
@@ -68,32 +69,52 @@
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val))
-#define LOAD_ARGS_0()
+#define PREP_ARGS_0()
+#define PREP_ARGS_1(a1) \
+ int _t1 = (int) (a1); \
+ PREP_ARGS_0 ()
+#define PREP_ARGS_2(a1, a2) \
+ int _t2 = (int) (a2); \
+ PREP_ARGS_1 (a1)
+#define PREP_ARGS_3(a1, a2, a3) \
+ int _t3 = (int) (a3); \
+ PREP_ARGS_2 (a1, a2)
+#define PREP_ARGS_4(a1, a2, a3, a4) \
+ int _t4 = (int) (a4); \
+ PREP_ARGS_3 (a1, a2, a3)
+#define PREP_ARGS_5(a1, a2, a3, a4, a5) \
+ int _t5 = (int) (a5); \
+ PREP_ARGS_4 (a1, a2, a3, a4)
+#define PREP_ARGS_6(a1, a2, a3, a4, a5, a6) \
+ int _t6 = (int) (a6); \
+ PREP_ARGS_5 (a1, a2, a3, a4, a5)
+
+#define LOAD_ARGS_0
#define ASM_ARGS_0
-#define LOAD_ARGS_1(a1) \
- register int _a1 __asm__ ("D1Ar1") = (int) (a1); \
- LOAD_ARGS_0 ()
-#define ASM_ARGS_1 ASM_ARGS_0, "d" (_a1)
-#define LOAD_ARGS_2(a1, a2) \
- register int _a2 __asm__ ("D0Ar2") = (int) (a2); \
- LOAD_ARGS_1 (a1)
-#define ASM_ARGS_2 ASM_ARGS_1, "d" (_a2)
-#define LOAD_ARGS_3(a1, a2, a3) \
- register int _a3 __asm__ ("D1Ar3") = (int) (a3); \
- LOAD_ARGS_2 (a1, a2)
-#define ASM_ARGS_3 ASM_ARGS_2, "d" (_a3)
-#define LOAD_ARGS_4(a1, a2, a3, a4) \
- register int _a4 __asm__ ("D0Ar4") = (int) (a4); \
- LOAD_ARGS_3 (a1, a2, a3)
-#define ASM_ARGS_4 ASM_ARGS_3, "d" (_a4)
-#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \
- register int _a5 __asm__ ("D1Ar5") = (int) (a5); \
- LOAD_ARGS_4 (a1, a2, a3, a4)
-#define ASM_ARGS_5 ASM_ARGS_4, "d" (_a5)
-#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \
- register int _a6 __asm__ ("D0Ar6") = (int) (a6); \
- LOAD_ARGS_5 (a1, a2, a3, a4, a5)
-#define ASM_ARGS_6 ASM_ARGS_5, "d" (_a6)
+#define LOAD_ARGS_1 \
+ register int _a1 __asm__ ("D1Ar1") = (int) (_t1); \
+ LOAD_ARGS_0
+#define ASM_ARGS_1 ASM_ARGS_0, "d" (_a1)
+#define LOAD_ARGS_2 \
+ register int _a2 __asm__ ("D0Ar2") = (int) (_t2); \
+ LOAD_ARGS_1
+#define ASM_ARGS_2 ASM_ARGS_1, "d" (_a2)
+#define LOAD_ARGS_3 \
+ register int _a3 __asm__ ("D1Ar3") = (int) (_t3); \
+ LOAD_ARGS_2
+#define ASM_ARGS_3 ASM_ARGS_2, "d" (_a3)
+#define LOAD_ARGS_4 \
+ register int _a4 __asm__ ("D0Ar4") = (int) (_t4); \
+ LOAD_ARGS_3
+#define ASM_ARGS_4 ASM_ARGS_3, "d" (_a4)
+#define LOAD_ARGS_5 \
+ register int _a5 __asm__ ("D1Ar5") = (int) (_t5); \
+ LOAD_ARGS_4
+#define ASM_ARGS_5 ASM_ARGS_4, "d" (_a5)
+#define LOAD_ARGS_6 \
+ register int _a6 __asm__ ("D0Ar6") = (int) (_t6); \
+ LOAD_ARGS_5
+#define ASM_ARGS_6 ASM_ARGS_5, "d" (_a6)
#endif /* __ASSEMBLER__ */
#endif /* _BITS_SYSCALLS_H */
diff --git a/libc/sysdeps/linux/metag/clone.S b/libc/sysdeps/linux/metag/clone.S
index 8fff56710..d9d836338 100644
--- a/libc/sysdeps/linux/metag/clone.S
+++ b/libc/sysdeps/linux/metag/clone.S
@@ -8,7 +8,17 @@
#include <asm/errno.h>
#include <asm/unistd.h>
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
+#define CLONE_VM 0x00000100
+#define CLONE_THREAD 0x00010000
+
+#ifdef __PIC__
+#define __CLONE_METAG_LOAD_TP ___metag_load_tp@PLT
+#else
+#define __CLONE_METAG_LOAD_TP ___metag_load_tp
+#endif
+
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+ pid_t *ptid, struct user_desc *tls, pid_t *ctid); */
.text
.global __clone
@@ -25,8 +35,12 @@ __clone:
MOV D0FrT, D1Ar1
! do the system call
- ! get flags
MOV D1Ar1, D1Ar3
+ MOV D1Ar3, D1Ar5
+ MOV D1Ar5, D0Ar6
+ MOV D0Ar6, D0Ar4
+ GETD D0Ar4, [A0StP+#-4]
+
! new sp is already in D0Ar2
MOV D1Re0, #__NR_clone
SWITCH #0x440001
@@ -38,14 +52,36 @@ __clone:
! BRKPNT
! We are the child
- ! pick the function arg and call address off the stack and execute
- MOV D0Ar2, D0FrT
- MOV D1Ar1, D0Ar4
- MOV D1RtP, PC
+#ifdef RESET_PID
+ SETL [A0StP++], D0FrT, D1RtP
+ MOVT D0FrT, #HI(CLONE_THREAD)
+ ADD D0FrT, D0FrT, #LO(CLONE_THREAD)
+ ANDS D0FrT, D0FrT, D1Ar1
+ BNZ 3f
+ MOVT D0FrT, #HI(CLONE_VM)
+ ADD D0FrT, D0FrT, #LO(CLONE_VM)
+ ANDS D0FrT, D0FrT, D1Ar1
+ BZ 1f
+ MOV D1Ar1, #-1
+ BA 2f
+1: MOV D1Re0, #__NR_getpid
+ SWITCH #0x440001
+ MOV D1Ar1, D0Re0
+2: CALLR D1RtP, __CLONE_METAG_LOAD_TP
+ SUB D0Re0, D0Re0, #TLS_PRE_TCB_SIZE
+ SETD [D0Re0 + #PID], D1Ar1
+ SETD [D0Re0 + #TID], D1Ar1
+3: GETL D0FrT, D1RtP, [--A0StP]
+#endif
+ ! Rearrange the function arg and call address from registers
+ MOV D0Ar2, D0FrT
+ MOV D1Ar1, D0Ar6
+ MOV D1RtP, PC
ADD D1RtP, D1RtP, #8
MOV PC, D0Ar2
- ! and we are done, passing the return value through D0Re0
+ ! and we are done, passing the return value D0Re0 through D1Ar1
+ MOV D1Ar1, D0Re0
#ifdef __PIC__
B _exit@PLT
#else
diff --git a/libc/sysdeps/linux/metag/crt1.S b/libc/sysdeps/linux/metag/crt1.S
index 74adc1fdb..e8561a46b 100644
--- a/libc/sysdeps/linux/metag/crt1.S
+++ b/libc/sysdeps/linux/metag/crt1.S
@@ -29,6 +29,7 @@ __start:
MOV D1Ar3,D0Ar2 ! argv
MOV D0Ar2,D1Ar1 ! argc
+ MOV D0Ar6,D0Ar4 ! rtld_fini
#ifdef __PIC__
ADDT A1LbP,CPC1,#HI(__GLOBAL_OFFSET_TABLE__)
@@ -54,8 +55,6 @@ __start:
ADD D1Ar5,D1Ar5,#LO(__fini)
#endif
- MOV D0Ar6,#0 ! rtld_fini
-
MOVT D1Re0,#0x80
SETL [A0StP++],D0Re0,D1Re0 ! stack_end (8Mb)
diff --git a/libc/sysdeps/linux/metag/libc-metag_load_tp.S b/libc/sysdeps/linux/metag/libc-metag_load_tp.S
new file mode 100644
index 000000000..a91f162ec
--- /dev/null
+++ b/libc/sysdeps/linux/metag/libc-metag_load_tp.S
@@ -0,0 +1,7 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <ldso/ldso/metag/metag_load_tp.S>
diff --git a/libc/sysdeps/linux/metag/sysdep.h b/libc/sysdeps/linux/metag/sysdep.h
new file mode 100644
index 000000000..a12f393ce
--- /dev/null
+++ b/libc/sysdeps/linux/metag/sysdep.h
@@ -0,0 +1,59 @@
+/*
+ * Assembler macros for Meta.
+ *
+ * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+ */
+
+#include <common/sysdep.h>
+
+#include <features.h>
+#include <libc-internal.h>
+
+#ifdef __ASSEMBLER__
+
+#ifdef SHARED
+#define PLTJMP(_x) _x##@PLT
+#else
+#define PLTJMP(_x) _x
+#endif
+
+#undef PSEUDO_END
+#define PSEUDO_END(name) \
+ SYSCALL_ERROR_HANDLER \
+ END (name)
+
+#if defined NOT_IN_libc
+# define SYSCALL_ERROR __local_syscall_error
+# ifdef RTLD_PRIVATE_ERRNO
+# define SYSCALL_ERROR_HANDLER \
+__local_syscall_error: \
+ NEG D0Re0, D0Re0; \
+ ADDT D1Re0, CPC1, #HI(_rtld_errno); \
+ ADD D1Re0, D1Re0, #LO(_rtld_errno) + 4; \
+ SETD [D1Re0], D0Re0; \
+ NEG D0Re0, #0x1; \
+ MOV PC, D1RtP;
+# else
+# define SYSCALL_ERROR_HANDLER \
+__local_syscall_error: \
+ MOV D1Re0, D1RtP; \
+ SETL [A0StP++], D0Re0, D1Re0; \
+ CALLR D1RtP, PLTJMP(___errno_location); \
+ GETD D1Re0, [A0StP+#-8]; \
+ NEG D1Re0, D1Re0; \
+ SETD [D0Re0], D1Re0; \
+ NEG D0Re0, #0x1; \
+ GETD D1RtP, [A0StP+#-4]; \
+ SUB A0StP, A0StP, #0x8; \
+ MOV PC, D1RtP;
+# endif
+#else
+# define SYSCALL_ERROR_HANDLER /* Nothing here; code in sysdep.S is used. */
+# define SYSCALL_ERROR ___syscall_error
+#endif
+
+#endif /* __ASSEMBLER __*/
+
+/* Pointer mangling is not yet supported for META. */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
diff --git a/libc/sysdeps/linux/metag/vfork.S b/libc/sysdeps/linux/metag/vfork.S
new file mode 100644
index 000000000..8573dedd3
--- /dev/null
+++ b/libc/sysdeps/linux/metag/vfork.S
@@ -0,0 +1,67 @@
+! Copyright (C) 2013 Imagination Technologies Ltd.
+
+! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
+
+#include <asm/unistd.h>
+
+#define _ERRNO_H
+#include <bits/errno.h>
+#include <sys/syscall.h>
+
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
+#ifdef __NR_vfork
+#define __VFORK_NR __NR_vfork
+#else
+#define __VFORK_NR __NR_fork
+#endif
+
+/* Clone the calling process, but without copying the whole address space.
+ The calling process is suspended until the new process exits or is
+ replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
+ and the process ID of the new process to the old process. */
+
+ .balign 4
+ .global ___vfork
+ .hidden ___vfork
+ .type ___vfork, @function
+___vfork:
+
+ SAVE_PID
+
+ MOV D1Ar1, #0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */
+ MOV D0Ar2, #0
+ MOV D1Ar3, #0
+ MOV D0Ar4, #0
+ MOV D1Ar5, #0
+ MOV D0Ar6, #0
+ MOV D1Re0, #__NR_clone
+ SWITCH #0x440001
+
+ RESTORE_PID
+
+ MOVT D1Re0, #HI(-4096)
+ ADD D1Re0, D1Re0, #LO(-4096)
+ CMP D1Re0, D0Re0
+ BCS error
+
+ /* Syscall worked. Return to child/parent */
+ MOV PC, D1RtP
+
+error:
+ MOV D1Ar1, D0Re0
+#ifdef __PIC__
+ B ___syscall_error@PLT
+#else
+ B ___syscall_error
+#endif
+ .size ___vfork,.-___vfork
+
+weak_alias(__vfork,vfork)
+libc_hidden_weak(vfork)