SPARC fixes: fork/vfork are special; crt0 needs to reserve more space;
define NSIG to _NSIG if the former does not exist.
diff --git a/SYSCALLS b/SYSCALLS
index 613fb92..75b848a 100644
--- a/SYSCALLS
+++ b/SYSCALLS
@@ -5,13 +5,14 @@
# linker can do its job properly.
#
# The full description of a line is:
-# [<[!]arch,...>] type [sysname[@systype]::]funcname(args)
+# [<[!]arch,...>] type sysname[@systype][::funcname](args)
#
#
# Process-related syscalls
#
-<!mips,mips64> pid_t vfork()
+<!mips,mips64,sparc> pid_t vfork()
+<sparc> pid_t vfork@forkish()
<!alpha> pid_t getpid()
<alpha> pid_t getxpid@dual0::getpid()
int setpgid(pid_t, pid_t)
diff --git a/arch/sparc/crt0i.S b/arch/sparc/crt0i.S
index a83fefa..44f9092 100644
--- a/arch/sparc/crt0i.S
+++ b/arch/sparc/crt0i.S
@@ -67,19 +67,31 @@
! or without an imposed bias.
andcc %sp, 1, %g5
- bnz,a .LHaveBias
+ bz,a .LNoBias
+ nop
mov 2047, %g5
-.LHaveBias:
+.LNoBias:
add %sp, %g5, %g5
+! On entry, the kernel leaves room for one register frame, but
+! the C API wants more free space. Thus, we need to drop the stack
+! pointer additionally.
+
#if TARGET_PTR_SIZE == 32
- ld [%g5 + 0x40], %o0 ! argc
+ sub %sp, 32, %sp ! make room for incoming arguments
+#else /* TARGET_PTR_SIZE == 64 */
+ sub %sp, 64, %sp ! make room for incoming arguments
+#endif
+
+! Set up pointers to argc and argv
+#if TARGET_PTR_SIZE == 32
+ ld [%g5 + 0x40], %o0 ! argc
add %g5, 0x44, %o1 ! argv
add %o0, 1, %o2
sll %o2, 2, %o2
#else /* TARGET_PTR_SIZE == 64 */
- ld [%g5 + 0x88], %o0 ! argc.lo
- add %sp, 0x90, %o1 ! argv
+ ld [%g5 + 0x80], %o0 ! argc.lo
+ add %sp, 0x88, %o1 ! argv
add %o0, 1, %o2
sll %o2, 3, %o2
#endif
@@ -87,16 +99,16 @@
sethi %hi (environ), %o3
or %o3, %lo (environ), %o3
#if TARGET_PTR_SIZE == 32
- st %o2, [%o3 + %g4]
+ st %o2, [%o3 + %g4]
#else /* TARGET_PTR_SIZE == 64 */
stx %o2, [%o3 + %g4]
#endif
call main
- nop
+ nop
call exit
- nop
+ nop
! If all the above methods fail to terminate the program, try an illegal insn.
! If that does not work, the o/s is hosed more than we are.
diff --git a/arch/sparc/include/klibc/archsys.h b/arch/sparc/include/klibc/archsys.h
index 61be726..fe6e68d 100644
--- a/arch/sparc/include/klibc/archsys.h
+++ b/arch/sparc/include/klibc/archsys.h
@@ -7,6 +7,29 @@
#ifndef _KLIBC_ARCHSYS_H
#define _KLIBC_ARCHSYS_H
+/* fork and vfork return the "other process" pid in %o0 and an
+ "is child" flag in %o1... */
+
+#define _syscall0_forkish(type,name) \
+type name(void) \
+{ \
+register long __g1 __asm__ ("g1") = __NR_##name; \
+register unsigned long __o0 __asm__ ("o0"); \
+register unsigned long __o1 __asm__ ("o1"); \
+__asm__ __volatile__ ("t 0x10\n\t" \
+ "bcc 1f\n\t" \
+ "mov %%o0, %0\n\t" \
+ "sub %%g0, %%o0, %0\n\t" \
+ "1:\n\t" \
+ : "=r" (__o0), "=r" (__o1)\
+ : "r" (__g1) \
+ : "cc"); \
+if ((unsigned long)__o0 < (unsigned long)-255) \
+ return (type)(__o0 & (__o1-1)); \
+errno = (int)-__o0; \
+return -1; \
+}
+
/* SPARC seems to lack _syscall6() in its headers */
#ifndef _syscall6
diff --git a/fork.c b/fork.c
index 1bf0169..080e38c 100644
--- a/fork.c
+++ b/fork.c
@@ -11,9 +11,13 @@
#ifdef __NR_fork
-_syscall0(pid_t,fork);
-
+#ifdef __sparc__
+_syscall0_forkish(pid_t,fork);
#else
+_syscall0(pid_t,fork);
+#endif
+
+#else /* __NR_fork */
static inline _syscall2(pid_t,clone,unsigned long,flags,void *,newsp);
diff --git a/include/arch/sparc/klibc/archsys.h b/include/arch/sparc/klibc/archsys.h
index 61be726..fe6e68d 100644
--- a/include/arch/sparc/klibc/archsys.h
+++ b/include/arch/sparc/klibc/archsys.h
@@ -7,6 +7,29 @@
#ifndef _KLIBC_ARCHSYS_H
#define _KLIBC_ARCHSYS_H
+/* fork and vfork return the "other process" pid in %o0 and an
+ "is child" flag in %o1... */
+
+#define _syscall0_forkish(type,name) \
+type name(void) \
+{ \
+register long __g1 __asm__ ("g1") = __NR_##name; \
+register unsigned long __o0 __asm__ ("o0"); \
+register unsigned long __o1 __asm__ ("o1"); \
+__asm__ __volatile__ ("t 0x10\n\t" \
+ "bcc 1f\n\t" \
+ "mov %%o0, %0\n\t" \
+ "sub %%g0, %%o0, %0\n\t" \
+ "1:\n\t" \
+ : "=r" (__o0), "=r" (__o1)\
+ : "r" (__g1) \
+ : "cc"); \
+if ((unsigned long)__o0 < (unsigned long)-255) \
+ return (type)(__o0 & (__o1-1)); \
+errno = (int)-__o0; \
+return -1; \
+}
+
/* SPARC seems to lack _syscall6() in its headers */
#ifndef _syscall6
diff --git a/include/signal.h b/include/signal.h
index fc12fa1..d417e40 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -18,6 +18,9 @@
#ifndef SA_NODEFER
# define SA_NODEFER SA_NOMASK
#endif
+#ifndef NSIG
+# define NSIG _NSIG
+#endif
__extern const char * const sys_siglist[];
diff --git a/klibc/SYSCALLS b/klibc/SYSCALLS
index 613fb92..75b848a 100644
--- a/klibc/SYSCALLS
+++ b/klibc/SYSCALLS
@@ -5,13 +5,14 @@
# linker can do its job properly.
#
# The full description of a line is:
-# [<[!]arch,...>] type [sysname[@systype]::]funcname(args)
+# [<[!]arch,...>] type sysname[@systype][::funcname](args)
#
#
# Process-related syscalls
#
-<!mips,mips64> pid_t vfork()
+<!mips,mips64,sparc> pid_t vfork()
+<sparc> pid_t vfork@forkish()
<!alpha> pid_t getpid()
<alpha> pid_t getxpid@dual0::getpid()
int setpgid(pid_t, pid_t)
diff --git a/klibc/arch/sparc/crt0i.S b/klibc/arch/sparc/crt0i.S
index a83fefa..44f9092 100644
--- a/klibc/arch/sparc/crt0i.S
+++ b/klibc/arch/sparc/crt0i.S
@@ -67,19 +67,31 @@
! or without an imposed bias.
andcc %sp, 1, %g5
- bnz,a .LHaveBias
+ bz,a .LNoBias
+ nop
mov 2047, %g5
-.LHaveBias:
+.LNoBias:
add %sp, %g5, %g5
+! On entry, the kernel leaves room for one register frame, but
+! the C API wants more free space. Thus, we need to drop the stack
+! pointer additionally.
+
#if TARGET_PTR_SIZE == 32
- ld [%g5 + 0x40], %o0 ! argc
+ sub %sp, 32, %sp ! make room for incoming arguments
+#else /* TARGET_PTR_SIZE == 64 */
+ sub %sp, 64, %sp ! make room for incoming arguments
+#endif
+
+! Set up pointers to argc and argv
+#if TARGET_PTR_SIZE == 32
+ ld [%g5 + 0x40], %o0 ! argc
add %g5, 0x44, %o1 ! argv
add %o0, 1, %o2
sll %o2, 2, %o2
#else /* TARGET_PTR_SIZE == 64 */
- ld [%g5 + 0x88], %o0 ! argc.lo
- add %sp, 0x90, %o1 ! argv
+ ld [%g5 + 0x80], %o0 ! argc.lo
+ add %sp, 0x88, %o1 ! argv
add %o0, 1, %o2
sll %o2, 3, %o2
#endif
@@ -87,16 +99,16 @@
sethi %hi (environ), %o3
or %o3, %lo (environ), %o3
#if TARGET_PTR_SIZE == 32
- st %o2, [%o3 + %g4]
+ st %o2, [%o3 + %g4]
#else /* TARGET_PTR_SIZE == 64 */
stx %o2, [%o3 + %g4]
#endif
call main
- nop
+ nop
call exit
- nop
+ nop
! If all the above methods fail to terminate the program, try an illegal insn.
! If that does not work, the o/s is hosed more than we are.
diff --git a/klibc/arch/sparc/include/klibc/archsys.h b/klibc/arch/sparc/include/klibc/archsys.h
index 61be726..fe6e68d 100644
--- a/klibc/arch/sparc/include/klibc/archsys.h
+++ b/klibc/arch/sparc/include/klibc/archsys.h
@@ -7,6 +7,29 @@
#ifndef _KLIBC_ARCHSYS_H
#define _KLIBC_ARCHSYS_H
+/* fork and vfork return the "other process" pid in %o0 and an
+ "is child" flag in %o1... */
+
+#define _syscall0_forkish(type,name) \
+type name(void) \
+{ \
+register long __g1 __asm__ ("g1") = __NR_##name; \
+register unsigned long __o0 __asm__ ("o0"); \
+register unsigned long __o1 __asm__ ("o1"); \
+__asm__ __volatile__ ("t 0x10\n\t" \
+ "bcc 1f\n\t" \
+ "mov %%o0, %0\n\t" \
+ "sub %%g0, %%o0, %0\n\t" \
+ "1:\n\t" \
+ : "=r" (__o0), "=r" (__o1)\
+ : "r" (__g1) \
+ : "cc"); \
+if ((unsigned long)__o0 < (unsigned long)-255) \
+ return (type)(__o0 & (__o1-1)); \
+errno = (int)-__o0; \
+return -1; \
+}
+
/* SPARC seems to lack _syscall6() in its headers */
#ifndef _syscall6
diff --git a/klibc/fork.c b/klibc/fork.c
index 1bf0169..080e38c 100644
--- a/klibc/fork.c
+++ b/klibc/fork.c
@@ -11,9 +11,13 @@
#ifdef __NR_fork
-_syscall0(pid_t,fork);
-
+#ifdef __sparc__
+_syscall0_forkish(pid_t,fork);
#else
+_syscall0(pid_t,fork);
+#endif
+
+#else /* __NR_fork */
static inline _syscall2(pid_t,clone,unsigned long,flags,void *,newsp);
diff --git a/klibc/include/signal.h b/klibc/include/signal.h
index fc12fa1..d417e40 100644
--- a/klibc/include/signal.h
+++ b/klibc/include/signal.h
@@ -18,6 +18,9 @@
#ifndef SA_NODEFER
# define SA_NODEFER SA_NOMASK
#endif
+#ifndef NSIG
+# define NSIG _NSIG
+#endif
__extern const char * const sys_siglist[];
diff --git a/klibc/tests/getenvtest.c b/klibc/tests/getenvtest.c
index c074220..76d8901 100644
--- a/klibc/tests/getenvtest.c
+++ b/klibc/tests/getenvtest.c
@@ -17,6 +17,7 @@
printf("USER = %s\n", getenv("USER"));
/* Test argc/argv */
+ printf("argc = %d\n", argc);
for ( i = 0 ; i < argc ; i++ ) {
printf("argv[%2d] = %s\n", i, argv[i]);
}
diff --git a/tests/getenvtest.c b/tests/getenvtest.c
index c074220..76d8901 100644
--- a/tests/getenvtest.c
+++ b/tests/getenvtest.c
@@ -17,6 +17,7 @@
printf("USER = %s\n", getenv("USER"));
/* Test argc/argv */
+ printf("argc = %d\n", argc);
for ( i = 0 ; i < argc ; i++ ) {
printf("argv[%2d] = %s\n", i, argv[i]);
}