summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-16 05:34:03 +0000
commit967c65a99059fd459b956c1588ce0ba227912c4e (patch)
tree8224d013ff5d255420713d05610c7efebd204d2a /arch/alpha/kernel
parente20c1cc1656a66a2773bca4591a895cbc12696ff (diff)
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c2
-rw-r--r--arch/alpha/kernel/entry.S480
-rw-r--r--arch/alpha/kernel/osf_sys.c412
-rw-r--r--arch/alpha/kernel/ptrace.c22
-rw-r--r--arch/alpha/kernel/signal.c599
-rw-r--r--arch/alpha/kernel/time.c182
-rw-r--r--arch/alpha/kernel/traps.c157
7 files changed, 1446 insertions, 408 deletions
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index be75f566f..822513e4e 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -94,7 +94,7 @@ EXPORT_SYMBOL(csum_partial_copy);
* The following are specially called from the uaccess assembly stubs.
*/
EXPORT_SYMBOL_NOVERS(__copy_user);
-EXPORT_SYMBOL_NOVERS(__clear_user);
+EXPORT_SYMBOL_NOVERS(__do_clear_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strlen_user);
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 75c0665a7..0eef8b539 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -10,7 +10,7 @@
#define rti .long PAL_rti
#define SIGCHLD 20
-#define NR_SYSCALLS 352
+#define NR_SYSCALLS 360
#define osf_vfork sys_fork
/*
@@ -32,9 +32,8 @@
#define TASK_STATE 0
#define TASK_COUNTER 8
#define TASK_PRIORITY 16
-#define TASK_SIGNAL 24
-#define TASK_BLOCKED 32
-#define TASK_FLAGS 40
+#define TASK_FLAGS 24
+#define TASK_SIGPENDING 32
/*
* task flags (must match include/linux/sched.h):
@@ -509,7 +508,7 @@ entSys:
lda $4,NR_SYSCALLS($31)
stq $16,SP_OFF+24($30)
lda $5,sys_call_table
- lda $27,do_entSys
+ lda $27,alpha_ni_syscall
cmpult $0,$4,$4
ldq $3,TASK_FLAGS($8)
stq $17,SP_OFF+32($30)
@@ -519,7 +518,7 @@ entSys:
bne $3,strace
beq $4,1f
ldq $27,0($5)
-1: jsr $26,($27),do_entSys
+1: jsr $26,($27),alpha_ni_syscall
ldgp $29,0($26)
blt $0,syscall_error /* the call failed */
stq $0,0($30)
@@ -544,11 +543,9 @@ ret_from_reschedule:
lda $4,init_task_union
bne $2,reschedule
xor $4,$8,$4
+ ldl $5,TASK_SIGPENDING($8)
beq $4,restore_all
- ldq $4,TASK_SIGNAL($8)
- ldq $16,TASK_BLOCKED($8)
- bic $4,$16,$4
- bne $4,signal_return
+ bne $5,signal_return
restore_all:
RESTORE_ALL
rti
@@ -574,12 +571,12 @@ strace:
/* get the system call pointer.. */
lda $1,NR_SYSCALLS($31)
lda $2,sys_call_table
- lda $27,do_entSys
+ lda $27,alpha_ni_syscall
cmpult $0,$1,$1
s8addq $0,$2,$2
beq $1,1f
ldq $27,0($2)
-1: jsr $26,($27),do_entSys
+1: jsr $26,($27),alpha_ni_syscall
ldgp $29,0($26)
/* check return.. */
@@ -656,6 +653,7 @@ signal_return:
bis $30,$30,$17
br $1,do_switch_stack
bis $30,$30,$18
+ bis $31,$31,$16
jsr $26,do_signal
lda $30,SWITCH_STACK_SIZE($30)
br $31,restore_all
@@ -686,6 +684,17 @@ sys_sigreturn:
.end sys_sigreturn
.align 3
+.ent sys_rt_sigreturn
+sys_rt_sigreturn:
+ bis $30,$30,$17
+ lda $30,-SWITCH_STACK_SIZE($30)
+ bis $30,$30,$18
+ jsr $26,do_rt_sigreturn
+ br $1,undo_switch_stack
+ br $31,ret_from_sys_call
+.end sys_rt_sigreturn
+
+.align 3
.ent sys_sigsuspend
sys_sigsuspend:
bis $30,$30,$17
@@ -696,80 +705,383 @@ sys_sigsuspend:
br $31,ret_from_sys_call
.end sys_sigsuspend
+.align 3
+.ent sys_rt_sigsuspend
+sys_rt_sigsuspend:
+ bis $30,$30,$18
+ br $1,do_switch_stack
+ bis $30,$30,$19
+ jsr $26,do_rt_sigsuspend
+ lda $30,SWITCH_STACK_SIZE($30)
+ br $31,ret_from_sys_call
+.end sys_rt_sigsuspend
+
+ .data
.align 3
.globl sys_call_table
sys_call_table:
-/*0*/ .quad do_entSys, sys_exit, sys_fork, sys_read, sys_write
- .quad do_entSys, sys_close, sys_wait4, do_entSys, sys_link
- .quad sys_unlink, do_entSys, sys_chdir, sys_fchdir, sys_mknod
- .quad sys_chmod, sys_chown, osf_brk, do_entSys, sys_lseek
- .quad sys_getxpid, osf_mount, osf_umount, sys_setuid, sys_getxuid
- .quad do_entSys, sys_ptrace, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, sys_access, do_entSys
- .quad do_entSys, sys_sync, sys_kill, do_entSys, sys_setpgid
- .quad do_entSys, sys_dup, sys_pipe, osf_set_program_attributes, do_entSys
- .quad sys_open, do_entSys, sys_getxgid, osf_sigprocmask, do_entSys
-/*50*/ .quad do_entSys, sys_acct, sys_sigpending, do_entSys, sys_ioctl
- .quad do_entSys, do_entSys, sys_symlink, sys_readlink, sys_execve
- .quad sys_umask, sys_chroot, do_entSys, sys_getpgrp, sys_getpagesize
- .quad do_entSys, osf_vfork, sys_newstat, sys_newlstat, do_entSys
- .quad do_entSys, osf_mmap, do_entSys, sys_munmap, sys_mprotect
- .quad sys_madvise, sys_vhangup, do_entSys, do_entSys, sys_getgroups
+ .quad alpha_ni_syscall /* 0 */
+ .quad sys_exit
+ .quad sys_fork
+ .quad sys_read
+ .quad sys_write
+ .quad alpha_ni_syscall /* 5 */
+ .quad sys_close
+ .quad osf_wait4
+ .quad alpha_ni_syscall
+ .quad sys_link
+ .quad sys_unlink /* 10 */
+ .quad alpha_ni_syscall
+ .quad sys_chdir
+ .quad sys_fchdir
+ .quad sys_mknod
+ .quad sys_chmod /* 15 */
+ .quad sys_chown
+ .quad osf_brk
+ .quad alpha_ni_syscall
+ .quad sys_lseek
+ .quad sys_getxpid /* 20 */
+ .quad osf_mount
+ .quad osf_umount
+ .quad sys_setuid
+ .quad sys_getxuid
+ .quad alpha_ni_syscall /* 25 */
+ .quad sys_ptrace
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 30 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad sys_access
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 35 */
+ .quad sys_sync
+ .quad sys_kill
+ .quad alpha_ni_syscall
+ .quad sys_setpgid
+ .quad alpha_ni_syscall /* 40 */
+ .quad sys_dup
+ .quad sys_pipe
+ .quad osf_set_program_attributes
+ .quad alpha_ni_syscall
+ .quad sys_open /* 45 */
+ .quad alpha_ni_syscall
+ .quad sys_getxgid
+ .quad osf_sigprocmask
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 50 */
+ .quad sys_acct
+ .quad osf_sigpending
+ .quad alpha_ni_syscall
+ .quad sys_ioctl
+ .quad alpha_ni_syscall /* 55 */
+ .quad alpha_ni_syscall
+ .quad sys_symlink
+ .quad sys_readlink
+ .quad sys_execve
+ .quad sys_umask /* 60 */
+ .quad sys_chroot
+ .quad alpha_ni_syscall
+ .quad sys_getpgrp
+ .quad sys_getpagesize
+ .quad alpha_ni_syscall /* 65 */
+ .quad osf_vfork
+ .quad sys_newstat
+ .quad sys_newlstat
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 70 */
+ .quad osf_mmap
+ .quad alpha_ni_syscall
+ .quad sys_munmap
+ .quad sys_mprotect
+ .quad sys_madvise /* 75 */
+ .quad sys_vhangup
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad sys_getgroups
/* map BSD's setpgrp to sys_setpgid for binary compatibility: */
- .quad sys_setgroups, do_entSys, sys_setpgid, sys_setitimer, do_entSys
- .quad do_entSys, sys_getitimer, sys_gethostname, sys_sethostname, sys_getdtablesize
- .quad sys_dup2, sys_newfstat, sys_fcntl, sys_select, sys_poll
- .quad sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
-/*100*/ .quad osf_getpriority, sys_send, sys_recv, sys_sigreturn, sys_bind
- .quad sys_setsockopt, sys_listen, do_entSys, do_entSys, do_entSys
- .quad do_entSys, sys_sigsuspend, do_entSys, sys_recvmsg, sys_sendmsg
- .quad do_entSys, sys_gettimeofday, sys_getrusage, sys_getsockopt, do_entSys
- .quad sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
- .quad sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
- .quad sys_ftruncate, sys_flock, sys_setgid, sys_sendto, sys_shutdown
- .quad sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, do_entSys
- .quad do_entSys, sys_getpeername, do_entSys, do_entSys, sys_getrlimit
- .quad sys_setrlimit, do_entSys, sys_setsid, sys_quotactl, do_entSys
-/*150*/ .quad sys_getsockname, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, sys_sigaction, do_entSys, do_entSys, osf_getdirentries
- .quad osf_statfs, osf_fstatfs, do_entSys, do_entSys, do_entSys
- .quad osf_getdomainname, sys_setdomainname, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, osf_swapon
-/*200*/ .quad sys_msgctl, sys_msgget, sys_msgrcv, sys_msgsnd, sys_semctl
- .quad sys_semget, sys_semop, osf_utsname, do_entSys, osf_shmat
- .quad sys_shmctl, sys_shmdt, sys_shmget, do_entSys, do_entSys
- .quad do_entSys, do_entSys, sys_msync, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, sys_getpgid, sys_getsid
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, osf_sysinfo, do_entSys, do_entSys, osf_proplist_syscall
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
-/*250*/ .quad do_entSys, osf_usleep_thread, do_entSys, do_entSys, sys_sysfs
- .quad do_entSys, osf_getsysinfo, osf_setsysinfo, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
- .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad sys_setgroups /* 80 */
+ .quad alpha_ni_syscall
+ .quad sys_setpgid
+ .quad osf_setitimer
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 85 */
+ .quad osf_getitimer
+ .quad sys_gethostname
+ .quad sys_sethostname
+ .quad sys_getdtablesize
+ .quad sys_dup2 /* 90 */
+ .quad sys_newfstat
+ .quad sys_fcntl
+ .quad osf_select
+ .quad sys_poll
+ .quad sys_fsync /* 95 */
+ .quad sys_setpriority
+ .quad sys_socket
+ .quad sys_connect
+ .quad sys_accept
+ .quad osf_getpriority /* 100 */
+ .quad sys_send
+ .quad sys_recv
+ .quad sys_sigreturn
+ .quad sys_bind
+ .quad sys_setsockopt /* 105 */
+ .quad sys_listen
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 110 */
+ .quad sys_sigsuspend
+ .quad alpha_ni_syscall
+ .quad sys_recvmsg
+ .quad sys_sendmsg
+ .quad alpha_ni_syscall /* 115 */
+ .quad osf_gettimeofday
+ .quad osf_getrusage
+ .quad sys_getsockopt
+ .quad alpha_ni_syscall
+ .quad sys_readv /* 120 */
+ .quad sys_writev
+ .quad osf_settimeofday
+ .quad sys_fchown
+ .quad sys_fchmod
+ .quad sys_recvfrom /* 125 */
+ .quad sys_setreuid
+ .quad sys_setregid
+ .quad sys_rename
+ .quad sys_truncate
+ .quad sys_ftruncate /* 130 */
+ .quad sys_flock
+ .quad sys_setgid
+ .quad sys_sendto
+ .quad sys_shutdown
+ .quad sys_socketpair /* 135 */
+ .quad sys_mkdir
+ .quad sys_rmdir
+ .quad osf_utimes
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 140 */
+ .quad sys_getpeername
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad sys_getrlimit
+ .quad sys_setrlimit /* 145 */
+ .quad alpha_ni_syscall
+ .quad sys_setsid
+ .quad sys_quotactl
+ .quad alpha_ni_syscall
+ .quad sys_getsockname /* 150 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 155 */
+ .quad osf_sigaction
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad osf_getdirentries
+ .quad osf_statfs /* 160 */
+ .quad osf_fstatfs
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad osf_getdomainname /* 165 */
+ .quad sys_setdomainname
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 170 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 175 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 180 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 185 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 190 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 195 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad osf_swapon
+ .quad sys_msgctl /* 200 */
+ .quad sys_msgget
+ .quad sys_msgrcv
+ .quad sys_msgsnd
+ .quad sys_semctl
+ .quad sys_semget /* 205 */
+ .quad sys_semop
+ .quad osf_utsname
+ .quad alpha_ni_syscall
+ .quad osf_shmat
+ .quad sys_shmctl /* 210 */
+ .quad sys_shmdt
+ .quad sys_shmget
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 215 */
+ .quad alpha_ni_syscall
+ .quad sys_msync
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 220 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 225 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 230 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad sys_getpgid
+ .quad sys_getsid
+ .quad alpha_ni_syscall /* 235 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 240 */
+ .quad osf_sysinfo
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad osf_proplist_syscall
+ .quad alpha_ni_syscall /* 245 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 250 */
+ .quad osf_usleep_thread
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad sys_sysfs
+ .quad alpha_ni_syscall /* 255 */
+ .quad osf_getsysinfo
+ .quad osf_setsysinfo
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 260 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 265 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 270 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 275 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 280 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 285 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 290 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 295 */
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
/* linux-specific system calls start at 300 */
-/*300*/ .quad sys_bdflush, sys_sethae, sys_mount, sys_adjtimex, sys_swapoff
- .quad sys_getdents, alpha_create_module, sys_init_module, sys_delete_module, sys_get_kernel_syms
- .quad sys_syslog, sys_reboot, sys_clone, sys_uselib, sys_mlock
- .quad sys_munlock, sys_mlockall, sys_munlockall, sys_sysinfo, sys_sysctl
- .quad sys_idle, sys_umount, sys_swapon, sys_times, sys_personality
- .quad sys_setfsuid, sys_setfsgid, sys_ustat, sys_statfs, sys_fstatfs
- .quad sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler, sys_sched_yield
- .quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname
- .quad sys_nanosleep, sys_mremap, sys_nfsservctl, sys_setresuid, sys_getresuid
- .quad sys_pciconfig_read, sys_pciconfig_write, sys_query_module
- .quad sys_prctl, sys_pread, sys_pwrite
- .quad do_entSys, do_entSys
+ .quad sys_bdflush /* 300 */
+ .quad sys_sethae
+ .quad sys_mount
+ .quad sys_adjtimex
+ .quad sys_swapoff
+ .quad sys_getdents /* 305 */
+ .quad alpha_create_module
+ .quad sys_init_module
+ .quad sys_delete_module
+ .quad sys_get_kernel_syms
+ .quad sys_syslog /* 310 */
+ .quad sys_reboot
+ .quad sys_clone
+ .quad sys_uselib
+ .quad sys_mlock
+ .quad sys_munlock /* 315 */
+ .quad sys_mlockall
+ .quad sys_munlockall
+ .quad sys_sysinfo
+ .quad sys_sysctl
+ .quad sys_idle /* 320 */
+ .quad sys_umount
+ .quad sys_swapon
+ .quad sys_times
+ .quad sys_personality
+ .quad sys_setfsuid /* 325 */
+ .quad sys_setfsgid
+ .quad sys_ustat
+ .quad sys_statfs
+ .quad sys_fstatfs
+ .quad sys_sched_setparam /* 330 */
+ .quad sys_sched_getparam
+ .quad sys_sched_setscheduler
+ .quad sys_sched_getscheduler
+ .quad sys_sched_yield
+ .quad sys_sched_get_priority_max /* 335 */
+ .quad sys_sched_get_priority_min
+ .quad sys_sched_rr_get_interval
+ .quad alpha_ni_syscall /* sys_afs_syscall */
+ .quad sys_newuname
+ .quad sys_nanosleep /* 340 */
+ .quad sys_mremap
+ .quad sys_nfsservctl
+ .quad sys_setresuid
+ .quad sys_getresuid
+ .quad sys_pciconfig_read /* 345 */
+ .quad sys_pciconfig_write
+ .quad sys_query_module
+ .quad sys_prctl
+ .quad sys_pread
+ .quad sys_pwrite /* 350 */
+ .quad sys_rt_sigreturn
+ .quad sys_rt_sigaction
+ .quad sys_rt_sigprocmask
+ .quad sys_rt_sigpending
+ .quad sys_rt_sigtimedwait /* 355 */
+ .quad sys_rt_sigqueueinfo
+ .quad sys_rt_sigsuspend
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall
+ .quad alpha_ni_syscall /* 360 */
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index a736704a0..e64b6d5e1 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -28,6 +28,7 @@
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/shm.h>
+#include <linux/poll.h>
#include <asm/fpu.h>
#include <asm/io.h>
@@ -167,6 +168,9 @@ out:
return error;
}
+#undef ROUND_UP
+#undef NAME_OFFSET
+
/*
* Alpha syscall convention has no problem returning negative
* values:
@@ -202,24 +206,24 @@ asmlinkage unsigned long sys_madvise(void)
/*
* No need to acquire the kernel lock, we're local..
*/
-asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5,
- struct pt_regs regs)
+asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4,
+ int a5, struct pt_regs regs)
{
struct task_struct * tsk = current;
(&regs)->r20 = tsk->euid;
return tsk->uid;
}
-asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5,
- struct pt_regs regs)
+asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4,
+ int a5, struct pt_regs regs)
{
struct task_struct * tsk = current;
(&regs)->r20 = tsk->egid;
return tsk->gid;
}
-asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5,
- struct pt_regs regs)
+asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4,
+ int a5, struct pt_regs regs)
{
struct task_struct *tsk = current;
@@ -524,47 +528,6 @@ asmlinkage int osf_umount(char *path, int flag)
return ret;
}
-/*
- * I don't know what the parameters are: the first one
- * seems to be a timeval pointer, and I suspect the second
- * one is the time remaining.. Ho humm.. No documentation.
- */
-asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain)
-{
- struct timeval tmp;
- unsigned long ticks;
- int retval;
-
- lock_kernel();
- retval = verify_area(VERIFY_READ, sleep, sizeof(*sleep));
- if (retval)
- goto out;
- if (remain && (retval = verify_area(VERIFY_WRITE, remain, sizeof(*remain))))
- goto out;
- copy_from_user(&tmp, sleep, sizeof(*sleep));
- ticks = tmp.tv_usec;
- ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
- ticks += tmp.tv_sec * HZ;
- current->timeout = ticks + jiffies;
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- retval = 0;
- if (!remain)
- goto out;
- ticks = jiffies;
- if (ticks < current->timeout)
- ticks = current->timeout - ticks;
- else
- ticks = 0;
- current->timeout = 0;
- tmp.tv_sec = ticks / HZ;
- tmp.tv_usec = ticks % HZ;
- copy_to_user(remain, &tmp, sizeof(*remain));
-out:
- unlock_kernel();
- return retval;
-}
-
asmlinkage int osf_utsname(char *name)
{
int error;
@@ -956,3 +919,358 @@ asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
return -EOPNOTSUPP;
}
+
+/* Translations due to the fact that OSF's time_t is an int. Which
+ affects all sorts of things, like timeval and itimerval. */
+
+extern struct timezone sys_tz;
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+extern int do_getitimer(int which, struct itimerval *value);
+extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+asmlinkage int sys_utimes(char *, struct timeval *);
+extern int sys_wait4(pid_t, int *, int, struct rusage *);
+
+struct timeval32
+{
+ int tv_sec, tv_usec;
+};
+
+struct itimerval32
+{
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+static inline long get_tv32(struct timeval *o, struct timeval32 *i)
+{
+ return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+ (__get_user(o->tv_sec, &i->tv_sec) |
+ __get_user(o->tv_usec, &i->tv_usec)));
+}
+
+static inline long put_tv32(struct timeval32 *o, struct timeval *i)
+{
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->tv_sec, &o->tv_sec) |
+ __put_user(i->tv_usec, &o->tv_usec)));
+}
+
+static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
+{
+ return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
+ (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
+ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
+ __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
+ __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
+}
+
+static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
+{
+ return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) ||
+ (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
+ __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
+ __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
+ __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
+}
+
+asmlinkage int osf_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (put_tv32(tv, &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int osf_settimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+ struct timeval ktv;
+ struct timezone ktz;
+
+ if (tv) {
+ if (get_tv32(&ktv, tv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, tz, sizeof(*tz)))
+ return -EFAULT;
+ }
+
+ return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+asmlinkage int osf_getitimer(int which, struct itimerval32 *it)
+{
+ struct itimerval kit;
+ int error;
+
+ error = do_getitimer(which, &kit);
+ if (!error && put_it32(it, &kit))
+ error = -EFAULT;
+
+ return error;
+}
+
+asmlinkage int osf_setitimer(int which, struct itimerval32 *in,
+ struct itimerval32 *out)
+{
+ struct itimerval kin, kout;
+ int error;
+
+ if (in) {
+ if (get_it32(&kin, in))
+ return -EFAULT;
+ } else
+ memset(&kin, 0, sizeof(kin));
+
+ error = do_setitimer(which, &kin, out ? &kout : NULL);
+ if (error || !out)
+ return error;
+
+ if (put_it32(out, &kout))
+ return -EFAULT;
+
+ return 0;
+
+}
+
+asmlinkage int osf_utimes(const char *filename, struct timeval32 *tvs)
+{
+ char *kfilename;
+ struct timeval ktvs[2];
+ mm_segment_t old_fs;
+ int ret;
+
+ kfilename = getname(filename);
+ if (IS_ERR(kfilename))
+ return PTR_ERR(kfilename);
+
+ if (tvs) {
+ if (get_tv32(&ktvs[0], &tvs[0]) ||
+ get_tv32(&ktvs[1], &tvs[1]))
+ return -EFAULT;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_utimes(kfilename, tvs ? ktvs : 0);
+ set_fs(old_fs);
+
+ putname(kfilename);
+
+ return ret;
+}
+
+asmlinkage int
+osf_select(int n, fd_set *inp, fd_set *outp, fd_set *exp,
+ struct timeval32 *tvp)
+{
+ fd_set_buffer *fds;
+ unsigned long timeout;
+ int ret;
+
+ timeout = ~0UL;
+ if (tvp) {
+ time_t sec, usec;
+
+ if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
+ || (ret = __get_user(sec, &tvp->tv_sec))
+ || (ret = __get_user(usec, &tvp->tv_usec)))
+ goto out_nofds;
+
+ timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
+ timeout += sec * HZ;
+ if (timeout)
+ timeout += jiffies + 1;
+ }
+
+ ret = -ENOMEM;
+ fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL);
+ if (!fds)
+ goto out_nofds;
+ ret = -EINVAL;
+ if (n < 0)
+ goto out;
+ if (n > KFDS_NR)
+ n = KFDS_NR;
+ if ((ret = get_fd_set(n, inp->fds_bits, fds->in)) ||
+ (ret = get_fd_set(n, outp->fds_bits, fds->out)) ||
+ (ret = get_fd_set(n, exp->fds_bits, fds->ex)))
+ goto out;
+ zero_fd_set(n, fds->res_in);
+ zero_fd_set(n, fds->res_out);
+ zero_fd_set(n, fds->res_ex);
+
+ ret = do_select(n, fds, timeout);
+
+ /* OSF does not copy back the remaining time. */
+
+ if (ret < 0)
+ goto out;
+ if (!ret) {
+ ret = -ERESTARTNOHAND;
+ if (signal_pending(current))
+ goto out;
+ ret = 0;
+ }
+
+ set_fd_set(n, inp->fds_bits, fds->res_in);
+ set_fd_set(n, outp->fds_bits, fds->res_out);
+ set_fd_set(n, exp->fds_bits, fds->res_ex);
+
+out:
+ free_page((unsigned long) fds);
+out_nofds:
+ return ret;
+}
+
+struct rusage32 {
+ struct timeval32 ru_utime; /* user time used */
+ struct timeval32 ru_stime; /* system time used */
+ long ru_maxrss; /* maximum resident set size */
+ long ru_ixrss; /* integral shared memory size */
+ long ru_idrss; /* integral unshared data size */
+ long ru_isrss; /* integral unshared stack size */
+ long ru_minflt; /* page reclaims */
+ long ru_majflt; /* page faults */
+ long ru_nswap; /* swaps */
+ long ru_inblock; /* block input operations */
+ long ru_oublock; /* block output operations */
+ long ru_msgsnd; /* messages sent */
+ long ru_msgrcv; /* messages received */
+ long ru_nsignals; /* signals received */
+ long ru_nvcsw; /* voluntary context switches */
+ long ru_nivcsw; /* involuntary " */
+};
+
+asmlinkage int osf_getrusage(int who, struct rusage32 *ru)
+{
+ struct rusage32 r;
+
+ if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
+ return -EINVAL;
+
+ memset(&r, 0, sizeof(r));
+ switch (who) {
+ case RUSAGE_SELF:
+ r.ru_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
+ r.ru_utime.tv_usec = CT_TO_USECS(current->times.tms_utime);
+ r.ru_stime.tv_sec = CT_TO_SECS(current->times.tms_stime);
+ r.ru_stime.tv_usec = CT_TO_USECS(current->times.tms_stime);
+ r.ru_minflt = current->min_flt;
+ r.ru_majflt = current->maj_flt;
+ r.ru_nswap = current->nswap;
+ break;
+ case RUSAGE_CHILDREN:
+ r.ru_utime.tv_sec = CT_TO_SECS(current->times.tms_cutime);
+ r.ru_utime.tv_usec = CT_TO_USECS(current->times.tms_cutime);
+ r.ru_stime.tv_sec = CT_TO_SECS(current->times.tms_cstime);
+ r.ru_stime.tv_usec = CT_TO_USECS(current->times.tms_cstime);
+ r.ru_minflt = current->cmin_flt;
+ r.ru_majflt = current->cmaj_flt;
+ r.ru_nswap = current->cnswap;
+ break;
+ default:
+ r.ru_utime.tv_sec = CT_TO_SECS(current->times.tms_utime +
+ current->times.tms_cutime);
+ r.ru_utime.tv_usec = CT_TO_USECS(current->times.tms_utime +
+ current->times.tms_cutime);
+ r.ru_stime.tv_sec = CT_TO_SECS(current->times.tms_stime +
+ current->times.tms_cstime);
+ r.ru_stime.tv_usec = CT_TO_USECS(current->times.tms_stime +
+ current->times.tms_cstime);
+ r.ru_minflt = current->min_flt + current->cmin_flt;
+ r.ru_majflt = current->maj_flt + current->cmaj_flt;
+ r.ru_nswap = current->nswap + current->cnswap;
+ break;
+ }
+
+ return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
+}
+
+asmlinkage int osf_wait4(pid_t pid, int *ustatus, int options,
+ struct rusage32 *ur)
+{
+ if (!ur) {
+ return sys_wait4(pid, ustatus, options, NULL);
+ } else {
+ struct rusage r;
+ int ret, status;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_wait4(pid, &status, options, &r);
+ set_fs (old_fs);
+
+ if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur)))
+ return -EFAULT;
+ __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec);
+ __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec);
+ __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec);
+ __put_user(r.ru_stime.tv_usec, &ur->ru_stime.tv_usec);
+ __put_user(r.ru_maxrss, &ur->ru_maxrss);
+ __put_user(r.ru_ixrss, &ur->ru_ixrss);
+ __put_user(r.ru_idrss, &ur->ru_idrss);
+ __put_user(r.ru_isrss, &ur->ru_isrss);
+ __put_user(r.ru_minflt, &ur->ru_minflt);
+ __put_user(r.ru_majflt, &ur->ru_majflt);
+ __put_user(r.ru_nswap, &ur->ru_nswap);
+ __put_user(r.ru_inblock, &ur->ru_inblock);
+ __put_user(r.ru_oublock, &ur->ru_oublock);
+ __put_user(r.ru_msgsnd, &ur->ru_msgsnd);
+ __put_user(r.ru_msgrcv, &ur->ru_msgrcv);
+ __put_user(r.ru_nsignals, &ur->ru_nsignals);
+ __put_user(r.ru_nvcsw, &ur->ru_nvcsw);
+ if (__put_user(r.ru_nivcsw, &ur->ru_nivcsw))
+ return -EFAULT;
+
+ if (ustatus && put_user(status, ustatus))
+ return -EFAULT;
+ return ret;
+ }
+}
+
+/*
+ * I don't know what the parameters are: the first one
+ * seems to be a timeval pointer, and I suspect the second
+ * one is the time remaining.. Ho humm.. No documentation.
+ */
+asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain)
+{
+ struct timeval tmp;
+ unsigned long ticks;
+
+ if (get_tv32(&tmp, sleep))
+ goto fault;
+
+ ticks = tmp.tv_usec;
+ ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
+ ticks += tmp.tv_sec * HZ;
+ current->timeout = ticks + jiffies;
+ current->state = TASK_INTERRUPTIBLE;
+
+ schedule();
+
+ if (remain) {
+ ticks = jiffies;
+ if (ticks < current->timeout)
+ ticks = current->timeout - ticks;
+ else
+ ticks = 0;
+ current->timeout = 0;
+ tmp.tv_sec = ticks / HZ;
+ tmp.tv_usec = ticks % HZ;
+ if (put_tv32(remain, &tmp))
+ goto fault;
+ }
+
+ return 0;
+fault:
+ return -EFAULT;
+}
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 84cde1b4f..38cb5e05d 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -574,7 +574,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
(return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
ret = -EIO;
- if ((unsigned long) data > NSIG)
+ if ((unsigned long) data > _NSIG)
goto out;
if (request == PTRACE_SYSCALL)
child->flags |= PF_TRACESYS;
@@ -606,7 +606,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
case PTRACE_SINGLESTEP: { /* execute single instruction. */
ret = -EIO;
- if ((unsigned long) data > NSIG)
+ if ((unsigned long) data > _NSIG)
goto out;
child->debugreg[4] = -1; /* mark single-stepping */
child->flags &= ~PF_TRACESYS;
@@ -619,7 +619,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
case PTRACE_DETACH: { /* detach a process that was attached. */
ret = -EIO;
- if ((unsigned long) data > NSIG)
+ if ((unsigned long) data > _NSIG)
goto out;
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
@@ -627,7 +627,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
SET_LINKS(child);
- /* make sure single-step breakpoint is gone. */
+ /* make sure single-step breakpoint is gone. */
ptrace_cancel_bpt(child);
ret = 0;
goto out;
@@ -644,22 +644,20 @@ out:
asmlinkage void syscall_trace(void)
{
- lock_kernel();
if ((current->flags & (PF_PTRACED|PF_TRACESYS))
!= (PF_PTRACED|PF_TRACESYS))
- goto out;
+ return;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
/*
- * this isn't the same as continuing with a signal, but it will do
+ * This isn't the same as continuing with a signal, but it will do
* for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl
*/
- if (current->exit_code)
- current->signal |= (1 << (current->exit_code - 1));
- current->exit_code = 0;
-out:
- unlock_kernel();
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
}
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 9f71e6146..1d4e8931d 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -2,6 +2,8 @@
* linux/arch/alpha/kernel/signal.c
*
* Copyright (C) 1995 Linus Torvalds
+ *
+ * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson
*/
#include <linux/sched.h>
@@ -14,21 +16,27 @@
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+
+#define DEBUG_SIG 0
-#define _S(nr) (1<<((nr)-1))
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int sys_wait4(int, int *, int, struct rusage *);
asmlinkage void ret_from_sys_call(void);
-asmlinkage int do_signal(unsigned long, struct pt_regs *, struct switch_stack *,
- unsigned long, unsigned long);
+asmlinkage int do_signal(sigset_t *, struct pt_regs *,
+ struct switch_stack *, unsigned long, unsigned long);
extern int ptrace_set_bpt (struct task_struct *child);
extern int ptrace_cancel_bpt (struct task_struct *child);
+
/*
* The OSF/1 sigprocmask calling sequence is different from the
* C sigprocmask() sequence..
@@ -44,51 +52,153 @@ extern int ptrace_cancel_bpt (struct task_struct *child);
* Note that we don't need to acquire the kernel lock for SMP
* operation, as all of this is local to this thread.
*/
-asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask,
- long a2, long a3, long a4, long a5, struct pt_regs regs)
+asmlinkage unsigned long
+osf_sigprocmask(int how, unsigned long newmask, long a2, long a3,
+ long a4, long a5, struct pt_regs regs)
{
- unsigned long ok, oldmask;
- struct task_struct * tsk;
-
- ok = how-1; /* 0 .. 2 */
- tsk = current;
- ok = ok <= 2;
- oldmask = -EINVAL;
- if (ok) {
- long sign; /* -1 .. 1 */
+ unsigned long oldmask = -EINVAL;
+
+ if ((unsigned long)how-1 <= 2) {
+ long sign = how-2; /* -1 .. 1 */
unsigned long block, unblock;
- oldmask = tsk->blocked;
newmask &= _BLOCKABLE;
- sign = how-2;
+ spin_lock_irq(&current->sigmask_lock);
+ oldmask = current->blocked.sig[0];
+
unblock = oldmask & ~newmask;
block = oldmask | newmask;
if (!sign)
block = unblock;
- regs.r0 = 0; /* special no error return */
if (sign <= 0)
newmask = block;
- tsk->blocked = newmask;
+ if (_NSIG_WORDS > 1 && sign > 0)
+ sigemptyset(&current->blocked);
+ current->blocked.sig[0] = newmask;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ (&regs)->r0 = 0; /* special no error return */
}
return oldmask;
}
+asmlinkage int
+osf_sigaction(int sig, const struct osf_sigaction *act,
+ struct osf_sigaction *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags))
+ return -EFAULT;
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ new_ka.ka_restorer = NULL;
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+asmlinkage int
+sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
+ void *restorer, size_t sigsetsize)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (act) {
+ new_ka.ka_restorer = restorer;
+ if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
+ return -EFAULT;
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+asmlinkage int
+osf_sigpending(old_sigset_t *set)
+{
+ sigset_t pending;
+
+ spin_lock_irq(&current->sigmask_lock);
+ sigandsets(&pending, &current->blocked, &current->signal);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ return copy_to_user(set, &pending, sizeof(*set));
+}
+
/*
- * atomically swap in the new signal mask, and wait for a signal.
+ * Atomically swap in the new signal mask, and wait for a signal.
*/
-asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw)
+asmlinkage int
+do_sigsuspend(old_sigset_t mask, struct pt_regs *reg, struct switch_stack *sw)
+{
+ sigset_t oldset;
+
+ mask &= _BLOCKABLE;
+ spin_lock_irq(&current->sigmask_lock);
+ oldset = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(&oldset, reg, sw, 0, 0))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize,
+ struct pt_regs *reg, struct switch_stack *sw)
{
- unsigned long oldmask;
+ sigset_t oldset, set;
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+ if (copy_from_user(&set, uset, sizeof(set)))
+ return -EFAULT;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
- oldmask = current->blocked;
- current->blocked = mask & _BLOCKABLE;
+ oldset = current->blocked;
+ current->blocked = set;
+ recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(oldmask, regs, sw, 0, 0))
+ if (do_signal(&oldset, reg, sw, 0, 0))
return -EINTR;
}
}
@@ -96,26 +206,35 @@ asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct s
/*
* Do a signal return; undo the signal stack.
*/
-asmlinkage void do_sigreturn(struct sigcontext * sc,
- struct pt_regs * regs, struct switch_stack * sw)
+
+struct sigframe
{
- unsigned long mask, ps, usp;
- int i;
+ struct sigcontext sc;
+ unsigned long extramask[_NSIG_WORDS-1];
+ unsigned int retcode[3];
+};
- /* verify that it's a good sigcontext before using it */
- if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
- goto give_sigsegv;
- if (__get_user(ps, &sc->sc_ps) || ps != 8)
- goto give_sigsegv;
- if (__get_user(mask, &sc->sc_mask) || (mask & ~_BLOCKABLE))
- goto give_sigsegv;
+struct rt_sigframe
+{
+ struct siginfo info;
+ struct ucontext uc;
+ unsigned int retcode[3];
+};
+
+#define INSN_MOV_R30_R16 0x47fe0410
+#define INSN_LDI_R0 0x201f0000
+#define INSN_CALLSYS 0x00000083
+
+
+static void
+restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+ struct switch_stack *sw)
+{
+ unsigned long usp;
+ int i;
- /* ok, looks fine, start restoring */
- __get_user(usp, sc->sc_regs+30);
- wrusp(usp);
__get_user(regs->pc, &sc->sc_pc);
sw->r26 = (unsigned long) ret_from_sys_call;
- current->blocked = mask;
__get_user(regs->r0, sc->sc_regs+0);
__get_user(regs->r1, sc->sc_regs+1);
@@ -147,47 +266,98 @@ asmlinkage void do_sigreturn(struct sigcontext * sc,
__get_user(regs->r27, sc->sc_regs+27);
__get_user(regs->r28, sc->sc_regs+28);
__get_user(regs->gp, sc->sc_regs+29);
+ __get_user(usp, sc->sc_regs+30);
+ wrusp(usp);
+
for (i = 0; i < 31; i++)
__get_user(sw->fp[i], sc->sc_fpregs+i);
+ __get_user(sw->fp[31], &sc->sc_fpcr);
+}
- /* send SIGTRAP if we're single-stepping: */
- lock_kernel();
+asmlinkage void
+do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
+ struct switch_stack *sw)
+{
+ unsigned long ps;
+ sigset_t set;
+
+ /* Verify that it's a good sigcontext before using it */
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto give_sigsegv;
+ if (__get_user(ps, &frame->sc.sc_ps) || ps != 8)
+ goto give_sigsegv;
+ if (__get_user(set.sig[0], &frame->sc.sc_mask)
+ || (_NSIG_WORDS > 1
+ && __copy_from_user(&set.sig[1], &frame->extramask,
+ sizeof(frame->extramask))))
+ goto give_sigsegv;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ restore_sigcontext(&frame->sc, regs, sw);
+
+ /* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current))
send_sig(SIGTRAP, current, 1);
- unlock_kernel();
return;
give_sigsegv:
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
}
-/*
- * Set up a signal frame...
- */
-static void setup_frame(struct sigaction * sa,
- struct pt_regs * regs,
- struct switch_stack * sw, int signr,
- unsigned long oldmask)
+asmlinkage void
+do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
+ struct switch_stack *sw)
{
- int i;
- unsigned long oldsp;
- struct sigcontext * sc;
+ unsigned long ps;
+ sigset_t set;
- oldsp = rdusp();
- sc = ((struct sigcontext *) oldsp) - 1;
+ /* Verify that it's a good sigcontext before using it */
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto give_sigsegv;
+ if (__get_user(ps, &frame->uc.uc_mcontext.sc_ps) || ps != 8)
+ goto give_sigsegv;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto give_sigsegv;
- /* check here if we would need to switch stacks.. */
- if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
- do_exit(SIGSEGV);
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
- wrusp((unsigned long) sc);
+ restore_sigcontext(&frame->uc.uc_mcontext, regs, sw);
- __put_user(oldmask, &sc->sc_mask);
- __put_user(8, &sc->sc_ps);
+ /* Send SIGTRAP if we're single-stepping: */
+ if (ptrace_cancel_bpt (current))
+ send_sig(SIGTRAP, current, 1);
+ return;
+
+give_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+
+/*
+ * Set up a signal frame.
+ */
+
+static void
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+ struct switch_stack *sw, unsigned long mask, unsigned long sp)
+{
+ long i;
+
+ __put_user(0, &sc->sc_onstack);
+ __put_user(mask, &sc->sc_mask);
__put_user(regs->pc, &sc->sc_pc);
- __put_user(oldsp, sc->sc_regs+30);
+ __put_user(8, &sc->sc_ps);
__put_user(regs->r0 , sc->sc_regs+0);
__put_user(regs->r1 , sc->sc_regs+1);
@@ -219,63 +389,167 @@ static void setup_frame(struct sigaction * sa,
__put_user(regs->r27, sc->sc_regs+27);
__put_user(regs->r28, sc->sc_regs+28);
__put_user(regs->gp , sc->sc_regs+29);
+ __put_user(sp, sc->sc_regs+30);
+ __put_user(0, sc->sc_regs+31);
+
for (i = 0; i < 31; i++)
__put_user(sw->fp[i], sc->sc_fpregs+i);
+ __put_user(0, sc->sc_fpregs+31);
+ __put_user(sw->fp[31], &sc->sc_fpcr);
+
__put_user(regs->trap_a0, &sc->sc_traparg_a0);
__put_user(regs->trap_a1, &sc->sc_traparg_a1);
__put_user(regs->trap_a2, &sc->sc_traparg_a2);
+}
+
+static void
+setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
+ struct pt_regs *regs, struct switch_stack * sw)
+{
+ unsigned long oldsp;
+ struct sigframe *frame;
+
+ oldsp = rdusp();
+ frame = (struct sigframe *)((oldsp - sizeof(*frame)) & -32);
+
+ /* XXX: Check here if we would need to switch stacks.. */
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
+ if (_NSIG_WORDS > 1) {
+ __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->ka_restorer) {
+ regs->r26 = (unsigned long) ka->ka_restorer;
+ } else {
+ __put_user(INSN_MOV_R30_R16, frame->retcode+0);
+ __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
+ __put_user(INSN_CALLSYS, frame->retcode+2);
+ imb();
+ regs->r26 = (unsigned long) frame->retcode;
+ }
+
+ /* "Return" to the handler */
+ regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->r16 = sig; /* a0: signal number */
+ regs->r17 = 0; /* a1: exception code */
+ regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */
+ wrusp((unsigned long) frame);
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->pc, regs->r26);
+#endif
+
+ return;
+
+give_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+static void
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
+{
+ unsigned long oldsp;
+ struct rt_sigframe *frame;
+
+ oldsp = rdusp();
+ frame = (struct rt_sigframe *)((oldsp - sizeof(*frame)) & -32);
+
+ /* XXX: Check here if we would need to switch stacks.. */
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ __copy_to_user(&frame->info, info, sizeof(siginfo_t));
+
+ /* Zero all bits of the ucontext besides the sigcontext. */
+ __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+ /* Copy in the bits we actually use. */
+ __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
+ setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp);
+ __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->ka_restorer) {
+ regs->r26 = (unsigned long) ka->ka_restorer;
+ } else {
+ __put_user(INSN_MOV_R30_R16, frame->retcode+0);
+ __put_user(INSN_LDI_R0+__NR_rt_sigreturn, frame->retcode+1);
+ __put_user(INSN_CALLSYS, frame->retcode+2);
+ imb();
+ regs->r26 = (unsigned long) frame->retcode;
+ }
- /*
- * The following is:
- *
- * bis $30,$30,$16
- * addq $31,0x67,$0
- * call_pal callsys
- *
- * ie, "sigreturn(stack-pointer)"
- */
- __put_user(0x43ecf40047de0410, sc->sc_retcode+0);
- __put_user(0x0000000000000083, sc->sc_retcode+1);
- imb();
-
- /* "return" to the handler */
- regs->r27 = regs->pc = (unsigned long) sa->sa_handler;
- regs->r26 = (unsigned long) sc->sc_retcode;
- regs->r16 = signr; /* a0: signal number */
- regs->r17 = 0; /* a1: exception code; see gentrap.h */
- regs->r18 = (unsigned long) sc; /* a2: sigcontext pointer */
+ /* "Return" to the handler */
+ regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->r16 = sig; /* a0: signal number */
+ regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
+ regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */
+ wrusp((unsigned long) frame);
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->pc, regs->r26);
+#endif
+
+ return;
+
+give_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
+
/*
- * OK, we're invoking a handler
+ * OK, we're invoking a handler.
*/
-static inline void handle_signal(unsigned long signr, struct sigaction *sa,
- unsigned long oldmask, struct pt_regs * regs, struct switch_stack *sw)
+static inline void
+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw)
{
- setup_frame(sa,regs,sw,signr,oldmask);
-
- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- if (!(sa->sa_flags & SA_NOMASK))
- current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(sig, ka, info, oldset, regs, sw);
+ else
+ setup_frame(sig, ka, oldset, regs, sw);
+
+ if (ka->sa.sa_flags & SA_RESETHAND)
+ ka->sa.sa_handler = SIG_DFL;
+
+ if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ spin_lock_irq(&current->sigmask_lock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ }
}
-static inline void syscall_restart(unsigned long r0, unsigned long r19,
- struct pt_regs * regs, struct sigaction * sa)
+static inline void
+syscall_restart(unsigned long r0, unsigned long r19,
+ struct pt_regs *regs, struct k_sigaction *ka)
{
switch (regs->r0) {
+ case ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
case ERESTARTNOHAND:
- no_system_call_restart:
regs->r0 = EINTR;
break;
- case ERESTARTSYS:
- if (!(sa->sa_flags & SA_RESTART))
- goto no_system_call_restart;
+ }
/* fallthrough */
- case ERESTARTNOINTR:
- regs->r0 = r0; /* reset v0 and a3 and replay syscall */
- regs->r19 = r19;
- regs->pc -= 4;
+ case ERESTARTNOINTR:
+ regs->r0 = r0; /* reset v0 and a3 and replay syscall */
+ regs->r19 = r19;
+ regs->pc -= 4;
+ break;
}
}
@@ -293,53 +567,77 @@ static inline void syscall_restart(unsigned long r0, unsigned long r19,
* restart. "r0" is also used as an indicator whether we can restart at
* all (if we get here from anything but a syscall return, it will be 0)
*/
-asmlinkage int do_signal(unsigned long oldmask,
- struct pt_regs * regs,
- struct switch_stack * sw,
- unsigned long r0, unsigned long r19)
+asmlinkage int
+do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw,
+ unsigned long r0, unsigned long r19)
{
- unsigned long mask;
- unsigned long signr, single_stepping;
- struct sigaction * sa;
- int ret;
+ unsigned long single_stepping = ptrace_cancel_bpt(current);
+
+ if (!oldset)
+ oldset = &current->blocked;
+
+ while (1) {
+ unsigned long signr;
+ struct k_sigaction *ka;
+ siginfo_t info;
+
+ spin_lock_irq(&current->sigmask_lock);
+ signr = dequeue_signal(&current->blocked, &info);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (!signr)
+ break;
- lock_kernel();
- mask = ~current->blocked;
- single_stepping = ptrace_cancel_bpt(current);
-
- while ((signr = current->signal & mask) != 0) {
- signr = ffz(~signr);
- clear_bit(signr, &current->signal);
- sa = current->sig->action + signr;
- signr++;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ /* Let the debugger run. */
current->exit_code = signr;
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
single_stepping |= ptrace_cancel_bpt(current);
+
+ /* We're back. Did the debugger cancel the sig? */
if (!(signr = current->exit_code))
continue;
current->exit_code = 0;
+
+ /* The debugger continued. Ignore SIGSTOP. */
if (signr == SIGSTOP)
continue;
- if (_S(signr) & current->blocked) {
- current->signal |= _S(signr);
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(&current->blocked, signr)) {
+ send_sig_info(signr, &info, current);
continue;
}
- sa = current->sig->action + signr - 1;
}
- if (sa->sa_handler == SIG_IGN) {
+
+ ka = &current->sig->action[signr-1];
+ if (ka->sa.sa_handler == SIG_IGN) {
if (signr != SIGCHLD)
continue;
- /* check for SIGCHLD: it's special */
+ /* Check for SIGCHLD: it's special. */
while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
/* nothing */;
continue;
}
- if (sa->sa_handler == SIG_DFL) {
+
+ if (ka->sa.sa_handler == SIG_DFL) {
+ int exit_code = signr & 0x7f;
+
+ /* Init gets no signals it doesn't want. */
if (current->pid == 1)
continue;
+
switch (signr) {
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
@@ -347,13 +645,13 @@ asmlinkage int do_signal(unsigned long oldmask,
case SIGTSTP: case SIGTTIN: case SIGTTOU:
if (is_orphaned_pgrp(current->pgrp))
continue;
+ /* FALLTHRU */
+
case SIGSTOP:
- if (current->flags & PF_PTRACED)
- continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
+ if (!(current->p_pptr->sig->action[SIGCHLD-1]
+ .sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
single_stepping |= ptrace_cancel_bpt(current);
@@ -361,26 +659,32 @@ asmlinkage int do_signal(unsigned long oldmask,
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV:
- if (current->binfmt && current->binfmt->core_dump) {
- if (current->binfmt->core_dump(signr, regs))
- signr |= 0x80;
- }
- /* fall through */
+ lock_kernel();
+ if (current->binfmt
+ && current->binfmt->core_dump
+ && current->binfmt->core_dump(signr, regs))
+ exit_code |= 0x80;
+ unlock_kernel();
+ /* FALLTHRU */
+
default:
- current->signal |= _S(signr & 0x7f);
+ lock_kernel();
+ sigaddset(&current->signal, signr);
current->flags |= PF_SIGNALED;
- do_exit(signr);
+ do_exit(exit_code);
+ /* NOTREACHED */
}
+ continue;
}
- if (r0)
- syscall_restart(r0, r19, regs, sa);
- handle_signal(signr, sa, oldmask, regs, sw);
- if (single_stepping) {
- ptrace_set_bpt(current); /* re-set breakpoint */
- }
- ret = 1;
- goto out;
+
+ /* Whee! Actually deliver the signal. */
+ if (r0) syscall_restart(r0, r19, regs, ka);
+ handle_signal(signr, ka, &info, oldset, regs, sw);
+ if (single_stepping)
+ ptrace_set_bpt(current); /* re-set bpt */
+ return 1;
}
+
if (r0 &&
(regs->r0 == ERESTARTNOHAND ||
regs->r0 == ERESTARTSYS ||
@@ -389,11 +693,8 @@ asmlinkage int do_signal(unsigned long oldmask,
regs->r19 = r19;
regs->pc -= 4;
}
- if (single_stepping) {
+ if (single_stepping)
ptrace_set_bpt(current); /* re-set breakpoint */
- }
- ret = 0;
-out:
- unlock_kernel();
- return ret;
+
+ return 0;
}
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 2b0870c3b..9d8b56dc3 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -17,17 +17,18 @@
* (round system clock to nearest tick instead of truncating)
* fixed algorithm in time_init for getting time from CMOS clock
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/hwrpb.h>
-#include <asm/delay.h>
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
@@ -52,16 +53,18 @@ static int set_rtc_mmss(unsigned long);
/* lump static variables together for more efficient access: */
static struct {
- __u32 last_time; /* cycle counter last time it got invoked */
- unsigned long scaled_ticks_per_cycle; /* ticks/cycle * 2^48 */
- long last_rtc_update; /* last time the cmos clock got updated */
+ /* cycle counter last time it got invoked */
+ __u32 last_time;
+ /* ticks/cycle * 2^48 */
+ unsigned long scaled_ticks_per_cycle;
+ /* last time the cmos clock got updated */
+ time_t last_rtc_update;
} state;
static inline __u32 rpcc(void)
{
__u32 result;
-
asm volatile ("rpcc %0" : "r="(result));
return result;
}
@@ -73,37 +76,46 @@ static inline __u32 rpcc(void)
*/
void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
{
- __u32 delta, now;
- int i, nticks;
+ const unsigned long half = 1UL << (FIX_SHIFT - 1);
+ const unsigned long mask = (1UL << (FIX_SHIFT + 1)) - 1;
+ unsigned long delta;
+ __u32 now;
+ long nticks;
+ /*
+ * Estimate how many ticks have passed since the last update.
+ * Round the result, .5 to even. When we loose ticks due to
+ * say using IDE, the clock has been seen to run up to 15% slow
+ * if we truncate.
+ */
now = rpcc();
delta = now - state.last_time;
state.last_time = now;
- if(hwrpb->cycle_freq) {
- nticks = (delta * state.scaled_ticks_per_cycle) >> (FIX_SHIFT-1);
- nticks = (nticks+1) >> 1;
- }
- else nticks=1; /* No way to estimate lost ticks if we don't know
- the cycle frequency. */
- for (i = 0; i < nticks; ++i) {
+ delta = delta * state.scaled_ticks_per_cycle;
+ if ((delta & mask) != half)
+ delta += half;
+ nticks = delta >> FIX_SHIFT;
+
+ do {
do_timer(regs);
- }
+ } while (--nticks > 0);
/*
* If we have an externally synchronized Linux clock, then update
* CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
* called as close as possible to 500 ms before the new second starts.
*/
- if (time_state != TIME_BAD && xtime.tv_sec > state.last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
- if (set_rtc_mmss(xtime.tv_sec) == 0)
- state.last_rtc_update = xtime.tv_sec;
- else
- state.last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ if (time_state != TIME_BAD
+ && xtime.tv_sec > state.last_rtc_update + 660
+ && xtime.tv_usec >= 500000 - (tick >> 1)
+ && xtime.tv_usec <= 500000 + (tick >> 1)) {
+ int tmp = set_rtc_mmss(xtime.tv_sec);
+ state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0);
+ }
}
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+/*
+ * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
@@ -140,25 +152,40 @@ void time_init(void)
unsigned char save_control;
#endif
void (*irq_handler)(int, void *, struct pt_regs *);
- unsigned int year, mon, day, hour, min, sec;
+ unsigned int year, mon, day, hour, min, sec, cc1, cc2;
- /* The Linux interpretation of the CMOS clock register contents:
+ /*
+ * The Linux interpretation of the CMOS clock register contents:
* When the Update-In-Progress (UIP) flag goes from 1 to 0, the
* RTC registers show the second which has precisely just started.
* Let's hope other operating systems interpret the RTC the same way.
*/
- /* read RTC exactly on falling edge of update flag */
- /* Wait for rise.... (may take up to 1 second) */
-
- do {} while(!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
-
-/* Jay Estabook <jestabro@amt.tay1.dec.com>:
- * Wait for the Update Done Interrupt bit (0x10) in reg C (12) to be set,
- * which (hopefully) indicates that the update is really done.
- */
-
- do {} while(!CMOS_READ(RTC_REG_C) & RTC_UIP);
-
+ do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
+ do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+
+ /* Read cycle counter exactly on falling edge of update flag */
+ cc1 = rpcc();
+
+ /* If our cycle frequency isn't valid, go another round and give
+ a guess at what it should be. */
+ if (hwrpb->cycle_freq == 0) {
+ printk("HWPRB cycle frequency bogus. Estimating... ");
+
+ do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
+ do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+ cc2 = rpcc();
+ hwrpb->cycle_freq = cc2 - cc1;
+ cc1 = cc2;
+
+ printk("%lu Hz\n", hwrpb->cycle_freq);
+ }
+
+ /* From John Bowman <bowman@math.ualberta.ca>: allow the values
+ to settle, as the Update-In-Progress bit going low isn't good
+ enough on some hardware. 2ms is our guess; we havn't found
+ bogomips yet, but this is close on a 500Mhz box. */
+ __delay(1000000);
+
sec = CMOS_READ(RTC_SECONDS);
min = CMOS_READ(RTC_MINUTES);
hour = CMOS_READ(RTC_HOURS);
@@ -167,14 +194,14 @@ void time_init(void)
year = CMOS_READ(RTC_YEAR);
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- {
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- }
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
#ifdef ALPHA_PRE_V1_2_SRM_CONSOLE
/*
* The meaning of life, the universe, and everything. Plus
@@ -192,9 +219,10 @@ void time_init(void)
extern void __you_loose (void);
__you_loose();
}
- state.last_time = rpcc();
- if(hwrpb->cycle_freq)
- state.scaled_ticks_per_cycle = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq;
+
+ state.last_time = cc1;
+ state.scaled_ticks_per_cycle
+ = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq;
state.last_rtc_update = 0;
#ifdef CONFIG_RTC
@@ -210,22 +238,52 @@ void time_init(void)
/* setup timer */
irq_handler = timer_interrupt;
if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL))
- panic("Could not allocate timer IRQ!");
+ panic("Could not allocate timer IRQ!");
}
/*
- * We could get better timer accuracy by using the alpha
- * time counters or something. Now this is limited to
- * the HZ clock frequency.
+ * Use the cycle counter to estimate an displacement from the last time
+ * tick. Unfortunately the Alpha designers made only the low 32-bits of
+ * the cycle counter active, so we overflow on 8.2 seconds on a 500MHz
+ * part. So we can't do the "find absolute time in terms of cycles" thing
+ * that the other ports do.
*/
void do_gettimeofday(struct timeval *tv)
{
- unsigned long flags;
+ unsigned long flags, now, delta_cycles, delta_usec;
+ unsigned long sec, usec;
- save_flags(flags);
- cli();
- *tv = xtime;
+ now = rpcc();
+ save_and_cli(flags);
+ sec = xtime.tv_sec;
+ usec = xtime.tv_usec;
+ delta_cycles = now - state.last_time;
restore_flags(flags);
+
+ /*
+ * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
+ * = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks)
+ * = cycles * (s_t_p_c) * 15625 / (2**42 * ticks)
+ *
+ * which, given a 600MHz cycle and a 1024Hz tick, has a
+ * dynamic range of about 1.7e17, which is less than the
+ * 1.8e19 in an unsigned long, so we are safe from overflow.
+ *
+ * Round, but with .5 up always, since .5 to even is harder
+ * with no clear gain.
+ */
+
+ delta_usec = delta_cycles * state.scaled_ticks_per_cycle * 15625;
+ delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6)) * HZ)) + 1) / 2;
+
+ usec += delta_usec;
+ if (usec >= 1000000) {
+ sec += 1;
+ usec -= 1000000;
+ }
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
}
void do_settimeofday(struct timeval *tv)
@@ -252,10 +310,12 @@ static int set_rtc_mmss(unsigned long nowtime)
int real_seconds, real_minutes, cmos_minutes;
unsigned char save_control, save_freq_select;
- save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ /* Tell the clock it's being set */
+ save_control = CMOS_READ(RTC_CONTROL);
CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
- save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ /* Stop and reset prescaler */
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
cmos_minutes = CMOS_READ(RTC_MINUTES);
@@ -270,8 +330,10 @@ static int set_rtc_mmss(unsigned long nowtime)
*/
real_seconds = nowtime % 60;
real_minutes = nowtime / 60;
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) {
+ /* correct for half hour time zone */
+ real_minutes += 30;
+ }
real_minutes %= 60;
if (abs(real_minutes - cmos_minutes) < 30) {
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 12bee3fbc..14a8e2010 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -12,6 +12,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/tty.h>
+#include <linux/delay.h>
#include <asm/gentrap.h>
#include <asm/uaccess.h>
@@ -20,45 +21,41 @@
#include <asm/smp_lock.h>
-void die_if_kernel(char * str, struct pt_regs * regs, long err,
- unsigned long *r9_15)
+static void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15)
{
- long i;
- unsigned long ra;
- unsigned int * pc;
- unsigned long * sp;
-
- if (regs->ps & 8)
- return;
- printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
- sp = (unsigned long *) (regs+1);
- __get_user(ra, (unsigned long *)sp);
- printk("pc = [<%016lx>] ps = %04lx\n", regs->pc, regs->ps);
- printk("rp = [<%016lx>] ra = [<%016lx>]\n", regs->r26, ra);
- printk("r0 = %016lx r1 = %016lx\n", regs->r0, regs->r1);
- printk("r2 = %016lx r3 = %016lx\n", regs->r2, regs->r3);
- printk("r4 = %016lx r5 = %016lx\n", regs->r4, regs->r5);
- printk("r6 = %016lx r7 = %016lx\n", regs->r6, regs->r7);
+ printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n",
+ regs->pc, regs->r26, regs->ps);
+ printk("r0 = %016lx r1 = %016lx r2 = %016lx\n",
+ regs->r0, regs->r1, regs->r2);
+ printk("r3 = %016lx r4 = %016lx r5 = %016lx\n",
+ regs->r3, regs->r4, regs->r5);
+ printk("r6 = %016lx r7 = %016lx r8 = %016lx\n",
+ regs->r6, regs->r7, regs->r8);
if (r9_15) {
- printk("r8 = %016lx r9 = %016lx\n", regs->r8, r9_15[9]);
- printk("r10= %016lx r11= %016lx\n", r9_15[10], r9_15[11]);
- printk("r12= %016lx r13= %016lx\n", r9_15[12], r9_15[13]);
- printk("r14= %016lx r15= %016lx\n", r9_15[14], r9_15[15]);
- } else {
- printk("r8 = %016lx\n", regs->r8);
+ printk("r9 = %016lx r10= %016lx r11= %016lx\n",
+ r9_15[9], r9_15[10], r9_15[11]);
+ printk("r12= %016lx r13= %016lx r14= %016lx\n",
+ r9_15[12], r9_15[13], r9_15[14]);
+ printk("r15= %016lx\n", r9_15[15]);
}
- printk("r16= %016lx r17= %016lx\n", regs->r16, regs->r17);
- printk("r18= %016lx r19= %016lx\n", regs->r18, regs->r19);
- printk("r20= %016lx r21= %016lx\n", regs->r20, regs->r21);
- printk("r22= %016lx r23= %016lx\n", regs->r22, regs->r23);
- printk("r24= %016lx r25= %016lx\n", regs->r24, regs->r25);
- printk("r27= %016lx r28= %016lx\n", regs->r27, regs->r28);
- printk("gp = %016lx sp = %p\n", regs->gp, sp);
+ printk("r16= %016lx r17= %016lx r18= %016lx\n",
+ regs->r16, regs->r17, regs->r18);
+ printk("r19= %016lx r20= %016lx r21= %016lx\n",
+ regs->r19, regs->r20, regs->r21);
+ printk("r22= %016lx r23= %016lx r24= %016lx\n",
+ regs->r22, regs->r23, regs->r24);
+ printk("r25= %016lx r27= %016lx r28= %016lx\n",
+ regs->r25, regs->r27, regs->r28);
+ printk("gp = %016lx sp = %p\n", regs->gp, regs+1);
+}
+
+static void dik_show_code(unsigned int *pc)
+{
+ long i;
printk("Code:");
- pc = (unsigned int *) regs->pc;
for (i = -3; i < 6; i++) {
unsigned int insn;
if (__get_user(insn, pc+i))
@@ -66,6 +63,11 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err,
printk("%c%08x%c",i?' ':'<',insn,i?' ':'>');
}
printk("\n");
+}
+
+static void dik_show_trace(unsigned long *sp)
+{
+ long i = 0;
printk("Trace:");
while (0x1ff8 & (unsigned long) sp) {
extern unsigned long _stext, _etext;
@@ -76,9 +78,30 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err,
if (tmp >= (unsigned long) &_etext)
continue;
printk(" [<%lx>]", tmp);
+ if (++i > 40) {
+ printk(" ...");
+ break;
+ }
}
printk("\n");
-
+}
+
+void die_if_kernel(char * str, struct pt_regs *regs, long err,
+ unsigned long *r9_15)
+{
+ if (regs->ps & 8)
+ return;
+ printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
+ dik_show_regs(regs, r9_15);
+ dik_show_code((unsigned int *)regs->pc);
+ dik_show_trace((unsigned long *)(regs+1));
+
+ if (current->tss.flags & (1UL << 63)) {
+ printk("die_if_kernel recursion detected.\n");
+ sti();
+ while (1);
+ }
+ current->tss.flags |= (1UL << 63);
do_exit(SIGSEGV);
}
@@ -397,8 +420,6 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
pc, va, opcode, reg);
do_exit(SIGSEGV);
- unlock_kernel();
- return;
got_exception:
/* Ok, we caught the exception, but we don't want it. Is there
@@ -416,13 +437,48 @@ got_exception:
return;
}
- /* Yikes! No one to forward the exception to. */
+ /*
+ * Yikes! No one to forward the exception to.
+ * Since the registers are in a weird format, dump them ourselves.
+ */
lock_kernel();
- printk("%s: unhandled unaligned exception at pc=%lx ra=%lx"
- " (bad address = %p)\n", current->comm,
- pc, una_reg(26), va);
+
+ printk("%s(%d): unhandled unaligned exception\n",
+ current->comm, current->pid);
+
+ printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n",
+ pc, una_reg(26), regs.ps);
+ printk("r0 = %016lx r1 = %016lx r2 = %016lx\n",
+ una_reg(0), una_reg(1), una_reg(2));
+ printk("r3 = %016lx r4 = %016lx r5 = %016lx\n",
+ una_reg(3), una_reg(4), una_reg(5));
+ printk("r6 = %016lx r7 = %016lx r8 = %016lx\n",
+ una_reg(6), una_reg(7), una_reg(8));
+ printk("r9 = %016lx r10= %016lx r11= %016lx\n",
+ una_reg(9), una_reg(10), una_reg(11));
+ printk("r12= %016lx r13= %016lx r14= %016lx\n",
+ una_reg(12), una_reg(13), una_reg(14));
+ printk("r15= %016lx\n", una_reg(15));
+ printk("r16= %016lx r17= %016lx r18= %016lx\n",
+ una_reg(16), una_reg(17), una_reg(18));
+ printk("r19= %016lx r20= %016lx r21= %016lx\n",
+ una_reg(19), una_reg(20), una_reg(21));
+ printk("r22= %016lx r23= %016lx r24= %016lx\n",
+ una_reg(22), una_reg(23), una_reg(24));
+ printk("r25= %016lx r27= %016lx r28= %016lx\n",
+ una_reg(25), una_reg(27), una_reg(28));
+ printk("gp = %016lx sp = %p\n", regs.gp, &regs+1);
+
+ dik_show_code((unsigned int *)pc);
+ dik_show_trace((unsigned long *)(&regs+1));
+
+ if (current->tss.flags & (1UL << 63)) {
+ printk("die_if_kernel recursion detected.\n");
+ sti();
+ while (1);
+ }
+ current->tss.flags |= (1UL << 63);
do_exit(SIGSEGV);
- unlock_kernel();
}
/*
@@ -800,26 +856,17 @@ give_sigbus:
}
/*
- * DEC means people to use the "retsys" instruction for return from
- * a system call, but they are clearly misguided about this. We use
- * "rti" in all cases, and fill in the stack with the return values.
- * That should make signal handling etc much cleaner.
- *
- * Even more horribly, DEC doesn't allow system calls from kernel mode.
- * "Security" features letting the user do something the kernel can't
- * are a thinko. DEC palcode is strange. The PAL-code designers probably
- * got terminally tainted by VMS at some point.
+ * Unimplemented system calls.
*/
-asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs regs)
+asmlinkage long alpha_ni_syscall(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
{
- lock_kernel();
/* Only report OSF system calls. */
if (regs.r0 != 112 && regs.r0 < 300)
printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
- unlock_kernel();
- return -1;
+ return -ENOSYS;
}
extern asmlinkage void entMM(void);