patch-2.4.20 linux-2.4.20/arch/parisc/kernel/syscall.S
Next file: linux-2.4.20/arch/parisc/kernel/time.c
Previous file: linux-2.4.20/arch/parisc/kernel/sys_parisc32.c
Back to the patch index
Back to the overall index
- Lines: 484
- Date:
Thu Nov 28 15:53:10 2002
- Orig file:
linux-2.4.19/arch/parisc/kernel/syscall.S
- Orig date:
Fri Aug 2 17:39:43 2002
diff -urN linux-2.4.19/arch/parisc/kernel/syscall.S linux-2.4.20/arch/parisc/kernel/syscall.S
@@ -1,5 +1,5 @@
/*
- * Linux/PARISC Project (http://www.thepuffingroup.com/parisc)
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
*
* System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
* Licensed under the GNU GPL.
@@ -12,7 +12,6 @@
#include <asm/errno.h>
#include <asm/psw.h>
-#define __ASSEMBLY__
#include <asm/assembly.h>
#include <asm/processor.h>
#include <linux/version.h>
@@ -23,7 +22,13 @@
.level 1.1
#endif
.text
-
+
+#ifdef __LP64__
+#define FRAME_SIZE 128
+#else
+#define FRAME_SIZE 64
+#endif
+
.import syscall_exit,code
.import syscall_exit_rfi,code
.export linux_gateway_page
@@ -39,17 +44,30 @@
.align 4096
linux_gateway_page:
+ .rept 56
break 0,0
+ .endr
+set_thread_pointer:
+ gate .+8, %r0 /* increase privilege */
+ depi 3, 31, 2, %r31 /* Ensure we return into user mode. */
+ be 0(%sr7,%r31) /* return to user space */
+ mtctl %r26, %cr27 /* move arg0 to the control register */
+
+ .rept 4
+ break 0,0
+ .endr
+
+/* This address must remain fixed, or user binaries go splat. */
.align 256
linux_gateway_entry:
- mfsp %sr7,%r1 /* we must set sr3 to the space */
- mtsp %r1,%sr3 /* of the user before the gate */
gate .+8, %r0 /* become privileged */
mtsp %r0,%sr4 /* get kernel space into sr4 */
mtsp %r0,%sr5 /* get kernel space into sr5 */
mtsp %r0,%sr6 /* get kernel space into sr6 */
- mtsp %r0,%sr7 /* get kernel space into sr7 */
+ mfsp %sr7,%r1 /* save user sr7 */
+ mtsp %r1,%sr3 /* and store it in sr3 */
+
#ifdef __LP64__
/* for now we can *always* set the W bit on entry to the syscall
* since we don't support wide userland processes. We could
@@ -58,15 +76,38 @@
* whether to do narrow or wide syscalls. -PB
*/
ssm PSW_SM_W, %r0
+ /* The top halves of argument registers must be cleared on syscall
+ * entry.
+ */
+ depdi 0, 31, 32, %r26
+ depdi 0, 31, 32, %r25
+ depdi 0, 31, 32, %r24
+ depdi 0, 31, 32, %r23
+ depdi 0, 31, 32, %r22
+ depdi 0, 31, 32, %r21
#endif
- mtctl %r28,%cr27
- rsm PSW_I, %r28 /* no ints for a bit */
- mfctl %cr30,%r1 /* get the kernel task ptr */
- mtctl %r0,%cr30 /* zero it (flag) */
+ mfctl %cr30,%r1
+ xor %r1,%r30,%r30 /* ye olde xor trick */
+ xor %r1,%r30,%r1
+ xor %r1,%r30,%r30
+ ldo TASK_SZ_ALGN+FRAME_SIZE(%r30),%r30 /* set up kernel stack */
+
+ /* N.B.: It is critical that we don't set sr7 to 0 until r30
+ * contains a valid kernel stack pointer. It is also
+ * critical that we don't start using the kernel stack
+ * until after sr7 has been set to 0.
+ */
+
+ mtsp %r0,%sr7 /* get kernel space into sr7 */
+ STREG %r1,TASK_PT_GR30-TASK_SZ_ALGN-FRAME_SIZE(%r30) /* save usp */
+ ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr in %r1 */
/* Save some registers for sigcontext and potential task
switch (see entry.S for the details of which ones are
- saved/restored) */
+ saved/restored). TASK_PT_PSW is zeroed so we can see whether
+ a process is on a syscall or not. For an interrupt the real
+ PSW value is stored. This is needed for gdb and sys_ptrace. */
+ STREG %r0, TASK_PT_PSW(%r1)
STREG %r2, TASK_PT_GR2(%r1) /* preserve rp */
STREG %r19, TASK_PT_GR19(%r1)
STREG %r20, TASK_PT_GR20(%r1)
@@ -77,11 +118,9 @@
STREG %r25, TASK_PT_GR25(%r1) /* 2nd argument */
STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */
STREG %r27, TASK_PT_GR27(%r1) /* user dp */
- mfctl %cr27,%r19
- STREG %r19, TASK_PT_GR28(%r1) /* return value 0 */
- STREG %r19, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */
+ STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */
+ STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */
STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */
- STREG %r30, TASK_PT_GR30(%r1) /* preserve userspace sp */
STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */
ldo TASK_PT_FR0(%r1), %r27 /* save fpregs from the kernel */
@@ -92,10 +131,10 @@
loadgp
- ldo TASK_SZ_ALGN+64(%r1),%r30 /* set up kernel stack */
-
-#ifndef __LP64__
- /* no need to save these on stack because in wide mode the first 8
+#ifdef __LP64__
+ ldo -16(%r30),%r29 /* Reference param save area */
+#else
+ /* no need to save these on stack in wide mode because the first 8
* args are passed in registers */
stw %r22, -52(%r30) /* 5th argument */
stw %r21, -56(%r30) /* 6th argument */
@@ -103,7 +142,6 @@
/* for some unknown reason, task_struct.ptrace is an unsigned long so use LDREG */
LDREG TASK_PTRACE(%r1), %r19 /* Are we being ptraced? */
- mtsm %r28 /* irqs back */
bb,<,n %r19, 31, .Ltracesys /* must match PT_PTRACE bit */
@@ -112,7 +150,6 @@
ldil L%sys_call_table, %r1
ldo R%sys_call_table(%r1), %r19
- LDIL_FIXUP(%r19)
comiclr,>>= __NR_Linux_syscalls, %r20, %r0
b,n .Lsyscall_nosys
@@ -131,13 +168,11 @@
comb,= %r2,%r20,.Lrt_sigreturn
.Lin_syscall:
ldil L%syscall_exit,%r2
- LDIL_FIXUP(%r2)
be 0(%sr7,%r19)
ldo R%syscall_exit(%r2),%r2
.Lrt_sigreturn:
comib,<> 0,%r25,.Lin_syscall
ldil L%syscall_exit_rfi,%r2
- LDIL_FIXUP(%r2)
be 0(%sr7,%r19)
ldo R%syscall_exit_rfi(%r2),%r2
@@ -149,7 +184,6 @@
.Lsyscall_nosys:
syscall_nosys:
ldil L%syscall_exit,%r1
- LDIL_FIXUP(%r1)
be R%syscall_exit(%sr7,%r1)
ldo -ENOSYS(%r0),%r28 /* set errno */
@@ -159,12 +193,17 @@
.Ltracesys:
tracesys:
/* Need to save more registers so the debugger can see where we
- * are.
+ * are. This saves only the lower 8 bits of PSW, so that the C
+ * bit is still clear on syscalls, and the D bit is set if this
+ * full register save path has been executed. We check the D
+ * bit on syscall_return_rfi to determine which registers to
+ * restore. An interrupt results in a full PSW saved with the
+ * C bit set, a non-straced syscall entry results in C and D clear
+ * in the saved PSW.
*/
- ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */
- ssm 0,%r2 /* Lower 8 bits only!! */
- STREG %r2,TASK_PT_PSW(%r1)
- STREG %r1,TASK_PT_CR30(%r1)
+ ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
+ ssm 0,%r2
+ STREG %r2,TASK_PT_PSW(%r1) /* Lower 8 bits only!! */
mfsp %sr0,%r2
STREG %r2,TASK_PT_SR0(%r1)
mfsp %sr1,%r2
@@ -204,18 +243,15 @@
/* Finished saving things for the debugger */
ldil L%syscall_trace,%r1
- LDIL_FIXUP(%r1)
ldil L%tracesys_next,%r2
- LDIL_FIXUP(%r2)
be R%syscall_trace(%sr7,%r1)
ldo R%tracesys_next(%r2),%r2
tracesys_next:
ldil L%sys_call_table,%r1
- LDIL_FIXUP(%r1)
ldo R%sys_call_table(%r1), %r19
- ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */
+ ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
LDREG TASK_PT_GR20(%r1), %r20
LDREG TASK_PT_GR26(%r1), %r26 /* Restore the users args */
LDREG TASK_PT_GR25(%r1), %r25
@@ -224,6 +260,7 @@
#ifdef __LP64__
LDREG TASK_PT_GR22(%r1), %r22
LDREG TASK_PT_GR21(%r1), %r21
+ ldo -16(%r30),%r29 /* Reference param save area */
#endif
comiclr,>>= __NR_Linux_syscalls, %r20, %r0
@@ -243,7 +280,6 @@
comb,= %r2,%r20,.Ltrace_rt_sigreturn
.Ltrace_in_syscall:
ldil L%tracesys_exit,%r2
- LDIL_FIXUP(%r2)
be 0(%sr7,%r19)
ldo R%tracesys_exit(%r2),%r2
@@ -251,30 +287,33 @@
makes a direct call to syscall_trace. */
tracesys_exit:
- ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */
+ ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
+#ifdef __LP64__
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
bl syscall_trace, %r2
STREG %r28,TASK_PT_GR28(%r1) /* save return value now */
- ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */
+ ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
LDREG TASK_PT_GR28(%r1), %r28 /* Restore return val. */
ldil L%syscall_exit,%r1
- LDIL_FIXUP(%r1)
be,n R%syscall_exit(%sr7,%r1)
.Ltrace_rt_sigreturn:
comib,<> 0,%r25,.Ltrace_in_syscall
ldil L%tracesys_sigexit,%r2
- LDIL_FIXUP(%r2)
be 0(%sr7,%r19)
ldo R%tracesys_sigexit(%r2),%r2
tracesys_sigexit:
- ldo -TASK_SZ_ALGN-64(%r30),%r1 /* get task ptr */
+ ldo -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
+#ifdef __LP64__
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
bl syscall_trace, %r2
nop
ldil L%syscall_exit_rfi,%r1
- LDIL_FIXUP(%r1)
be,n R%syscall_exit_rfi(%sr7,%r1)
#ifdef __LP64__
@@ -282,13 +321,13 @@
* narrow palinux. Use ENTRY_DIFF for those where a 32-bit specific
* implementation is required on wide palinux.
*/
-#define ENTRY_SAME(_name_) .dword sys_##_name_
-#define ENTRY_DIFF(_name_) .dword sys32_##_name_
-#define ENTRY_UHOH(_name_) .dword sys32_unimplemented
+#define ENTRY_SAME(_name_) .dword sys_/**/_name_
+#define ENTRY_DIFF(_name_) .dword sys32_/**/_name_
+#define ENTRY_UHOH(_name_) .dword sys32_/**/unimplemented
#else
-#define ENTRY_SAME(_name_) .word sys_##_name_
-#define ENTRY_DIFF(_name_) .word sys_##_name_
-#define ENTRY_UHOH(_name_) .word sys_##_name_
+#define ENTRY_SAME(_name_) .word sys_/**/_name_
+#define ENTRY_DIFF(_name_) .word sys_/**/_name_
+#define ENTRY_UHOH(_name_) .word sys_/**/_name_
#endif
.align 8
@@ -316,7 +355,7 @@
ENTRY_SAME(socket)
/* struct stat is MAYBE identical wide and narrow ?? */
ENTRY_DIFF(newstat)
- ENTRY_SAME(lseek)
+ ENTRY_DIFF(lseek)
ENTRY_SAME(getpid) /* 20 */
/* the 'void * data' parameter may need re-packing in wide */
ENTRY_DIFF(mount)
@@ -391,8 +430,8 @@
ENTRY_DIFF(getrlimit)
ENTRY_DIFF(getrusage)
/* struct timeval and timezone are maybe?? consistent wide and narrow */
- ENTRY_SAME(gettimeofday)
- ENTRY_SAME(settimeofday)
+ ENTRY_DIFF(gettimeofday)
+ ENTRY_DIFF(settimeofday)
ENTRY_SAME(getgroups) /* 80 */
ENTRY_SAME(setgroups)
/* struct socketaddr... */
@@ -402,12 +441,12 @@
ENTRY_DIFF(newlstat)
ENTRY_SAME(readlink) /* 85 */
/* suspect we'll need some work for narrow shlibs on wide kernel */
+ /* NOTE this doesn't get used when I boot 32-bit userspace */
+ /* containing working shlib apps -- can this be nuked? */
ENTRY_UHOH(uselib)
ENTRY_SAME(swapon)
ENTRY_SAME(reboot)
- /* argh! struct dirent contains a long */
- ENTRY_UHOH(old_readdir)
- /* I'm not certain about off_t... */
+ ENTRY_SAME(mmap2)
ENTRY_SAME(mmap) /* 90 */
ENTRY_SAME(munmap)
ENTRY_SAME(truncate)
@@ -419,28 +458,27 @@
ENTRY_SAME(recv)
ENTRY_DIFF(statfs)
ENTRY_DIFF(fstatfs) /* 100 */
- ENTRY_SAME(ni_syscall)
+ ENTRY_SAME(stat64)
/* don't think hppa glibc even provides an entry pt for this
* so disable for now */
ENTRY_UHOH(socketcall)
ENTRY_SAME(syslog)
/* even though manpage says struct timeval contains longs, ours has
* time_t and suseconds_t -- both of which are safe wide/narrow */
- ENTRY_SAME(setitimer)
- ENTRY_SAME(getitimer) /* 105 */
+ ENTRY_DIFF(setitimer)
+ ENTRY_DIFF(getitimer) /* 105 */
ENTRY_SAME(capget)
ENTRY_SAME(capset)
- ENTRY_SAME(pread)
- ENTRY_SAME(pwrite)
+ ENTRY_DIFF(pread)
+ ENTRY_DIFF(pwrite)
ENTRY_SAME(getcwd) /* 110 */
ENTRY_SAME(vhangup)
- ENTRY_SAME(ni_syscall)
+ ENTRY_SAME(fstat64)
ENTRY_SAME(vfork_wrapper)
/* struct rusage contains longs... */
ENTRY_DIFF(wait4)
ENTRY_SAME(swapoff) /* 115 */
- /* struct sysinfo contains longs */
- ENTRY_SAME(sysinfo)
+ ENTRY_DIFF(sysinfo)
ENTRY_SAME(shutdown)
ENTRY_SAME(fsync)
ENTRY_SAME(madvise)
@@ -450,7 +488,7 @@
/* struct sockaddr... */
ENTRY_SAME(recvfrom)
/* struct timex contains longs */
- ENTRY_UHOH(adjtimex)
+ ENTRY_DIFF(adjtimex)
ENTRY_SAME(mprotect) /* 125 */
/* old_sigset_t forced to 32 bits. Beware glibc sigset_t */
ENTRY_DIFF(sigprocmask)
@@ -461,12 +499,11 @@
ENTRY_SAME(delete_module)
/* struct kernel_sym contains a long. Linus never heard of size_t? */
ENTRY_DIFF(get_kernel_syms) /* 130 */
- ENTRY_SAME(quotactl)
+ /* time_t inside struct dqblk */
+ ENTRY_DIFF(quotactl)
ENTRY_SAME(getpgid)
ENTRY_SAME(fchdir)
- /* bdflush(func, addr) where func has least-significant-bit set means
- * addr is a pointer to long :-( */
- ENTRY_UHOH(bdflush)
+ ENTRY_SAME(bdflush)
ENTRY_SAME(sysfs) /* 135 */
ENTRY_SAME(personality)
ENTRY_SAME(ni_syscall) /* for afs_syscall */
@@ -479,12 +516,12 @@
ENTRY_DIFF(getdents)
/* it is POSSIBLE that select will be OK because even though fd_set
* contains longs, the macros and sizes are clever. */
- ENTRY_SAME(select)
+ ENTRY_DIFF(select)
ENTRY_SAME(flock)
ENTRY_SAME(msync)
/* struct iovec contains pointers */
- ENTRY_UHOH(readv) /* 145 */
- ENTRY_UHOH(writev)
+ ENTRY_DIFF(readv) /* 145 */
+ ENTRY_DIFF(writev)
ENTRY_SAME(getsid)
ENTRY_SAME(fdatasync)
/* struct __sysctl_args is a mess */
@@ -509,13 +546,12 @@
ENTRY_SAME(mremap)
ENTRY_SAME(setresuid)
ENTRY_SAME(getresuid) /* 165 */
- /* might work, but in general signals need a thorough review */
- ENTRY_UHOH(sigaltstack_wrapper)
+ ENTRY_DIFF(sigaltstack_wrapper)
/* struct passed back to user can contain long symbol values */
ENTRY_DIFF(query_module)
ENTRY_SAME(poll)
/* structs contain pointers and an in_addr... */
- ENTRY_UHOH(nfsservctl)
+ ENTRY_DIFF(nfsservctl)
ENTRY_SAME(setresgid) /* 170 */
ENTRY_SAME(getresgid)
ENTRY_SAME(prctl)
@@ -525,35 +561,43 @@
ENTRY_DIFF(rt_sigprocmask) /* 175 */
ENTRY_DIFF(rt_sigpending)
ENTRY_UHOH(rt_sigtimedwait)
- ENTRY_UHOH(rt_sigqueueinfo)
+ /* even though the struct siginfo_t is different, it appears like
+ * all the paths use values which should be same wide and narrow.
+ * Also the struct is padded to 128 bytes which means we don't have
+ * to worry about faulting trying to copy in a larger 64-bit
+ * struct from a 32-bit user-space app.
+ */
+ ENTRY_SAME(rt_sigqueueinfo)
ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
ENTRY_SAME(chown) /* 180 */
- /* *sockopt() might work... */
- ENTRY_SAME(setsockopt)
+ /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
+ ENTRY_DIFF(setsockopt)
ENTRY_SAME(getsockopt)
- /* struct msghdr contains pointers... */
- ENTRY_UHOH(sendmsg)
- ENTRY_UHOH(recvmsg)
+ ENTRY_DIFF(sendmsg)
+ ENTRY_DIFF(recvmsg)
ENTRY_SAME(semop) /* 185 */
ENTRY_SAME(semget)
- /* needs a more careful review */
- ENTRY_UHOH(semctl)
- /* struct msgbuf contains a long */
- ENTRY_UHOH(msgsnd)
- ENTRY_UHOH(msgrcv)
+ ENTRY_DIFF(semctl_broken)
+ ENTRY_DIFF(msgsnd)
+ ENTRY_DIFF(msgrcv)
ENTRY_SAME(msgget) /* 190 */
- /* struct msqid_ds contains pointers */
- ENTRY_UHOH(msgctl)
+ ENTRY_SAME(msgctl_broken)
ENTRY_SAME(shmat_wrapper)
ENTRY_SAME(shmdt)
ENTRY_SAME(shmget)
- /***************/
- /* struct shmid_ds contains pointers */
- ENTRY_UHOH(shmctl) /* 195 */
+ ENTRY_SAME(shmctl_broken) /* 195 */
ENTRY_SAME(ni_syscall) /* streams1 */
ENTRY_SAME(ni_syscall) /* streams2 */
+ ENTRY_SAME(lstat64)
+ ENTRY_DIFF(truncate64)
+ ENTRY_DIFF(ftruncate64) /* 200 */
+ ENTRY_SAME(getdents64)
+ ENTRY_DIFF(fcntl64)
+ ENTRY_SAME(ni_syscall) /* attrctl */
+ ENTRY_SAME(ni_syscall) /* acl_get */
+ ENTRY_SAME(ni_syscall) /* acl_set */
ENTRY_SAME(gettid)
- ENTRY_SAME(tkill)
+ ENTRY_SAME(readahead)
.end
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)