diff options
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r-- | arch/alpha/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/alpha/kernel/alpha_ksyms.c | 120 | ||||
-rw-r--r-- | arch/alpha/kernel/bios32.c | 8 | ||||
-rw-r--r-- | arch/alpha/kernel/entry.S | 144 | ||||
-rw-r--r-- | arch/alpha/kernel/head.S | 6 | ||||
-rw-r--r-- | arch/alpha/kernel/irq.c | 66 | ||||
-rw-r--r-- | arch/alpha/kernel/ksyms.c | 112 | ||||
-rw-r--r-- | arch/alpha/kernel/osf_sys.c | 329 | ||||
-rw-r--r-- | arch/alpha/kernel/process.c | 56 | ||||
-rw-r--r-- | arch/alpha/kernel/ptrace.c | 86 | ||||
-rw-r--r-- | arch/alpha/kernel/setup.c | 13 | ||||
-rw-r--r-- | arch/alpha/kernel/signal.c | 192 | ||||
-rw-r--r-- | arch/alpha/kernel/time.c | 29 | ||||
-rw-r--r-- | arch/alpha/kernel/traps.c | 455 |
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(®s); + handle_irq(RTC_IRQ, ®s); return; case 2: machine_check(vector, la_ptr, ®s); 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) { - (®s)->r20 = current->euid; - return current->uid; + 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) { - (®s)->r20 = current->egid; - return current->gid; + 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) { - (®s)->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. + */ + (®s)->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; (®s)->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, ®s); 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(¤t->sigmask_lock); + oldmask = current->blocked; current->blocked = mask & _BLOCKABLE; + spin_unlock_irq(¤t->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", ®s, 0); + die_if_kernel("Arithmetic fault", ®s, 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", ®s, type); + lock_kernel(); + die_if_kernel("Instruction fault", ®s, 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(); + (®s)->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); |