summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r--arch/alpha/kernel/Makefile3
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c120
-rw-r--r--arch/alpha/kernel/bios32.c8
-rw-r--r--arch/alpha/kernel/entry.S144
-rw-r--r--arch/alpha/kernel/head.S6
-rw-r--r--arch/alpha/kernel/irq.c66
-rw-r--r--arch/alpha/kernel/ksyms.c112
-rw-r--r--arch/alpha/kernel/osf_sys.c329
-rw-r--r--arch/alpha/kernel/process.c56
-rw-r--r--arch/alpha/kernel/ptrace.c86
-rw-r--r--arch/alpha/kernel/setup.c13
-rw-r--r--arch/alpha/kernel/signal.c192
-rw-r--r--arch/alpha/kernel/time.c29
-rw-r--r--arch/alpha/kernel/traps.c455
14 files changed, 1092 insertions, 527 deletions
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index 4aa11ce78..260ac7bff 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -16,7 +16,8 @@ all: kernel.o head.o
O_TARGET := kernel.o
O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
- bios32.o ptrace.o time.o apecs.o lca.o cia.o ksyms.o
+ bios32.o ptrace.o time.o apecs.o lca.o cia.o
+OX_OBJS := alpha_ksyms.o
all: kernel.o head.o
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
new file mode 100644
index 000000000..be75f566f
--- /dev/null
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -0,0 +1,120 @@
+/*
+ * linux/arch/alpha/kernel/ksyms.c
+ *
+ * Export the alpha-specific functions that are needed for loadable
+ * modules.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#include <asm/io.h>
+#include <asm/hwrpb.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/checksum.h>
+#include <linux/interrupt.h>
+#include <asm/softirq.h>
+
+extern void bcopy (const char *src, char *dst, int len);
+extern struct hwrpb_struct *hwrpb;
+extern long __kernel_thread(unsigned long, int (*)(void *), void *);
+extern void dump_thread(struct pt_regs *, struct user *);
+extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+
+/* these are C runtime functions with special calling conventions: */
+extern void __divl (void);
+extern void __reml (void);
+extern void __divq (void);
+extern void __remq (void);
+extern void __divlu (void);
+extern void __remlu (void);
+extern void __divqu (void);
+extern void __remqu (void);
+
+EXPORT_SYMBOL(__alpha_bh_counter);
+EXPORT_SYMBOL(local_irq_count);
+
+/* platform dependent support */
+EXPORT_SYMBOL(_inb);
+EXPORT_SYMBOL(_inw);
+EXPORT_SYMBOL(_inl);
+EXPORT_SYMBOL(_outb);
+EXPORT_SYMBOL(_outw);
+EXPORT_SYMBOL(_outl);
+EXPORT_SYMBOL(_readb);
+EXPORT_SYMBOL(_readw);
+EXPORT_SYMBOL(_readl);
+EXPORT_SYMBOL(_writeb);
+EXPORT_SYMBOL(_writew);
+EXPORT_SYMBOL(_writel);
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(__memcpy);
+EXPORT_SYMBOL(__memset);
+EXPORT_SYMBOL(__constant_c_memset);
+
+EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(hwrpb);
+EXPORT_SYMBOL(wrusp);
+EXPORT_SYMBOL(__kernel_thread);
+EXPORT_SYMBOL(start_thread);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_tcpudp_magic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(ip_compute_csum);
+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(__strncpy_from_user);
+EXPORT_SYMBOL(__strlen_user);
+
+/*
+ * The following are special because they're not called
+ * explicitly (the C compiler or assembler generates them in
+ * response to division operations). Fortunately, their
+ * interface isn't gonna change any time soon now, so it's OK
+ * to leave it out of version control.
+ */
+# undef bcopy
+# undef memcpy
+# undef memset
+EXPORT_SYMBOL_NOVERS(__divl);
+EXPORT_SYMBOL_NOVERS(__divlu);
+EXPORT_SYMBOL_NOVERS(__divq);
+EXPORT_SYMBOL_NOVERS(__divqu);
+EXPORT_SYMBOL_NOVERS(__reml);
+EXPORT_SYMBOL_NOVERS(__remlu);
+EXPORT_SYMBOL_NOVERS(__remq);
+EXPORT_SYMBOL_NOVERS(__remqu);
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL_NOVERS(memset);
diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c
index 01751697f..16d7474d1 100644
--- a/arch/alpha/kernel/bios32.c
+++ b/arch/alpha/kernel/bios32.c
@@ -24,6 +24,9 @@
* within the United States, $35 abroad.
*/
#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#if 0
# define DBG_DEVS(args) printk args
@@ -48,7 +51,6 @@ asmlinkage int sys_pciconfig_write()
#else /* CONFIG_PCI */
-#include <linux/kernel.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/malloc.h>
@@ -1217,6 +1219,7 @@ asmlinkage int sys_pciconfig_read(
unsigned int uint;
long err = 0;
+ lock_kernel();
switch (len) {
case 1:
err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
@@ -1240,6 +1243,7 @@ asmlinkage int sys_pciconfig_read(
err = -EINVAL;
break;
}
+ unlock_kernel();
return err;
}
asmlinkage int sys_pciconfig_write(
@@ -1254,6 +1258,7 @@ asmlinkage int sys_pciconfig_write(
unsigned int uint;
long err = 0;
+ lock_kernel();
switch (len) {
case 1:
err = get_user(ubyte, buf);
@@ -1286,6 +1291,7 @@ asmlinkage int sys_pciconfig_write(
err = -EINVAL;
break;
}
+ unlock_kernel();
return err;
}
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 6f63fdb7e..ef582b80e 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -22,7 +22,7 @@
/*
* stack offsets
*/
-#define SP_OFF 160
+#define SP_OFF 184
#define SWITCH_STACK_SIZE 320
@@ -47,9 +47,11 @@
* regs 9-15 preserved by C code
* regs 16-18 saved by PAL-code
* regs 29-30 saved and set up by PAL-code
+ * JRP - Save regs 16-18 in a special area of the stack, so that
+ * the palcode-provided values are available to the signal handler.
*/
#define SAVE_ALL \
- subq $30,160,$30; \
+ subq $30,184,$30; \
stq $0,0($30); \
stq $1,8($30); \
stq $2,16($30); \
@@ -71,7 +73,10 @@
stq $26,128($30); \
stq $27,136($30); \
stq $28,144($30); \
- stq $2,152($30)
+ stq $2,152($30); \
+ stq $16,160($30); \
+ stq $17,168($30); \
+ stq $18,176($30)
#define RESTORE_ALL \
lda $19,hae; \
@@ -108,7 +113,7 @@
ldq $26,128($30); \
ldq $27,136($30); \
ldq $28,144($30); \
- addq $30,160,$30
+ addq $30,184,$30
.text
.set noat
@@ -121,19 +126,8 @@
.ent entInt
entInt:
SAVE_ALL
-/* start atomic operation with respect to software interrupts */
- lda $0,intr_count
- ldq $1,0($0)
- addq $1,1,$1
- stq $1,0($0)
-/* set up the arguments to the C interrupt handler */
- lda $27,do_entInt
- jsr $26,($27),do_entInt
-/* ok, return */
- lda $0,intr_count
- ldq $1,0($0)
- subq $1,1,$1
- stq $1,0($0)
+ ldq $8,current_set
+ jsr $26,do_entInt
br $31,ret_from_sys_call
.end entInt
@@ -153,6 +147,7 @@ entMM:
stq $15,48($30)
addq $30,56,$19
/* handle the fault */
+ ldq $8,current_set
jsr $26,do_page_fault
/* reload the registers after the exception code played. */
ldq $9,0($30)
@@ -172,6 +167,9 @@ entMM:
.ent entArith
entArith:
SAVE_ALL
+ ldq $8,current_set
+ /* How much of a win is this clockwise? We are, after all, messing
+ up the call/return prefetch stack. -- rth */
lda $27,do_entArith
lda $26,ret_from_sys_call
jsr $31,($27),do_entArith
@@ -182,6 +180,7 @@ entArith:
.ent entIF
entIF:
SAVE_ALL
+ ldq $8,current_set
lda $27,do_entIF
lda $26,ret_from_sys_call
jsr $31,($27),do_entIF
@@ -199,6 +198,8 @@ entIF:
.align 3
.ent kernel_clone
kernel_clone:
+ .frame $30, 0, $26
+ .prologue 0
subq $30,6*8,$30
stq $31,0($30)
stq $26,8($30)
@@ -208,8 +209,7 @@ kernel_clone:
stq $18,40($30)
bis $31,2,$0 /* Register v0: syscall nr for fork() */
SAVE_ALL
- lda $27,sys_clone
- jsr $26,($27),sys_clone
+ jsr $26,sys_clone
stq $0,0($30)
br $31,ret_from_sys_call
.end kernel_clone
@@ -221,26 +221,30 @@ kernel_clone:
.globl __kernel_thread
.ent __kernel_thread
__kernel_thread:
+ .frame $30, 4*8, $26
subq $30,4*8,$30
- stq $9,0($30)
- stq $10,8($30)
- stq $26,16($30)
+ stq $10,16($30)
+ stq $9,8($30)
+ stq $26,0($30)
+ .prologue 0
bis $17,$17,$9 /* save fn */
bis $18,$18,$10 /* save arg */
bsr $26,kernel_clone
bne $20,1f /* $20 is non-zero in child */
- ldq $9,0($30)
- ldq $10,8($30)
- ldq $26,16($30)
+ ldq $26,0($30)
+ ldq $9,8($30)
+ ldq $10,16($30)
addq $30,4*8,$30
ret $31,($26),1
/* this is in child: look out as we don't have any stack here.. */
1: bis $9,$9,$27 /* get fn */
+ br $29,2f
+2: ldgp $29,0($29)
bis $10,$10,$16 /* get arg */
+ ldq $8,current_set
jsr $26,($27)
bis $0,$0,$16
- lda $27,sys_exit
- jsr $26,($27),sys_exit
+ jsr $26,sys_exit
call_pal PAL_halt
.end __kernel_thread
@@ -378,8 +382,8 @@ entUna:
stq $29,232($30)
stq $30,240($30)
stq $31,248($30)
- lda $27,do_entUna
- jsr $26,($27),do_entUna
+ ldq $8,current_set
+ jsr $26,do_entUna
ldq $0,0($30)
ldq $1,8($30)
ldq $2,16($30)
@@ -427,9 +431,9 @@ entUnaUser:
stq $13,32($30)
stq $14,40($30)
stq $15,48($30)
- lda $27,do_entUnaUser
bis $31,$30,$19
- jsr $26,($27),do_entUnaUser
+ ldq $8,current_set
+ jsr $26,do_entUnaUser
ldq $9,0($30)
ldq $10,8($30)
ldq $11,16($30)
@@ -453,8 +457,7 @@ sys_fork:
bis $31,SIGCHLD,$16
bis $31,$31,$17
bis $30,$30,$18
- lda $27,alpha_clone
- jsr $26,($27),alpha_clone
+ jsr $26,alpha_clone
bsr $1,undo_switch_stack
ret $31,($26),1
.end sys_fork
@@ -466,8 +469,7 @@ sys_clone:
bsr $1,do_switch_stack
/* arg1 and arg2 come from the user */
bis $30,$30,$18
- lda $27,alpha_clone
- jsr $26,($27),alpha_clone
+ jsr $26,alpha_clone
bsr $1,undo_switch_stack
ret $31,($26),1
.end sys_clone
@@ -495,14 +497,13 @@ alpha_switch_to:
.ent entSys
entSys:
SAVE_ALL
- lda $1,current_set
+ ldq $8,current_set
lda $4,NR_SYSCALLS($31)
stq $16,SP_OFF+24($30)
lda $5,sys_call_table
- ldq $2,0($1)
lda $27,do_entSys
cmpult $0,$4,$4
- ldq $3,TASK_FLAGS($2)
+ ldq $3,TASK_FLAGS($8)
stq $17,SP_OFF+32($30)
s8addq $0,$5,$5
and $3,PF_PTRACED,$3
@@ -519,14 +520,9 @@ entSys:
ret_from_sys_call:
cmovne $26,0,$19 /* $19 = 0 => non-restartable */
/* check bottom half interrupts */
- lda $0,intr_count
- ldq $1,0($0)
bne $1,ret_from_handle_bh
- lda $2,bh_active
- ldq $3,0($2)
- lda $2,bh_mask
- ldq $4,0($2)
- addq $1,1,$1
+ ldq $3,bh_active
+ ldq $4,bh_mask
and $3,$4,$2
bne $2,handle_bottom_half
ret_from_handle_bh:
@@ -535,15 +531,13 @@ ret_from_handle_bh:
beq $0,restore_all
ret_from_reschedule:
lda $0,need_resched
- lda $1,current_set
ldl $2,0($0)
lda $4,init_task
- ldq $3,0($1)
bne $2,reschedule
- subq $4,$3,$4
+ xor $4,$8,$4
beq $4,restore_all
- ldq $4,TASK_SIGNAL($3)
- ldq $16,TASK_BLOCKED($3)
+ ldq $4,TASK_SIGNAL($8)
+ ldq $16,TASK_BLOCKED($8)
bic $4,$16,$4
bne $4,signal_return
restore_all:
@@ -556,8 +550,7 @@ restore_all:
strace:
/* set up signal stack, call syscall_trace */
bsr $1,do_switch_stack
- lda $27,syscall_trace
- jsr $26,($27),syscall_trace
+ jsr $26,syscall_trace
bsr $1,undo_switch_stack
/* get the system call number and the arguments back.. */
@@ -586,8 +579,7 @@ strace_success:
stq $0,0($30) /* save return value */
bsr $1,do_switch_stack
- lda $27,syscall_trace
- jsr $26,($27),syscall_trace
+ jsr $26,syscall_trace
bsr $1,undo_switch_stack
br $31,ret_from_sys_call
@@ -605,8 +597,7 @@ strace_error:
bsr $1,do_switch_stack
bis $19,$19,$9 /* save old syscall number */
bis $20,$20,$10 /* save old a3 */
- lda $27,syscall_trace
- jsr $26,($27),syscall_trace
+ jsr $26,syscall_trace
bis $9,$9,$19
bis $10,$10,$20
bsr $1,undo_switch_stack
@@ -616,21 +607,13 @@ strace_error:
.align 3
handle_bottom_half:
- /*
- * We're called with $0 containing the address of
- * 'intr_count' and $1 containing 'intr_count+1'
- */
- stq $1,0($0) /* intr_count = 1 */
subq $30,16,$30
stq $19,0($30) /* save syscall nr */
stq $20,8($30) /* and error indication (a3) */
- lda $27,do_bottom_half
- jsr $26,($27),do_bottom_half
- lda $0,intr_count
+ jsr $26,do_bottom_half
ldq $19,0($30)
ldq $20,8($30)
addq $30,16,$30
- stq $31,0($0) /* intr_count = 0 */
br $31,ret_from_handle_bh
.align 3
@@ -648,10 +631,14 @@ syscall_error:
ldq $20,72($30) /* .. and this a3 */
subq $31,$0,$0 /* with error in v0 */
addq $31,1,$1 /* set a3 for errno return */
- bis $31,$31,$26 /* tell "ret_from_sys_call" that we can restart */
+ stq $0,0($30)
+ bis $31,$31,$26 /* tell "ret_from_sys_call" we can restart */
stq $1,72($30) /* a3 for return */
+ br $31,ret_from_sys_call
+
ret_success:
stq $0,0($30)
+ stq $31,72($30) /* a3=0 => no error */
br $31,ret_from_sys_call
.align 3
@@ -659,8 +646,7 @@ signal_return:
bis $30,$30,$17
br $1,do_switch_stack
bis $30,$30,$18
- lda $27,do_signal
- jsr $26,($27),do_signal
+ jsr $26,do_signal
lda $30,SWITCH_STACK_SIZE($30)
br $31,restore_all
.end entSys
@@ -671,8 +657,7 @@ reschedule:
subq $30,16,$30
stq $19,0($30) /* save syscall nr */
stq $20,8($30) /* and error indication (a3) */
- lda $27,schedule
- jsr $26,($27),schedule
+ jsr $26,schedule
ldq $19,0($30)
ldq $20,8($30)
addq $30,16,$30
@@ -685,8 +670,7 @@ sys_sigreturn:
bis $30,$30,$17
lda $30,-SWITCH_STACK_SIZE($30)
bis $30,$30,$18
- lda $27,do_sigreturn
- jsr $26,($27),do_sigreturn
+ jsr $26,do_sigreturn
br $1,undo_switch_stack
br $31,ret_from_sys_call
.end sys_sigreturn
@@ -697,8 +681,7 @@ sys_sigsuspend:
bis $30,$30,$17
br $1,do_switch_stack
bis $30,$30,$18
- lda $27,do_sigsuspend
- jsr $26,($27),do_sigsuspend
+ jsr $26,do_sigsuspend
lda $30,SWITCH_STACK_SIZE($30)
br $31,ret_from_sys_call
.end sys_sigsuspend
@@ -709,12 +692,12 @@ 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, sys_brk, do_entSys, sys_lseek
+ .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, do_entSys, do_entSys
+ .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
@@ -725,7 +708,7 @@ sys_call_table:
/* 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, do_entSys
+ .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
@@ -755,7 +738,7 @@ sys_call_table:
.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, do_entSys, do_entSys, do_entSys, osf_proplist_syscall
+ .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
@@ -776,5 +759,6 @@ sys_call_table:
.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, do_entSys, sys_setresuid, sys_getresuid
- .quad sys_pciconfig_read, sys_pciconfig_write, do_entSys, do_entSys, do_entSys
+ .quad sys_nanosleep, sys_mremap, sys_nfsservctl, sys_setresuid, sys_getresuid
+ .quad sys_pciconfig_read, sys_pciconfig_write, sys_query_module
+ .quad do_entSys, do_entSys
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index 0c1fc8681..17ca4581a 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -23,8 +23,10 @@ _stext:
__start:
br $27,1f
1: ldgp $29,0($27)
- lda $27,start_kernel
- jsr $26,($27),start_kernel
+ /* We need to get current loaded up with our first task. */
+ ldq $8,current_set
+ /* And then we can start the kernel. */
+ jsr $26,start_kernel
halt
.end __start
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index a769a37be..133c27828 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -26,7 +26,12 @@
#include <asm/bitops.h>
#include <asm/dma.h>
-extern void timer_interrupt(struct pt_regs * regs);
+#define RTC_IRQ 8
+#ifdef CONFIG_RTC
+#define TIMER_IRQ 0 /* timer is the pit */
+#else
+#define TIMER_IRQ RTC_IRQ /* the timer is, in fact, the rtc */
+#endif
#if NR_IRQS > 64
# error Unable to handle more than 64 irq levels.
@@ -53,7 +58,6 @@ extern void timer_interrupt(struct pt_regs * regs);
*/
static unsigned long irq_mask = ~0UL;
-
/*
* Update the hardware with the irq mask passed in MASK. The function
* exploits the fact that it is known that only bit IRQ has changed.
@@ -133,6 +137,7 @@ void enable_irq(unsigned int irq_nr)
/*
* Initial irq handlers.
*/
+static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL};
static struct irqaction *irq_action[NR_IRQS];
int get_irq_list(char *buf)
@@ -144,7 +149,7 @@ int get_irq_list(char *buf)
action = irq_action[i];
if (!action)
continue;
- len += sprintf(buf+len, "%2d: %8d %c %s",
+ len += sprintf(buf+len, "%2d: %10u %c %s",
i, kstat.interrupts[i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
@@ -212,7 +217,10 @@ int request_irq(unsigned int irq,
shared = 1;
}
- action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
+ if (irq == TIMER_IRQ)
+ action = &timer_irq;
+ else
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
GFP_KERNEL);
if (!action)
return -ENOMEM;
@@ -274,6 +282,16 @@ static inline void handle_nmi(struct pt_regs * regs)
printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
}
+unsigned int local_irq_count[NR_CPUS];
+atomic_t __alpha_bh_counter;
+
+#ifdef __SMP__
+#error Me no hablo Alpha SMP
+#else
+#define irq_enter(cpu, irq) (++local_irq_count[cpu])
+#define irq_exit(cpu, irq) (--local_irq_count[cpu])
+#endif
+
static void unexpected_irq(int irq, struct pt_regs * regs)
{
struct irqaction *action;
@@ -302,27 +320,32 @@ static void unexpected_irq(int irq, struct pt_regs * regs)
static inline void handle_irq(int irq, struct pt_regs * regs)
{
struct irqaction * action = irq_action[irq];
+ int cpu = smp_processor_id();
+ irq_enter(cpu, irq);
kstat.interrupts[irq]++;
if (!action) {
unexpected_irq(irq, regs);
- return;
+ } else {
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
}
- do {
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while (action);
+ irq_exit(cpu, irq);
}
static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
{
struct irqaction * action;
+ int cpu = smp_processor_id();
if ((unsigned) irq > NR_IRQS) {
printk("device_interrupt: unexpected interrupt %d\n", irq);
return;
}
+ irq_enter(cpu, irq);
kstat.interrupts[irq]++;
action = irq_action[irq];
/*
@@ -336,15 +359,16 @@ static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
*/
mask_irq(ack);
ack_irq(ack);
- if (!action)
- return;
- if (action->flags & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- do {
- action->handler(irq, action->dev_id, regs);
- action = action->next;
- } while (action);
- unmask_irq(ack);
+ if (action) {
+ if (action->flags & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ unmask_irq(ack);
+ }
+ irq_exit(cpu, irq);
}
#ifdef CONFIG_PCI
@@ -646,7 +670,9 @@ int probe_irq_off(unsigned long irqs)
{
int i;
- irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */
+ /* as irq 0 & 8 handling don't use this function, i didn't
+ * bother changing the following: */
+ irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */
#ifdef CONFIG_ALPHA_P2K
irqs &= ~(1 << 8); /* mask out irq 8 since that's the unused RTC input to PIC */
#endif
@@ -686,7 +712,7 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned lon
printk("Interprocessor interrupt? You must be kidding\n");
break;
case 1:
- timer_interrupt(&regs);
+ handle_irq(RTC_IRQ, &regs);
return;
case 2:
machine_check(vector, la_ptr, &regs);
diff --git a/arch/alpha/kernel/ksyms.c b/arch/alpha/kernel/ksyms.c
deleted file mode 100644
index 9b9e19e46..000000000
--- a/arch/alpha/kernel/ksyms.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * linux/arch/alpha/kernel/ksyms.c
- *
- * Export the alpha-specific functions that are needed for loadable
- * modules.
- */
-
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <asm/io.h>
-#include <asm/hwrpb.h>
-
-extern void bcopy (const char *src, char *dst, int len);
-extern struct hwrpb_struct *hwrpb;
-
-/* these are C runtime functions with special calling conventions: */
-extern void __divl (void);
-extern void __reml (void);
-extern void __divq (void);
-extern void __remq (void);
-extern void __divlu (void);
-extern void __remlu (void);
-extern void __divqu (void);
-extern void __remqu (void);
-
-extern void dump_thread(struct pt_regs *, struct user *);
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-
-static struct symbol_table arch_symbol_table = {
-#include <linux/symtab_begin.h>
- /* platform dependent support */
-
- X(_inb),
- X(_inw),
- X(_inl),
- X(_outb),
- X(_outw),
- X(_outl),
- X(_readb),
- X(_readw),
- X(_readl),
- X(_writeb),
- X(_writew),
- X(_writel),
- X(__divl),
- X(__reml),
- X(__divq),
- X(__remq),
- X(__divlu),
- X(__remlu),
- X(__divqu),
- X(__remqu),
- X(insb),
- X(insw),
- X(insl),
- X(outsb),
- X(outsw),
- X(outsl),
- X(strcat),
- X(strcmp),
- X(strcpy),
- X(strlen),
- X(strncmp),
- X(strncpy),
- X(strnlen),
- X(strstr),
- X(strtok),
- X(strchr),
- X(memcmp),
- X(memmove),
- X(__memcpy),
- X(__constant_c_memset),
-
- X(dump_thread),
- X(dump_fpu),
- X(hwrpb),
- X(wrusp),
-
- /*
- * The following are special because they're not called
- * explicitly (the C compiler or assembler generates them in
- * response to division operations). Fortunately, their
- * interface isn't gonna change any time soon now, so it's OK
- * to leave it out of version control.
- */
-# undef bcopy
-# undef memcpy
-# undef memset
- XNOVERS(__divl),
- XNOVERS(__divlu),
- XNOVERS(__divq),
- XNOVERS(__divqu),
- XNOVERS(__reml),
- XNOVERS(__remlu),
- XNOVERS(__remq),
- XNOVERS(__remqu),
- XNOVERS(memcpy),
- XNOVERS(memset),
- /* these shouldn't be necessary---they should be versioned: */
- XNOVERS(__memcpy),
- XNOVERS(__memset),
-#include <linux/symtab_end.h>
-};
-
-void arch_syms_export(void)
-{
- register_symtab(&arch_symbol_table);
-}
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 003775d2e..ef9576492 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -14,6 +14,8 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
@@ -31,6 +33,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/sysinfo.h>
extern int do_mount(kdev_t, const char *, const char *, char *, int, void *);
extern int do_pipe(int *);
@@ -43,6 +46,40 @@ extern void put_unnamed_dev(kdev_t);
extern asmlinkage int sys_umount(char *);
extern asmlinkage int sys_swapon(const char *specialfile, int swap_flags);
+extern asmlinkage unsigned long sys_brk(unsigned long);
+
+/*
+ * Brk needs to return an error. Still support Linux's brk(0) query idiom,
+ * which OSF programs just shouldn't be doing. We're still not quite
+ * identical to OSF as we don't return 0 on success, but doing otherwise
+ * would require changes to libc. Hopefully this is good enough.
+ */
+asmlinkage unsigned long osf_brk(unsigned long brk)
+{
+ unsigned long retval = sys_brk(brk);
+ if (brk && brk != retval)
+ retval = -ENOMEM;
+ return retval;
+}
+
+/*
+ * This is pure guess-work..
+ */
+asmlinkage int osf_set_program_attributes(
+ unsigned long text_start, unsigned long text_len,
+ unsigned long bss_start, unsigned long bss_len)
+{
+ struct mm_struct *mm;
+
+ lock_kernel();
+ mm = current->mm;
+ mm->end_code = bss_start + bss_len;
+ mm->brk = bss_start + bss_len;
+ printk("set_program_attributes(%lx %lx %lx %lx)\n",
+ text_start, text_len, bss_start, bss_len);
+ unlock_kernel();
+ return 0;
+}
/*
* OSF/1 directory handling functions...
@@ -134,12 +171,17 @@ asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4,
extern int sys_getpriority(int, int);
int prio;
+ /*
+ * We don't need to acquire the kernel lock here, because
+ * all of these operations are local. sys_getpriority
+ * will get the lock as required..
+ */
prio = sys_getpriority(which, who);
- if (prio < 0)
- return prio;
-
- regs.r0 = 0; /* special return: no errors */
- return 20 - prio;
+ if (prio >= 0) {
+ regs.r0 = 0; /* special return: no errors */
+ prio = 20 - prio;
+ }
+ return prio;
}
@@ -151,25 +193,39 @@ asmlinkage unsigned long sys_madvise(void)
return 0;
}
+/*
+ * 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)
{
- (&regs)->r20 = current->euid;
- return current->uid;
+ 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)
{
- (&regs)->r20 = current->egid;
- return current->gid;
+ 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)
{
- (&regs)->r20 = current->p_opptr->pid;
- return current->pid;
+ struct task_struct *tsk = current;
+
+ /*
+ * This isn't strictly "local" any more and we should actually
+ * acquire the kernel lock. The "p_opptr" pointer might change
+ * if the parent goes away (or due to ptrace). But any race
+ * isn't actually going to matter, as if the parent happens
+ * to change we can happily return either of the pids.
+ */
+ (&regs)->r20 = tsk->p_opptr->pid;
+ return tsk->pid;
}
asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
@@ -177,15 +233,20 @@ asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
unsigned long off)
{
struct file *file = NULL;
+ unsigned long ret = -EBADF;
+ lock_kernel();
if (flags & (MAP_HASSEMAPHORE | MAP_INHERIT | MAP_UNALIGNED))
printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags);
if (!(flags & MAP_ANONYMOUS)) {
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- return -EBADF;
+ goto out;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- return do_mmap(file, addr, len, prot, flags, off);
+ ret = do_mmap(file, addr, len, prot, flags, off);
+out:
+ unlock_kernel();
+ return ret;
}
@@ -228,22 +289,27 @@ asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long b
struct inode *inode;
int retval;
+ lock_kernel();
if (bufsiz > sizeof(struct osf_statfs))
bufsiz = sizeof(struct osf_statfs);
retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
if (retval)
- return retval;
+ goto out;
retval = namei(path, &inode);
if (retval)
- return retval;
+ goto out;
+ retval = -ENOSYS;
if (!inode->i_sb->s_op->statfs) {
iput(inode);
- return -ENOSYS;
+ goto out;
}
inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat));
linux_to_osf_statfs(&linux_stat, buffer);
iput(inode);
- return 0;
+ retval = 0;
+out:
+ unlock_kernel();
+ return retval;
}
asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz)
@@ -253,20 +319,27 @@ asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned
struct inode *inode;
int retval;
+ lock_kernel();
retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
if (retval)
- return retval;
+ goto out;
if (bufsiz > sizeof(struct osf_statfs))
bufsiz = sizeof(struct osf_statfs);
+ retval = -EBADF;
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- return -EBADF;
+ goto out;
+ retval = -ENOENT;
if (!(inode = file->f_inode))
- return -ENOENT;
+ goto out;
+ retval = -ENOSYS;
if (!inode->i_sb->s_op->statfs)
- return -ENOSYS;
+ goto out;
inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat));
linux_to_osf_statfs(&linux_stat, buffer);
- return 0;
+ retval = 0;
+out:
+ unlock_kernel();
+ return retval;
}
/*
@@ -414,9 +487,9 @@ static int osf_procfs_mount(char *dirname, struct procfs_args *args, int flags)
asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
{
- int retval;
+ int retval = -EINVAL;
- retval = -EINVAL;
+ lock_kernel();
switch (typenr) {
case 1:
retval = osf_ufs_mount(path, (struct ufs_args *) data, flag);
@@ -430,12 +503,18 @@ asmlinkage int osf_mount(unsigned long typenr, char *path, int flag, void *data)
default:
printk("osf_mount(%ld, %x)\n", typenr, flag);
}
+ unlock_kernel();
return retval;
}
asmlinkage int osf_umount(char *path, int flag)
{
- return sys_umount(path);
+ int ret;
+
+ lock_kernel();
+ ret = sys_umount(path);
+ unlock_kernel();
+ return ret;
}
/*
@@ -449,11 +528,12 @@ asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain)
unsigned long ticks;
int retval;
+ lock_kernel();
retval = verify_area(VERIFY_READ, sleep, sizeof(*sleep));
if (retval)
- return retval;
+ goto out;
if (remain && (retval = verify_area(VERIFY_WRITE, remain, sizeof(*remain))))
- return retval;
+ goto out;
copy_from_user(&tmp, sleep, sizeof(*sleep));
ticks = tmp.tv_usec;
ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
@@ -461,8 +541,9 @@ asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain)
current->timeout = ticks + jiffies;
current->state = TASK_INTERRUPTIBLE;
schedule();
+ retval = 0;
if (!remain)
- return 0;
+ goto out;
ticks = jiffies;
if (ticks < current->timeout)
ticks = current->timeout - ticks;
@@ -472,26 +553,38 @@ asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain)
tmp.tv_sec = ticks / HZ;
tmp.tv_usec = ticks % HZ;
copy_to_user(remain, &tmp, sizeof(*remain));
- return 0;
+out:
+ unlock_kernel();
+ return retval;
}
asmlinkage int osf_utsname(char *name)
{
- int error = verify_area(VERIFY_WRITE, name, 5 * 32);
+ int error;
+
+ lock_kernel();
+ error = verify_area(VERIFY_WRITE, name, 5 * 32);
if (error)
- return error;
+ goto out;
copy_to_user(name + 0, system_utsname.sysname, 32);
copy_to_user(name + 32, system_utsname.nodename, 32);
copy_to_user(name + 64, system_utsname.release, 32);
copy_to_user(name + 96, system_utsname.version, 32);
copy_to_user(name + 128, system_utsname.machine, 32);
- return 0;
+out:
+ unlock_kernel();
+ return error;
}
asmlinkage int osf_swapon(const char *path, int flags, int lowat, int hiwat)
{
+ int ret;
+
/* for now, simply ignore lowat and hiwat... */
- return sys_swapon(path, flags);
+ lock_kernel();
+ ret = sys_swapon(path, flags);
+ unlock_kernel();
+ return ret;
}
asmlinkage unsigned long sys_getpagesize(void)
@@ -510,11 +603,15 @@ asmlinkage int sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5,
int fd[2];
int error;
+ lock_kernel();
error = do_pipe(fd);
if (error)
- return error;
+ goto out;
(&regs)->r20 = fd[1];
- return fd[0];
+ error = fd[0];
+out:
+ unlock_kernel();
+ return error;
}
/*
@@ -525,9 +622,10 @@ asmlinkage int osf_getdomainname(char *name, int namelen)
unsigned len;
int i, error;
+ lock_kernel();
error = verify_area(VERIFY_WRITE, name, namelen);
if (error)
- return error;
+ goto out;
len = namelen;
if (namelen > 32)
@@ -538,23 +636,29 @@ asmlinkage int osf_getdomainname(char *name, int namelen)
if (system_utsname.domainname[i] == '\0')
break;
}
- return 0;
+out:
+ unlock_kernel();
+ return error;
}
asmlinkage long osf_shmat(int shmid, void *shmaddr, int shmflg)
{
unsigned long raddr;
- int err;
+ long err;
+ lock_kernel();
err = sys_shmat(shmid, shmaddr, shmflg, &raddr);
if (err)
- return err;
+ goto out;
/*
* This works because all user-level addresses are
* non-negative longs!
*/
- return raddr;
+ err = raddr;
+out:
+ unlock_kernel();
+ return err;
}
@@ -628,46 +732,44 @@ asmlinkage long osf_proplist_syscall(enum pl_code code, union pl_args *args)
long error;
int *min_buf_size_ptr;
+ lock_kernel();
switch (code) {
case PL_SET:
error = verify_area(VERIFY_READ, &args->set.nbytes,
sizeof(args->set.nbytes));
- if (error)
- return error;
- return args->set.nbytes;
-
+ if (!error)
+ error = args->set.nbytes;
+ break;
case PL_FSET:
error = verify_area(VERIFY_READ, &args->fset.nbytes,
sizeof(args->fset.nbytes));
- if (error)
- return error;
- return args->fset.nbytes;
-
+ if (!error)
+ error = args->fset.nbytes;
+ break;
case PL_GET:
get_user(min_buf_size_ptr, &args->get.min_buf_size);
error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
sizeof(*min_buf_size_ptr));
- if (error)
- return error;
- put_user(0, min_buf_size_ptr);
- return 0;
-
+ if (!error)
+ put_user(0, min_buf_size_ptr);
+ break;
case PL_FGET:
get_user(min_buf_size_ptr, &args->fget.min_buf_size);
error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
sizeof(*min_buf_size_ptr));
- if (error)
- return error;
- put_user(0, min_buf_size_ptr);
- return 0;
-
+ if (!error)
+ put_user(0, min_buf_size_ptr);
+ break;
case PL_DEL:
case PL_FDEL:
- return 0;
-
+ error = 0;
+ break;
default:
- return -EOPNOTSUPP;
- }
+ error = -EOPNOTSUPP;
+ break;
+ };
+ unlock_kernel();
+ return error;
}
/*
@@ -684,6 +786,7 @@ asmlinkage unsigned long alpha_create_module(char *module_name, unsigned long si
asmlinkage unsigned long sys_create_module(char *, unsigned long);
long retval;
+ lock_kernel();
retval = sys_create_module(module_name, size);
/*
* we get either a module address or an error number,
@@ -692,29 +795,69 @@ asmlinkage unsigned long alpha_create_module(char *module_name, unsigned long si
* much larger.
*/
if (retval + 1000 > 0)
- return retval;
+ goto out;
/* tell entry.S:syscall_error that this is NOT an error: */
regs.r0 = 0;
+out:
+ unlock_kernel();
return retval;
}
+asmlinkage long osf_sysinfo(int command, char *buf, long count)
+{
+ static char * sysinfo_table[] = {
+ system_utsname.sysname,
+ system_utsname.nodename,
+ system_utsname.release,
+ system_utsname.version,
+ system_utsname.machine,
+ "alpha", /* instruction set architecture */
+ "dummy", /* hardware serial number */
+ "dummy", /* hardware manufacturer */
+ "dummy", /* secure RPC domain */
+ };
+ unsigned long offset;
+ char *res;
+ long len, err = -EINVAL;
+
+ lock_kernel();
+ offset = command-1;
+ if (offset >= sizeof(sysinfo_table)/sizeof(char *)) {
+ /* Digital unix has a few unpublished interfaces here */
+ printk("sysinfo(%d)", command);
+ goto out;
+ }
+ res = sysinfo_table[offset];
+ len = strlen(res)+1;
+ if (len > count)
+ len = count;
+ if (copy_to_user(buf, res, len))
+ err = -EFAULT;
+ else
+ err = 0;
+out:
+ unlock_kernel();
+ return err;
+}
-asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
+asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer,
+ unsigned long nbytes,
int *start, void *arg)
{
extern unsigned long rdfpcr(void);
- unsigned long fpcw;
+ unsigned long w;
switch (op) {
- case 45: /* GSI_IEEE_FP_CONTROL */
+ case GSI_IEEE_FP_CONTROL:
/* build and return current fp control word: */
- fpcw = current->tss.flags & IEEE_TRAP_ENABLE_MASK;
- fpcw |= ((rdfpcr() >> 52) << 17) & IEEE_STATUS_MASK;
- put_user(fpcw, (unsigned long *) buffer);
+ w = current->tss.flags & IEEE_TRAP_ENABLE_MASK;
+ w |= ((rdfpcr() >> 52) << 17) & IEEE_STATUS_MASK;
+ if (put_user(w, (unsigned long *) buffer))
+ return -EFAULT;
return 0;
- case 46: /* GSI_IEEE_STATE_AT_SIGNAL */
+ case GSI_IEEE_STATE_AT_SIGNAL:
/*
* Not sure anybody will ever use this weird stuff. These
* ops can be used (under OSF/1) to set the fpcr that should
@@ -722,35 +865,67 @@ asmlinkage unsigned long osf_getsysinfo(unsigned long op, void *buffer, unsigned
*/
break;
+ case GSI_UACPROC:
+ w = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
+ if (put_user(w, (unsigned int *)buffer))
+ return -EFAULT;
+ return 0;
+
default:
break;
}
+
return -EOPNOTSUPP;
}
-asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
+asmlinkage unsigned long osf_setsysinfo(unsigned long op, void *buffer,
+ unsigned long nbytes,
int *start, void *arg)
{
- unsigned long fpcw;
+ unsigned long v, w, i;
switch (op) {
- case 14: /* SSI_IEEE_FP_CONTROL */
+ case SSI_IEEE_FP_CONTROL:
/* update trap enable bits: */
- get_user(fpcw, (unsigned long *) buffer);
+ if (get_user(w, (unsigned long *) buffer))
+ return -EFAULT;
current->tss.flags &= ~IEEE_TRAP_ENABLE_MASK;
- current->tss.flags |= (fpcw & IEEE_TRAP_ENABLE_MASK);
+ current->tss.flags |= (w & IEEE_TRAP_ENABLE_MASK);
return 0;
- case 15: /* SSI_IEEE_STATE_AT_SIGNAL */
- case 16: /* SSI_IEEE_IGNORE_STATE_AT_SIGNAL */
+ case SSI_IEEE_STATE_AT_SIGNAL:
+ case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
/*
* Not sure anybody will ever use this weird stuff. These
* ops can be used (under OSF/1) to set the fpcr that should
* be used when a signal handler starts executing.
*/
+ break;
+
+ case SSI_NVPAIRS:
+ for (i = 0; i < nbytes; ++i) {
+ if (get_user(v, 2*i + (unsigned int *)buffer))
+ return -EFAULT;
+ if (get_user(w, 2*i + 1 + (unsigned int *)buffer))
+ return -EFAULT;
+ switch (v) {
+ case SSIN_UACPROC:
+ current->tss.flags &=
+ ~(UAC_BITMASK << UAC_SHIFT);
+ current->tss.flags |=
+ (w & UAC_BITMASK) << UAC_SHIFT;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+ return 0;
+
default:
break;
}
+
return -EOPNOTSUPP;
}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index a31ba1732..2eb2d51b7 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -13,6 +13,8 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
@@ -25,12 +27,20 @@
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/elfcore.h>
+#include <linux/reboot.h>
+
+#ifdef CONFIG_RTC
+#include <linux/mc146818rtc.h>
+#endif
#include <asm/reg.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+/*
+ * No need to acquire the kernel lock, we're entirely local..
+ */
asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs regs)
@@ -41,18 +51,43 @@ asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
asmlinkage int sys_idle(void)
{
+ int ret = -EPERM;
+
+ lock_kernel();
if (current->pid != 0)
- return -EPERM;
+ goto out;
/* endless idle loop with no priority at all */
current->counter = -100;
for (;;) {
schedule();
}
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
}
-void hard_reset_now(void)
+void machine_restart(char * __unused)
{
+#ifdef CONFIG_RTC /* reset rtc to defaults */
+ unsigned char control;
+ unsigned long flags;
+
+ /* i'm not sure if i really need to disable interrupts here */
+ save_flags(flags);
+ cli();
+ /* reset periodic interrupt frequency */
+ CMOS_WRITE(0x26, RTC_FREQ_SELECT);
+
+ /* turn on periodic interrupts */
+ control = CMOS_READ(RTC_CONTROL);
+ control |= RTC_PIE;
+ CMOS_WRITE(control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+ restore_flags(flags);
+#endif
+
#if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR)
/* who said DEC engineer's have no sense of humor? ;-)) */
*(int *) GRU_RESET = 0x0000dead;
@@ -61,6 +96,14 @@ void hard_reset_now(void)
halt();
}
+void machine_halt(void)
+{
+}
+
+void machine_power_off(void)
+{
+}
+
void show_regs(struct pt_regs * regs)
{
printk("\nps: %04lx pc: [<%016lx>]\n", regs->ps, regs->pc);
@@ -133,7 +176,7 @@ extern void ret_from_sys_call(void);
* Use the passed "regs" pointer to determine how much space we need
* for a kernel fork().
*/
-void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
@@ -159,6 +202,8 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
p->tss.pal_flags = 1; /* set FEN, clear everything else */
p->tss.flags = current->tss.flags;
p->mm->context = 0;
+
+ return 0;
}
/*
@@ -244,10 +289,13 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
int error;
char * filename;
+ lock_kernel();
error = getname((char *) a0, &filename);
if (error)
- return error;
+ goto out;
error = do_execve(filename, (char **) a1, (char **) a2, &regs);
putname(filename);
+out:
+ unlock_kernel();
return error;
}
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index d03744a68..019fb6b95 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -8,6 +8,8 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
@@ -487,27 +489,30 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
int a4, int a5, struct pt_regs regs)
{
struct task_struct *child;
- struct user * dummy;
-
- dummy = NULL;
+ long ret;
+ lock_kernel();
DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",
request, pid, addr, data));
+ ret = -EPERM;
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
if (current->flags & PF_PTRACED)
- return -EPERM;
+ goto out;
/* set the ptrace bit in the process flags. */
current->flags |= PF_PTRACED;
- return 0;
+ ret = 0;
+ goto out;
}
if (pid == 1) /* you may not mess with init */
- return -EPERM;
+ goto out;
+ ret = -ESRCH;
if (!(child = get_task(pid)))
- return -ESRCH;
+ goto out;
if (request == PTRACE_ATTACH) {
+ ret = -EPERM;
if (child == current)
- return -EPERM;
+ goto out;
if ((!child->dumpable ||
(current->uid != child->euid) ||
(current->uid != child->suid) ||
@@ -515,10 +520,10 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
(current->gid != child->egid) ||
(current->gid != child->sgid) ||
(current->gid != child->gid)) && !suser())
- return -EPERM;
+ goto out;
/* the same process cannot be attached many times */
if (child->flags & PF_PTRACED)
- return -EPERM;
+ goto out;
child->flags |= PF_PTRACED;
if (child->p_pptr != current) {
REMOVE_LINKS(child);
@@ -526,20 +531,22 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
SET_LINKS(child);
}
send_sig(SIGSTOP, child, 1);
- return 0;
+ ret = 0;
+ goto out;
}
+ ret = -ESRCH;
if (!(child->flags & PF_PTRACED)) {
DBG(DBG_MEM, ("child not traced\n"));
- return -ESRCH;
+ goto out;
}
if (child->state != TASK_STOPPED) {
DBG(DBG_MEM, ("child process not stopped\n"));
if (request != PTRACE_KILL)
- return -ESRCH;
+ goto out;
}
if (child->p_pptr != current) {
DBG(DBG_MEM, ("child not parent of this process\n"));
- return -ESRCH;
+ goto out;
}
switch (request) {
@@ -547,37 +554,41 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: {
unsigned long tmp;
- int res;
- res = read_long(child, addr, &tmp);
+ ret = read_long(child, addr, &tmp);
DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp));
- if (res < 0)
- return res;
+ if (ret < 0)
+ goto out;
regs.r0 = 0; /* special return: no errors */
- return tmp;
+ ret = tmp;
+ goto out;
}
/* read register number ADDR. */
case PTRACE_PEEKUSR:
regs.r0 = 0; /* special return: no errors */
DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0));
- return get_reg(child, addr);
+ ret = get_reg(child, addr);
+ goto out;
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
DBG(DBG_MEM, ("poke %#lx<-%#lx\n", addr, data));
- return write_long(child, addr, data);
+ ret = write_long(child, addr, data);
+ goto out;
case PTRACE_POKEUSR: /* write the specified register */
DBG(DBG_MEM, ("poke $%ld<-%#lx\n", addr, data));
- return put_reg(child, addr, data);
+ ret = put_reg(child, addr, data);
+ goto out;
case PTRACE_SYSCALL: /* continue and stop at next
(return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
+ ret = -EIO;
if ((unsigned long) data > NSIG)
- return -EIO;
+ goto out;
if (request == PTRACE_SYSCALL)
child->flags |= PF_TRACESYS;
else
@@ -586,7 +597,8 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
wake_up_process(child);
/* make sure single-step breakpoint is gone. */
ptrace_cancel_bpt(child);
- return data;
+ ret = data;
+ goto out;
}
/*
@@ -601,23 +613,27 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
}
/* make sure single-step breakpoint is gone. */
ptrace_cancel_bpt(child);
- return 0;
+ ret = 0;
+ goto out;
}
case PTRACE_SINGLESTEP: { /* execute single instruction. */
+ ret = -EIO;
if ((unsigned long) data > NSIG)
- return -EIO;
+ goto out;
child->debugreg[4] = -1; /* mark single-stepping */
child->flags &= ~PF_TRACESYS;
wake_up_process(child);
child->exit_code = data;
/* give it a chance to run. */
- return 0;
+ ret = 0;
+ goto out;
}
case PTRACE_DETACH: { /* detach a process that was attached. */
+ ret = -EIO;
if ((unsigned long) data > NSIG)
- return -EIO;
+ goto out;
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
child->exit_code = data;
@@ -626,19 +642,25 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data,
SET_LINKS(child);
/* make sure single-step breakpoint is gone. */
ptrace_cancel_bpt(child);
- return 0;
+ ret = 0;
+ goto out;
}
default:
- return -EIO;
+ ret = -EIO;
+ goto out;
}
+out:
+ unlock_kernel();
+ return ret;
}
asmlinkage void syscall_trace(void)
{
+ lock_kernel();
if ((current->flags & (PF_PTRACED|PF_TRACESYS))
!= (PF_PTRACED|PF_TRACESYS))
- return;
+ goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
notify_parent(current);
@@ -651,4 +673,6 @@ asmlinkage void syscall_trace(void)
if (current->exit_code)
current->signal |= (1 << (current->exit_code - 1));
current->exit_code = 0;
+out:
+ unlock_kernel();
}
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index f53d556e3..0fa1129ee 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -22,6 +22,11 @@
#include <linux/delay.h>
#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */
+#ifdef CONFIG_RTC
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#endif
+
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -83,9 +88,17 @@ static void init_pit (void)
outb(0x18, 0x41);
#endif
+#ifdef CONFIG_RTC /* setup interval timer if /dev/rtc is being used */
+ outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb(LATCH & 0xff, 0x40); /* LSB */
+ outb(LATCH >> 8, 0x40); /* MSB */
+ request_region(0x40, 0x20, "timer"); /* reserve pit */
+#else
outb(0x36, 0x43); /* counter 0: system timer */
outb(0x00, 0x40);
outb(0x00, 0x40);
+ request_region(0x70, 0x10, "timer"); /* reserve rtc */
+#endif
outb(0xb6, 0x43); /* counter 2: speaker */
outb(0x31, 0x42);
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 9e6ca449d..5c3eb79ef 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -12,6 +12,8 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
@@ -38,6 +40,9 @@ extern int ptrace_cancel_bpt (struct task_struct *child);
*
* We change the range to -1 .. 1 in order to let gcc easily
* use the conditional move instructions.
+ *
+ * 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)
@@ -73,12 +78,17 @@ asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask,
*/
asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw)
{
- unsigned long oldmask = current->blocked;
+ unsigned long oldmask;
+
+ spin_lock_irq(&current->sigmask_lock);
+ oldmask = current->blocked;
current->blocked = mask & _BLOCKABLE;
+ spin_unlock_irq(&current->sigmask_lock);
+
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(oldmask,regs, sw, 0, 0))
+ if (do_signal(oldmask, regs, sw, 0, 0))
return -EINTR;
}
}
@@ -94,57 +104,63 @@ asmlinkage void do_sigreturn(struct sigcontext * sc,
/* verify that it's a good sigcontext before using it */
if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
- do_exit(SIGSEGV);
- get_user(ps, &sc->sc_ps);
- if (ps != 8)
- do_exit(SIGSEGV);
- get_user(mask, &sc->sc_mask);
- if (mask & ~_BLOCKABLE)
- do_exit(SIGSEGV);
+ 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;
/* ok, looks fine, start restoring */
- get_user(usp, sc->sc_regs+30);
+ __get_user(usp, sc->sc_regs+30);
wrusp(usp);
- get_user(regs->pc, &sc->sc_pc);
+ __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);
- get_user(regs->r2, sc->sc_regs+2);
- get_user(regs->r3, sc->sc_regs+3);
- get_user(regs->r4, sc->sc_regs+4);
- get_user(regs->r5, sc->sc_regs+5);
- get_user(regs->r6, sc->sc_regs+6);
- get_user(regs->r7, sc->sc_regs+7);
- get_user(regs->r8, sc->sc_regs+8);
- get_user(sw->r9, sc->sc_regs+9);
- get_user(sw->r10, sc->sc_regs+10);
- get_user(sw->r11, sc->sc_regs+11);
- get_user(sw->r12, sc->sc_regs+12);
- get_user(sw->r13, sc->sc_regs+13);
- get_user(sw->r14, sc->sc_regs+14);
- get_user(sw->r15, sc->sc_regs+15);
- get_user(regs->r16, sc->sc_regs+16);
- get_user(regs->r17, sc->sc_regs+17);
- get_user(regs->r18, sc->sc_regs+18);
- get_user(regs->r19, sc->sc_regs+19);
- get_user(regs->r20, sc->sc_regs+20);
- get_user(regs->r21, sc->sc_regs+21);
- get_user(regs->r22, sc->sc_regs+22);
- get_user(regs->r23, sc->sc_regs+23);
- get_user(regs->r24, sc->sc_regs+24);
- get_user(regs->r25, sc->sc_regs+25);
- get_user(regs->r26, sc->sc_regs+26);
- 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(regs->r0, sc->sc_regs+0);
+ __get_user(regs->r1, sc->sc_regs+1);
+ __get_user(regs->r2, sc->sc_regs+2);
+ __get_user(regs->r3, sc->sc_regs+3);
+ __get_user(regs->r4, sc->sc_regs+4);
+ __get_user(regs->r5, sc->sc_regs+5);
+ __get_user(regs->r6, sc->sc_regs+6);
+ __get_user(regs->r7, sc->sc_regs+7);
+ __get_user(regs->r8, sc->sc_regs+8);
+ __get_user(sw->r9, sc->sc_regs+9);
+ __get_user(sw->r10, sc->sc_regs+10);
+ __get_user(sw->r11, sc->sc_regs+11);
+ __get_user(sw->r12, sc->sc_regs+12);
+ __get_user(sw->r13, sc->sc_regs+13);
+ __get_user(sw->r14, sc->sc_regs+14);
+ __get_user(sw->r15, sc->sc_regs+15);
+ __get_user(regs->r16, sc->sc_regs+16);
+ __get_user(regs->r17, sc->sc_regs+17);
+ __get_user(regs->r18, sc->sc_regs+18);
+ __get_user(regs->r19, sc->sc_regs+19);
+ __get_user(regs->r20, sc->sc_regs+20);
+ __get_user(regs->r21, sc->sc_regs+21);
+ __get_user(regs->r22, sc->sc_regs+22);
+ __get_user(regs->r23, sc->sc_regs+23);
+ __get_user(regs->r24, sc->sc_regs+24);
+ __get_user(regs->r25, sc->sc_regs+25);
+ __get_user(regs->r26, sc->sc_regs+26);
+ __get_user(regs->r27, sc->sc_regs+27);
+ __get_user(regs->r28, sc->sc_regs+28);
+ __get_user(regs->gp, sc->sc_regs+29);
for (i = 0; i < 31; i++)
- get_user(sw->fp[i], sc->sc_fpregs+i);
+ __get_user(sw->fp[i], sc->sc_fpregs+i);
/* send SIGTRAP if we're single-stepping: */
+ lock_kernel();
if (ptrace_cancel_bpt (current))
send_sig(SIGTRAP, current, 1);
+ unlock_kernel();
+ return;
+
+give_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+ unlock_kernel();
}
/*
@@ -168,43 +184,46 @@ static void setup_frame(struct sigaction * sa,
wrusp((unsigned long) sc);
- put_user(oldmask, &sc->sc_mask);
- put_user(8, &sc->sc_ps);
- put_user(regs->pc, &sc->sc_pc);
- put_user(oldsp, sc->sc_regs+30);
-
- put_user(regs->r0 , sc->sc_regs+0);
- put_user(regs->r1 , sc->sc_regs+1);
- put_user(regs->r2 , sc->sc_regs+2);
- put_user(regs->r3 , sc->sc_regs+3);
- put_user(regs->r4 , sc->sc_regs+4);
- put_user(regs->r5 , sc->sc_regs+5);
- put_user(regs->r6 , sc->sc_regs+6);
- put_user(regs->r7 , sc->sc_regs+7);
- put_user(regs->r8 , sc->sc_regs+8);
- put_user(sw->r9 , sc->sc_regs+9);
- put_user(sw->r10 , sc->sc_regs+10);
- put_user(sw->r11 , sc->sc_regs+11);
- put_user(sw->r12 , sc->sc_regs+12);
- put_user(sw->r13 , sc->sc_regs+13);
- put_user(sw->r14 , sc->sc_regs+14);
- put_user(sw->r15 , sc->sc_regs+15);
- put_user(regs->r16, sc->sc_regs+16);
- put_user(regs->r17, sc->sc_regs+17);
- put_user(regs->r18, sc->sc_regs+18);
- put_user(regs->r19, sc->sc_regs+19);
- put_user(regs->r20, sc->sc_regs+20);
- put_user(regs->r21, sc->sc_regs+21);
- put_user(regs->r22, sc->sc_regs+22);
- put_user(regs->r23, sc->sc_regs+23);
- put_user(regs->r24, sc->sc_regs+24);
- put_user(regs->r25, sc->sc_regs+25);
- put_user(regs->r26, sc->sc_regs+26);
- 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(oldmask, &sc->sc_mask);
+ __put_user(8, &sc->sc_ps);
+ __put_user(regs->pc, &sc->sc_pc);
+ __put_user(oldsp, sc->sc_regs+30);
+
+ __put_user(regs->r0 , sc->sc_regs+0);
+ __put_user(regs->r1 , sc->sc_regs+1);
+ __put_user(regs->r2 , sc->sc_regs+2);
+ __put_user(regs->r3 , sc->sc_regs+3);
+ __put_user(regs->r4 , sc->sc_regs+4);
+ __put_user(regs->r5 , sc->sc_regs+5);
+ __put_user(regs->r6 , sc->sc_regs+6);
+ __put_user(regs->r7 , sc->sc_regs+7);
+ __put_user(regs->r8 , sc->sc_regs+8);
+ __put_user(sw->r9 , sc->sc_regs+9);
+ __put_user(sw->r10 , sc->sc_regs+10);
+ __put_user(sw->r11 , sc->sc_regs+11);
+ __put_user(sw->r12 , sc->sc_regs+12);
+ __put_user(sw->r13 , sc->sc_regs+13);
+ __put_user(sw->r14 , sc->sc_regs+14);
+ __put_user(sw->r15 , sc->sc_regs+15);
+ __put_user(regs->r16, sc->sc_regs+16);
+ __put_user(regs->r17, sc->sc_regs+17);
+ __put_user(regs->r18, sc->sc_regs+18);
+ __put_user(regs->r19, sc->sc_regs+19);
+ __put_user(regs->r20, sc->sc_regs+20);
+ __put_user(regs->r21, sc->sc_regs+21);
+ __put_user(regs->r22, sc->sc_regs+22);
+ __put_user(regs->r23, sc->sc_regs+23);
+ __put_user(regs->r24, sc->sc_regs+24);
+ __put_user(regs->r25, sc->sc_regs+25);
+ __put_user(regs->r26, sc->sc_regs+26);
+ __put_user(regs->r27, sc->sc_regs+27);
+ __put_user(regs->r28, sc->sc_regs+28);
+ __put_user(regs->gp , sc->sc_regs+29);
for (i = 0; i < 31; i++)
- put_user(sw->fp[i], sc->sc_fpregs+i);
+ __put_user(sw->fp[i], sc->sc_fpregs+i);
+ __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);
/*
* The following is:
@@ -215,8 +234,8 @@ static void setup_frame(struct sigaction * sa,
*
* ie, "sigreturn(stack-pointer)"
*/
- put_user(0x43ecf40047de0410, sc->sc_retcode+0);
- put_user(0x0000000000000083, sc->sc_retcode+1);
+ __put_user(0x43ecf40047de0410, sc->sc_retcode+0);
+ __put_user(0x0000000000000083, sc->sc_retcode+1);
imb();
/* "return" to the handler */
@@ -279,10 +298,13 @@ asmlinkage int do_signal(unsigned long oldmask,
struct switch_stack * sw,
unsigned long r0, unsigned long r19)
{
- unsigned long mask = ~current->blocked;
+ unsigned long mask;
unsigned long signr, single_stepping;
struct sigaction * sa;
+ int ret;
+ lock_kernel();
+ mask = ~current->blocked;
single_stepping = ptrace_cancel_bpt(current);
while ((signr = current->signal & mask) != 0) {
@@ -356,7 +378,8 @@ asmlinkage int do_signal(unsigned long oldmask,
if (single_stepping) {
ptrace_set_bpt(current); /* re-set breakpoint */
}
- return 1;
+ ret = 1;
+ goto out;
}
if (r0 &&
(regs->r0 == ERESTARTNOHAND ||
@@ -369,5 +392,8 @@ asmlinkage int do_signal(unsigned long oldmask,
if (single_stepping) {
ptrace_set_bpt(current); /* re-set breakpoint */
}
- return 0;
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
}
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 05dc250f1..b289d4f82 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -10,6 +10,8 @@
* 1995-03-26 Markus Kuhn
* fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
* precision CMOS clock update
+ * 1997-01-09 Adrian Sun
+ * use interval timer if CONFIG_RTC=y
*/
#include <linux/errno.h>
#include <linux/sched.h>
@@ -25,7 +27,11 @@
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
-#define TIMER_IRQ 0
+#ifdef CONFIG_RTC
+#define TIMER_IRQ 0 /* using pit for timer */
+#else
+#define TIMER_IRQ 8 /* using rtc for timer */
+#endif
extern struct hwrpb_struct *hwrpb;
@@ -61,7 +67,7 @@ static inline __u32 rpcc(void)
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-void timer_interrupt(struct pt_regs * regs)
+void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
{
__u32 delta, now;
@@ -125,6 +131,10 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon,
void time_init(void)
{
+#ifdef CONFIG_RTC
+ unsigned char save_control;
+#endif
+ void (*irq_handler)(int, void *, struct pt_regs *);
unsigned int year, mon, day, hour, min, sec;
int i;
@@ -178,6 +188,21 @@ void time_init(void)
state.scaled_ticks_per_cycle = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq;
state.max_cycles_per_tick = (2 * hwrpb->cycle_freq) / HZ;
state.last_rtc_update = 0;
+
+#ifdef CONFIG_RTC
+ /* turn off RTC interrupts before /dev/rtc is initialized */
+ save_control = CMOS_READ(RTC_CONTROL);
+ save_control &= ~RTC_PIE;
+ save_control &= ~RTC_AIE;
+ save_control &= ~RTC_UIE;
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+#endif
+
+ /* setup timer */
+ irq_handler = timer_interrupt;
+ if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL))
+ panic("Could not allocate timer IRQ!");
}
/*
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index a9e0c6cf2..02fa5a35d 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -16,34 +16,54 @@
#include <asm/gentrap.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
+#include <asm/sysinfo.h>
+#include <asm/smp_lock.h>
-void die_if_kernel(char * str, struct pt_regs * regs, long err)
+
+void die_if_kernel(char * str, struct pt_regs * regs, long err,
+ unsigned long *r9_15)
{
long i;
- unsigned long sp;
+ unsigned long sp, ra;
unsigned int * pc;
if (regs->ps & 8)
return;
printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
sp = (unsigned long) (regs+1);
- printk("pc = [<%lx>] ps = %04lx\n", regs->pc, regs->ps);
- printk("rp = [<%lx>] sp = %lx\n", regs->r26, sp);
- printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
- regs->r0, regs->r1, regs->r2, regs->r3);
- printk("r8=%lx\n", regs->r8);
- printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
- regs->r16, regs->r17, regs->r18, regs->r19);
- printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
- regs->r20, regs->r21, regs->r22, regs->r23);
- printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
- regs->r24, regs->r25, regs->r26, regs->r27);
- printk("r28=%lx r29=%lx r30=%lx\n",
- regs->r28, regs->gp, sp);
+ __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);
+
+ 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("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 = %016lx\n", regs->gp, sp);
+
printk("Code:");
pc = (unsigned int *) regs->pc;
- for (i = -3; i < 6; i++)
- printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
+ for (i = -3; i < 6; i++) {
+ unsigned int insn;
+ if (__get_user(insn, pc+i))
+ break;
+ printk("%c%08x%c",i?' ':'<',insn,i?' ':'>');
+ }
printk("\n");
do_exit(SIGSEGV);
}
@@ -64,10 +84,13 @@ asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
return; /* emulation was successful */
}
}
+
+ lock_kernel();
printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
current->comm, regs.pc, summary, write_mask);
- die_if_kernel("Arithmetic fault", &regs, 0);
+ die_if_kernel("Arithmetic fault", &regs, 0, 0);
force_sig(SIGFPE, current);
+ unlock_kernel();
}
asmlinkage void do_entIF(unsigned long type, unsigned long a1,
@@ -76,7 +99,8 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1,
{
extern int ptrace_cancel_bpt (struct task_struct *who);
- die_if_kernel("Instruction fault", &regs, type);
+ lock_kernel();
+ die_if_kernel("Instruction fault", &regs, type, 0);
switch (type) {
case 0: /* breakpoint */
if (ptrace_cancel_bpt(current)) {
@@ -154,6 +178,7 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1,
default:
panic("do_entIF: unexpected instruction-fault type");
}
+ unlock_kernel();
}
/*
@@ -187,21 +212,10 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
unsigned long a3, unsigned long a4, unsigned long a5,
struct allregs regs)
{
- static int cnt = 0;
- static long last_time = 0;
long error, tmp1, tmp2, tmp3, tmp4;
unsigned long pc = regs.pc - 4;
unsigned fixup;
- if (cnt >= 5 && jiffies - last_time > 5*HZ) {
- cnt = 0;
- }
- if (++cnt < 5) {
- printk("kernel: unaligned trap at %016lx: %p %lx %ld\n",
- pc, va, opcode, reg);
- }
- last_time = jiffies;
-
unaligned[0].count++;
unaligned[0].va = (unsigned long) va;
unaligned[0].pc = pc;
@@ -211,7 +225,6 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
exception will we decide whether we should have caught it. */
switch (opcode) {
-#ifdef __HAVE_CPU_BWX
case 0x0c: /* ldwu */
__asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
@@ -224,14 +237,13 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto got_exception;
una_reg(reg) = tmp1|tmp2;
return;
-#endif
case 0x28: /* ldl */
__asm__ __volatile__(
@@ -245,7 +257,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
@@ -265,7 +277,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
@@ -276,7 +288,6 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
/* Note that the store sequences do not indicate that they change
memory because it _should_ be affecting nothing in this context.
(Otherwise we have other, much larger, problems.) */
-#ifdef __HAVE_CPU_BWX
case 0x0d: /* stw */
__asm__ __volatile__(
"1: ldq_u %2,1(%5)\n"
@@ -299,14 +310,13 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
if (error)
goto got_exception;
return;
-#endif
case 0x2c: /* stl */
__asm__ __volatile__(
@@ -330,7 +340,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
@@ -360,7 +370,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
@@ -368,9 +378,12 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
goto got_exception;
return;
}
+
+ lock_kernel();
printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
pc, va, opcode, reg);
do_exit(SIGSEGV);
+ unlock_kernel();
return;
got_exception:
@@ -379,17 +392,23 @@ got_exception:
if ((fixup = search_exception_table(pc)) != 0) {
unsigned long newpc;
newpc = fixup_exception(una_reg, fixup, pc);
+
+ lock_kernel();
printk("Forwarding unaligned exception at %lx (%lx)\n",
pc, newpc);
+ unlock_kernel();
+
(&regs)->pc = newpc;
return;
}
/* Yikes! No one to forward the exception to. */
+ lock_kernel();
printk("%s: unhandled unaligned exception at pc=%lx ra=%lx"
" (bad address = %p)\n", current->comm,
pc, una_reg(26), va);
do_exit(SIGSEGV);
+ unlock_kernel();
}
/*
@@ -409,13 +428,13 @@ static inline unsigned long s_mem_to_reg (unsigned long s_mem)
exp = (exp_msb << 10) | exp_low; /* common case */
if (exp_msb) {
if (exp_low == 0x7f) {
- exp = 0x3ff;
+ exp = 0x7ff;
}
} else {
if (exp_low == 0x00) {
exp = 0x000;
} else {
- exp |= (0x7 << 8);
+ exp |= (0x7 << 7);
}
}
return (sign << 63) | (exp << 52) | (frac << 29);
@@ -449,50 +468,68 @@ static inline unsigned long s_reg_to_mem (unsigned long s_reg)
* uses them as temporary storage for integer memory to memory copies.
* However, we need to deal with stt/ldt and sts/lds only.
*/
-asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg,
- unsigned long * frame)
+
+#define OP_INT_MASK ( 1L << 0x28 | 1L << 0x2c /* ldl stl */ \
+ | 1L << 0x29 | 1L << 0x2d /* ldq stq */ \
+ | 1L << 0x0c | 1L << 0x0d ) /* ldwu stw */
+
+#define OP_WRITE_MASK ( 1L << 0x26 | 1L << 0x27 /* sts stt */ \
+ | 1L << 0x2c | 1L << 0x2d /* stl stq */ \
+ | 1L << 0xd ) /* stw */
+
+asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
+ unsigned long reg, unsigned long * frame)
{
- long dir, size;
- unsigned long *reg_addr, *pc_addr, usp, zero = 0;
- static int cnt = 0;
- static long last_time = 0;
extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
extern unsigned long alpha_read_fp_reg (unsigned long reg);
- pc_addr = frame + 7 + 20 + 1; /* pc in PAL frame */
+ static int cnt = 0;
+ static long last_time = 0;
- if (cnt >= 5 && jiffies - last_time > 5*HZ) {
- cnt = 0;
- }
- if (++cnt < 5) {
- printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
- current->comm, current->pid,
- *pc_addr - 4, va, opcode, reg);
- }
- last_time = jiffies;
+ unsigned long tmp1, tmp2, tmp3, tmp4;
+ unsigned long *reg_addr, *pc_addr, fake_reg;
+ unsigned long uac_bits;
+ long error;
- ++unaligned[1].count;
- unaligned[1].va = (unsigned long) va - 4;
- unaligned[1].pc = *pc_addr;
+ pc_addr = frame + 7 + 20 + 1; /* pc in PAL frame */
+
+ /* Check the UAC bits to decide what the user wants us to do
+ with the unaliged access. */
- dir = VERIFY_READ;
- if (opcode & 0x4) {
- /* it's a stl, stq, stt, or sts */
- dir = VERIFY_WRITE;
+ uac_bits = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
+ if (!(uac_bits & UAC_NOPRINT)) {
+ if (cnt >= 5 && jiffies - last_time > 5*HZ) {
+ cnt = 0;
+ }
+ if (++cnt < 5) {
+ lock_kernel();
+ printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
+ current->comm, current->pid,
+ *pc_addr - 4, va, opcode, reg);
+ unlock_kernel();
+ }
+ last_time = jiffies;
}
- size = 4;
- if (opcode & 0x1) {
- /* it's a quadword op */
- size = 8;
+ if (uac_bits & UAC_SIGBUS) {
+ goto give_sigbus;
}
- if (verify_area(dir, va, size)) {
- *pc_addr -= 4; /* make pc point to faulting insn */
- force_sig(SIGSEGV, current);
+ if (uac_bits & UAC_NOFIX) {
+ /* Not sure why you'd want to use this, but... */
return;
}
+ /* Don't bother reading ds in the access check since we already
+ know that this came from the user. Also rely on the fact that
+ the page at TASK_SIZE is unmapped and so can't be touched anyway. */
+ if (!__access_ok((unsigned long)va, 0, USER_DS))
+ goto give_sigsegv;
+
+ ++unaligned[1].count;
+ unaligned[1].va = (unsigned long)va;
+ unaligned[1].pc = *pc_addr - 4;
+
reg_addr = frame;
- if (opcode >= 0x28) {
+ if ((1L << opcode) & OP_INT_MASK) {
/* it's an integer load/store */
switch (reg) {
case 0: case 1: case 2: case 3: case 4:
@@ -525,57 +562,249 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
case 30:
/* usp in PAL regs */
- usp = rdusp();
- reg_addr = &usp;
+ fake_reg = rdusp();
+ reg_addr = &fake_reg;
break;
case 31:
/* zero "register" */
- reg_addr = &zero;
+ fake_reg = 0;
+ reg_addr = &fake_reg;
break;
}
}
+ /* We don't want to use the generic get/put unaligned macros as
+ we want to trap exceptions. Only if we actually get an
+ exception will we decide whether we should have caught it. */
+
switch (opcode) {
- case 0x22: /* lds */
- alpha_write_fp_reg(reg, s_mem_to_reg(
- get_unaligned((unsigned int *)va)));
- break;
- case 0x26: /* sts */
- put_unaligned(s_reg_to_mem(alpha_read_fp_reg(reg)),
- (unsigned int *)va);
+ case 0x0c: /* ldwu */
+ __asm__ __volatile__(
+ "1: ldq_u %1,0(%3)\n"
+ "2: ldq_u %2,1(%3)\n"
+ " extwl %1,%3,%1\n"
+ " extwh %2,%3,%2\n"
+ "3:\n"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ *reg_addr = tmp1|tmp2;
break;
- case 0x23: /* ldt */
- alpha_write_fp_reg(reg, get_unaligned((unsigned long *)va));
- break;
- case 0x27: /* stt */
- put_unaligned(alpha_read_fp_reg(reg), (unsigned long *)va);
- break;
+ case 0x22: /* lds */
+ __asm__ __volatile__(
+ "1: ldq_u %1,0(%3)\n"
+ "2: ldq_u %2,3(%3)\n"
+ " extll %1,%3,%1\n"
+ " extlh %2,%3,%2\n"
+ "3:\n"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ alpha_write_fp_reg(reg, s_mem_to_reg((int)(tmp1|tmp2)));
+ return;
- case 0x28: /* ldl */
- *reg_addr = get_unaligned((int *)va);
- break;
- case 0x2c: /* stl */
- put_unaligned(*reg_addr, (int *)va);
- break;
+ case 0x23: /* ldt */
+ __asm__ __volatile__(
+ "1: ldq_u %1,0(%3)\n"
+ "2: ldq_u %2,7(%3)\n"
+ " extql %1,%3,%1\n"
+ " extqh %2,%3,%2\n"
+ "3:\n"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ alpha_write_fp_reg(reg, tmp1|tmp2);
+ return;
- case 0x29: /* ldq */
- *reg_addr = get_unaligned((long *)va);
+ case 0x28: /* ldl */
+ __asm__ __volatile__(
+ "1: ldq_u %1,0(%3)\n"
+ "2: ldq_u %2,3(%3)\n"
+ " extll %1,%3,%1\n"
+ " extlh %2,%3,%2\n"
+ "3:\n"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ *reg_addr = (int)(tmp1|tmp2);
break;
- case 0x2d: /* stq */
- put_unaligned(*reg_addr, (long *)va);
+
+ case 0x29: /* ldq */
+ __asm__ __volatile__(
+ "1: ldq_u %1,0(%3)\n"
+ "2: ldq_u %2,7(%3)\n"
+ " extql %1,%3,%1\n"
+ " extqh %2,%3,%2\n"
+ "3:\n"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ *reg_addr = tmp1|tmp2;
break;
- default:
- *pc_addr -= 4; /* make pc point to faulting insn */
- force_sig(SIGBUS, current);
+ /* Note that the store sequences do not indicate that they change
+ memory because it _should_ be affecting nothing in this context.
+ (Otherwise we have other, much larger, problems.) */
+ case 0x0d: /* stw */
+ __asm__ __volatile__(
+ "1: ldq_u %2,1(%5)\n"
+ "2: ldq_u %1,0(%5)\n"
+ " inswh %6,%5,%4\n"
+ " inswl %6,%5,%3\n"
+ " mskwh %2,%5,%2\n"
+ " mskwl %1,%5,%1\n"
+ " or %2,%4,%2\n"
+ " or %1,%3,%1\n"
+ "3: stq_u %2,1(%5)\n"
+ "4: stq_u %1,0(%5)\n"
+ "5:\n"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %2,5b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %1,5b-2b(%0)\n"
+ " .gprel32 3b\n"
+ " lda $31,5b-3b(%0)\n"
+ " .gprel32 4b\n"
+ " lda $31,5b-4b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
+ "=&r"(tmp3), "=&r"(tmp4)
+ : "r"(va), "r"(*reg_addr), "0"(0));
+ if (error)
+ goto give_sigsegv;
return;
- }
- if (opcode >= 0x28 && reg == 30 && dir == VERIFY_WRITE) {
- wrusp(usp);
+ case 0x26: /* sts */
+ fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));
+ reg_addr = &fake_reg;
+ /* FALLTHRU */
+
+ case 0x2c: /* stl */
+ __asm__ __volatile__(
+ "1: ldq_u %2,3(%5)\n"
+ "2: ldq_u %1,0(%5)\n"
+ " inslh %6,%5,%4\n"
+ " insll %6,%5,%3\n"
+ " msklh %2,%5,%2\n"
+ " mskll %1,%5,%1\n"
+ " or %2,%4,%2\n"
+ " or %1,%3,%1\n"
+ "3: stq_u %2,3(%5)\n"
+ "4: stq_u %1,0(%5)\n"
+ "5:\n"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %2,5b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %1,5b-2b(%0)\n"
+ " .gprel32 3b\n"
+ " lda $31,5b-3b(%0)\n"
+ " .gprel32 4b\n"
+ " lda $31,5b-4b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
+ "=&r"(tmp3), "=&r"(tmp4)
+ : "r"(va), "r"(*reg_addr), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ return;
+
+ case 0x27: /* stt */
+ fake_reg = alpha_read_fp_reg(reg);
+ reg_addr = &fake_reg;
+ /* FALLTHRU */
+
+ case 0x2d: /* stq */
+ __asm__ __volatile__(
+ "1: ldq_u %2,7(%5)\n"
+ "2: ldq_u %1,0(%5)\n"
+ " insqh %6,%5,%4\n"
+ " insql %6,%5,%3\n"
+ " mskqh %2,%5,%2\n"
+ " mskql %1,%5,%1\n"
+ " or %2,%4,%2\n"
+ " or %1,%3,%1\n"
+ "3: stq_u %2,7(%5)\n"
+ "4: stq_u %1,0(%5)\n"
+ "5:\n"
+ ".section __ex_table,\"a\"\n\t"
+ " .gprel32 1b\n"
+ " lda %2,5b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %1,5b-2b(%0)\n"
+ " .gprel32 3b\n"
+ " lda $31,5b-3b(%0)\n"
+ " .gprel32 4b\n"
+ " lda $31,5b-4b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
+ "=&r"(tmp3), "=&r"(tmp4)
+ : "r"(va), "r"(*reg_addr), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ return;
+
+ default:
+ /* What instruction were you trying to use, exactly? */
+ goto give_sigbus;
}
+
+ /* Only integer loads should get here; everyone else returns early. */
+ if (reg == 30)
+ wrusp(fake_reg);
+ return;
+
+give_sigsegv:
+ *pc_addr -= 4; /* make pc point to faulting insn */
+ lock_kernel();
+ force_sig(SIGSEGV, current);
+ unlock_kernel();
+ return;
+
+give_sigbus:
+ *pc_addr -= 4;
+ lock_kernel();
+ force_sig(SIGBUS, current);
+ unlock_kernel();
+ return;
}
/*
@@ -593,8 +822,11 @@ 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)
{
- if (regs.r0 != 112)
+ 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;
}
@@ -604,16 +836,11 @@ extern asmlinkage void entArith(void);
extern asmlinkage void entUna(void);
extern asmlinkage void entSys(void);
+register unsigned long gptr __asm__("$29");
+
void trap_init(void)
{
- unsigned long gptr;
-
- /*
- * Tell PAL-code what global pointer we want in the kernel..
- */
- __asm__("br %0,___tmp\n"
- "___tmp:\tldgp %0,0(%0)"
- : "=r" (gptr));
+ /* Tell PAL-code what global pointer we want in the kernel. */
wrkgp(gptr);
wrent(entArith, 1);