diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-16 05:34:03 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-16 05:34:03 +0000 |
commit | 967c65a99059fd459b956c1588ce0ba227912c4e (patch) | |
tree | 8224d013ff5d255420713d05610c7efebd204d2a /arch/alpha | |
parent | e20c1cc1656a66a2773bca4591a895cbc12696ff (diff) |
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'arch/alpha')
-rw-r--r-- | arch/alpha/config.in | 13 | ||||
-rw-r--r-- | arch/alpha/kernel/alpha_ksyms.c | 2 | ||||
-rw-r--r-- | arch/alpha/kernel/entry.S | 480 | ||||
-rw-r--r-- | arch/alpha/kernel/osf_sys.c | 412 | ||||
-rw-r--r-- | arch/alpha/kernel/ptrace.c | 22 | ||||
-rw-r--r-- | arch/alpha/kernel/signal.c | 599 | ||||
-rw-r--r-- | arch/alpha/kernel/time.c | 182 | ||||
-rw-r--r-- | arch/alpha/kernel/traps.c | 157 | ||||
-rw-r--r-- | arch/alpha/lib/Makefile | 3 | ||||
-rw-r--r-- | arch/alpha/lib/clear_user.S | 8 | ||||
-rw-r--r-- | arch/alpha/lib/csum_partial_copy.c | 2 |
11 files changed, 1464 insertions, 416 deletions
diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 9c74cc091..84402f1e0 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -134,6 +134,8 @@ if [ "$CONFIG_NET" = "y" ]; then endmenu fi +source drivers/net/hamradio/Config.in + mainmenu_option next_comment comment 'ISDN subsystem' @@ -152,6 +154,17 @@ if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then fi endmenu +# Conditionally compile in the Uniform CD-ROM driver +if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_CM206" = "y" -o "$CONFIG_CDU31A" = "y" ]; then + define_bool CONFIG_CDROM y +else + if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" -o "$CONFIG_SBPCD" = "m" -o "$CONFIG_MCD" = "m" -o "$CONFIG_CM206" = "m" -o "$CONFIG_CDU31A" = "m" ]; then + define_bool CONFIG_CDROM m + else + define_bool CONFIG_CDROM n + fi +fi + source fs/Config.in source fs/nls/Config.in 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; (®s)->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; (®s)->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(¤t->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(¤t->blocked); + current->blocked.sig[0] = newmask; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + (®s)->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(¤t->sigmask_lock); + sigandsets(&pending, ¤t->blocked, ¤t->signal); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + oldset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); - oldmask = current->blocked; - current->blocked = mask & _BLOCKABLE; + oldset = current->blocked; + current->blocked = set; + recalc_sigpending(current); spin_unlock_irq(¤t->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(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->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(¤t->sigmask_lock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); + spin_unlock_irq(¤t->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 = ¤t->blocked; + + while (1) { + unsigned long signr; + struct k_sigaction *ka; + siginfo_t info; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->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, ¤t->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(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if (sa->sa_handler == SIG_IGN) { + + ka = ¤t->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(¤t->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, ®s+1); + + dik_show_code((unsigned int *)pc); + dik_show_trace((unsigned long *)(®s+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); diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index a4e0fea9f..28dc3d451 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -19,9 +19,6 @@ endif lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) -memset.o: memset.S - $(CC) -c -o memset.o memset.S - __divqu.o: divide.S $(CC) -DDIV -c -o __divqu.o divide.S diff --git a/arch/alpha/lib/clear_user.S b/arch/alpha/lib/clear_user.S index db179adfd..65d7e2f28 100644 --- a/arch/alpha/lib/clear_user.S +++ b/arch/alpha/lib/clear_user.S @@ -37,8 +37,8 @@ .set noreorder .align 4 - .globl __clear_user - .ent __clear_user + .globl __do_clear_user + .ent __do_clear_user .frame $30, 0, $28 .prologue 0 @@ -79,7 +79,7 @@ $tail: EX( stq_u $5, 0($6) ) # e0 : ret $31, ($28), 1 # .. e1 : -__clear_user: +__do_clear_user: and $6, 7, $4 # e0 : find dest misalignment beq $0, $zerolength # .. e1 : addq $0, $4, $1 # e0 : bias counter @@ -110,4 +110,4 @@ $zerolength: $exception: ret $31, ($28), 1 # .. e1 : - .end __clear_user + .end __do_clear_user diff --git a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c index 475c84e7d..24a45e7aa 100644 --- a/arch/alpha/lib/csum_partial_copy.c +++ b/arch/alpha/lib/csum_partial_copy.c @@ -8,7 +8,7 @@ */ #include <linux/types.h> -#include <asm/string.h> +#include <linux/string.h> #include <asm/uaccess.h> |