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]);
   }