diff options
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/devices.c | 18 | ||||
-rw-r--r-- | arch/sparc/kernel/entry.S | 40 | ||||
-rw-r--r-- | arch/sparc/kernel/head.S | 19 | ||||
-rw-r--r-- | arch/sparc/kernel/irq.c | 201 | ||||
-rw-r--r-- | arch/sparc/kernel/pcic.c | 9 | ||||
-rw-r--r-- | arch/sparc/kernel/process.c | 131 | ||||
-rw-r--r-- | arch/sparc/kernel/ptrace.c | 12 | ||||
-rw-r--r-- | arch/sparc/kernel/setup.c | 24 | ||||
-rw-r--r-- | arch/sparc/kernel/signal.c | 76 | ||||
-rw-r--r-- | arch/sparc/kernel/smp.c | 1 | ||||
-rw-r--r-- | arch/sparc/kernel/sparc_ksyms.c | 7 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4d_irq.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4d_smp.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4m_irq.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/sun4m_smp.c | 6 | ||||
-rw-r--r-- | arch/sparc/kernel/sys_sparc.c | 13 | ||||
-rw-r--r-- | arch/sparc/kernel/systbls.S | 8 | ||||
-rw-r--r-- | arch/sparc/kernel/time.c | 19 | ||||
-rw-r--r-- | arch/sparc/kernel/traps.c | 28 | ||||
-rw-r--r-- | arch/sparc/kernel/unaligned.c | 4 |
21 files changed, 402 insertions, 226 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index d5f65dda3..f4d5e3f67 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.48 1998/09/21 05:04:46 jj Exp $ +# $Id: Makefile,v 1.49 1999/01/02 16:45:37 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index 69f3070e5..11f1587dd 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c @@ -29,24 +29,25 @@ device_scan(unsigned long mem_start)) prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); + prom_printf("Booting Linux...\n"); if(strcmp(node_str, "cpu") == 0) { linux_num_cpus++; } else { int scan; scan = prom_getchild(prom_root_node); - prom_printf("root child is %08lx\n", (unsigned long) scan); + /* One can look it up in PROM instead */ + /* prom_printf("root child is %08lx\n", (unsigned long) scan); */ while((scan = prom_getsibling(scan)) != 0) { prom_getstring(scan, "device_type", node_str, sizeof(node_str)); if(strcmp(node_str, "cpu") == 0) { linux_cpus[linux_num_cpus].prom_node = scan; prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid)); linux_cpus[linux_num_cpus].mid = thismid; - prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", - linux_num_cpus, (unsigned long) scan, - thismid); + /* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid); */ + printk("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid); linux_num_cpus++; } - }; + } if(linux_num_cpus == 0) { if (sparc_cpu_model == sun4d) { scan = prom_getchild(prom_root_node); @@ -59,9 +60,10 @@ device_scan(unsigned long mem_start)) prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid)); linux_cpus[linux_num_cpus].prom_node = node; linux_cpus[linux_num_cpus].mid = thismid; - prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", - linux_num_cpus, (unsigned long) node, - thismid); + /* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", + linux_num_cpus, (unsigned long) node, thismid); */ + printk("Found CPU %d <node=%08lx,mid=%d>\n", + linux_num_cpus, (unsigned long) node, thismid); linux_num_cpus++; } } diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index d628c0c8d..8eeac72b0 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -1,10 +1,10 @@ -/* $Id: entry.S,v 1.153 1998/11/11 15:12:33 jj Exp $ +/* $Id: entry.S,v 1.159 1999/05/08 03:00:03 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) - * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) */ @@ -874,7 +874,7 @@ C_LABEL(vac_hwflush_patch2_on): sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG ! We want error in %l5, vaddr in %l6 sun4c_fault: #ifdef CONFIG_SUN4 - sethi C_LABEL(sun4c_memerr_reg), %l4 + sethi %hi(C_LABEL(sun4c_memerr_reg)), %l4 ld [%l4+%lo(C_LABEL(sun4c_memerr_reg))], %l4 ! memerr ctrl reg addr ld [%l4], %l6 ! memerr ctrl reg ld [%l4 + 4], %l5 ! memerr vaddr reg @@ -956,7 +956,7 @@ sun4c_fault: sll %l6, 2, %l6 ld [%l4 + %l6], %l4 #ifdef CONFIG_SUN4 - sethi PAGE_MASK, %l6 + sethi %hi(PAGE_MASK), %l6 andcc %l4, %l6, %g0 #else andcc %l4, PAGE_MASK, %g0 @@ -1117,7 +1117,7 @@ C_LABEL(num_context_patch2): #ifndef CONFIG_SUN4 and %l4, PAGE_MASK, %l4 #else - sethi PAGE_MASK, %l6 + sethi %hi(PAGE_MASK), %l6 and %l4, %l6, %l4 #endif @@ -1380,11 +1380,13 @@ C_LABEL(sys_rt_sigreturn): /* Now that we have a real sys_clone, sys_fork() is * implemented in terms of it. Our _real_ implementation - * of SunOS vfork() will use sys_clone() instead. + * of SunOS vfork() will use sys_vfork(). + * + * XXX These three should be consolidated into mostly shared + * XXX code just like on sparc64... -DaveM */ .align 4 - .globl C_LABEL(sys_fork), C_LABEL(sys_vfork), flush_patch_two -C_LABEL(sys_vfork): + .globl C_LABEL(sys_fork), flush_patch_two C_LABEL(sys_fork): mov %o7, %l5 flush_patch_two: @@ -1422,6 +1424,23 @@ flush_patch_three: call C_LABEL(do_fork) mov %l5, %o7 + /* Whee, real vfork! */ + .globl C_LABEL(sys_vfork), flush_patch_four +C_LABEL(sys_vfork): +flush_patch_four: + FLUSH_ALL_KERNEL_WINDOWS; + rd %psr, %g4 + WRITE_PAUSE + rd %wim, %g5 + WRITE_PAUSE + std %g4, [%curptr + AOFF_task_tss + AOFF_thread_fork_kpsr] + sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0 + mov %fp, %o1 + or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0 + sethi %hi(C_LABEL(do_fork)), %l1 + jmpl %l1 + %lo(C_LABEL(do_fork)), %g0 + add %sp, REGWIN_SZ, %o2 + .align 4 linux_sparc_ni_syscall: sethi %hi(C_LABEL(sys_ni_syscall)), %l7 @@ -1454,11 +1473,10 @@ C_LABEL(ret_from_syscall): #ifdef __SMP__ .globl C_LABEL(ret_from_smpfork) C_LABEL(ret_from_smpfork): - /* Nowadays all we need to do is drop the scheduler lock. */ - sethi %hi(C_LABEL(scheduler_lock)), %o4 - stb %g0, [%o4 + %lo(C_LABEL(scheduler_lock))] wr %l0, PSR_ET, %psr WRITE_PAUSE + call schedule_tail + mov %g3, %o0 b C_LABEL(ret_sys_call) ld [%sp + REGWIN_SZ + PT_I0], %o0 #endif diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index 9c396c928..0020770e0 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.92 1998/06/10 07:21:55 davem Exp $ +/* $Id: head.S,v 1.95 1999/04/13 07:40:34 anton Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -408,13 +408,11 @@ C_LABEL(trapbase_cpu3): /* This was the only reasonable way I could think of to properly align * these page-table data structures. */ - .globl C_LABEL(bootup_user_stack) .globl C_LABEL(pg0), C_LABEL(pg1), C_LABEL(pg2), C_LABEL(pg3) .globl C_LABEL(empty_bad_page) .globl C_LABEL(empty_bad_page_table) .globl C_LABEL(empty_zero_page) .globl C_LABEL(swapper_pg_dir) -C_LABEL(bootup_user_stack): .skip 0x2000 C_LABEL(swapper_pg_dir): .skip PAGE_SIZE C_LABEL(pg0): .skip PAGE_SIZE C_LABEL(pg1): .skip PAGE_SIZE @@ -427,8 +425,8 @@ C_LABEL(empty_zero_page): .skip PAGE_SIZE .global C_LABEL(root_flags) .global C_LABEL(ram_flags) .global C_LABEL(root_dev) - .global C_LABEL(ramdisk_image) - .global C_LABEL(ramdisk_size) + .global C_LABEL(sparc_ramdisk_image) + .global C_LABEL(sparc_ramdisk_size) /* This stuff has to be in sync with SILO and other potential boot loaders * Fields should be kept upward compatible and whenever any change is made, @@ -443,9 +441,9 @@ C_LABEL(root_dev): .half 0 C_LABEL(ram_flags): .half 0 -C_LABEL(ramdisk_image): +C_LABEL(sparc_ramdisk_image): .word 0 -C_LABEL(ramdisk_size): +C_LABEL(sparc_ramdisk_size): .word 0 .word C_LABEL(reboot_command) @@ -1005,8 +1003,8 @@ sun4c_continue_boot: WRITE_PAUSE /* I want a kernel stack NOW! */ - set C_LABEL(bootup_user_stack), %g1 - set (0x2000 - REGWIN_SZ), %g2 + set C_LABEL(init_task_union), %g1 + set (TASK_UNION_SIZE - REGWIN_SZ), %g2 add %g1, %g2, %sp mov 0, %fp /* And for good luck */ @@ -1110,6 +1108,9 @@ sun4c_continue_boot: set flush_patch_three, %g5 st %g4, [%g5 + 0x18] st %g4, [%g5 + 0x1c] + set flush_patch_four, %g5 + st %g4, [%g5 + 0x18] + st %g4, [%g5 + 0x1c] set flush_patch_exception, %g5 st %g4, [%g5 + 0x18] st %g4, [%g5 + 0x1c] diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 4c8f78c8a..26f3194bd 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj Exp $ +/* $Id: irq.c,v 1.93 1999/04/21 06:15:45 anton Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -8,7 +8,7 @@ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com) * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) - * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au) */ #include <linux/config.h> @@ -24,6 +24,8 @@ #include <linux/init.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/delay.h> +#include <linux/tasks.h> #include <asm/ptrace.h> #include <asm/processor.h> @@ -192,12 +194,18 @@ void free_irq(unsigned int irq, void *dev_id) restore_flags(flags); } -/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */ +#ifndef __SMP__ +unsigned int local_bh_count; +unsigned int local_irq_count; + +#else +/* SMP interrupt locking on Sparc. */ + unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -#ifdef __SMP__ -/* SMP interrupt locking on Sparc. */ +atomic_t global_bh_lock = ATOMIC_INIT(0); +spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED; /* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; @@ -208,58 +216,71 @@ spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); -atomic_t global_bh_count = ATOMIC_INIT(0); -atomic_t global_bh_lock = ATOMIC_INIT(0); - /* This protects BH software state (masks, things like that). */ spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED; -#ifdef DEBUG_IRQLOCK +void smp_show_backtrace_all_cpus(void); +void show_backtrace(void); -#undef INIT_STUCK -#define INIT_STUCK 100000000 +#define MAXCOUNT 100000000 +#define VERBOSE_DEBUG_IRQLOCK -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("wait_on_bh CPU#%d stuck at %08lx\n", cpu, where); stuck = INIT_STUCK; } - -static inline void wait_on_bh(int cpu, unsigned long where) +static void show(char * str) { - int stuck = INIT_STUCK; - do { - STUCK; - /* nothing .. wait for the other bh's to go away */ - } while (atomic_read(&global_bh_count) != 0); -} + int i; + int cpu = smp_processor_id(); + + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [ ", atomic_read(&global_irq_count)); -static unsigned long previous_irqholder; + for (i = 0; i < NR_CPUS; i++) { + printk("%d ", local_irq_count[i]); + } + printk("]\n"); -#undef INIT_STUCK -#define INIT_STUCK 100000000 + printk("bh: %d [ ", (spin_is_locked(&global_bh_count) ? 1 : 0)); -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } + for (i = 0; i < NR_CPUS; i++) { + printk("%d ", local_bh_count[cpu]); + } + printk("]\n"); + +#ifdef VERBOSE_DEBUG_IRQLOCK + smp_show_backtrace_all_cpus(); +#else + show_backtrace(); +#endif +} + +static inline void wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if(!--count) { + show("wait_on_bh"); + count = 0; + } + barrier(); + } while(spin_is_locked(&global_bh_count)); +} /* * We have to allow irqs to arrive between __sti and __cli */ -#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") +#define SYNC_OTHER_CORES(x) udelay(x+1) -static inline void wait_on_irq(int cpu, unsigned long where) +static inline void wait_on_irq(int cpu) { - int stuck = INIT_STUCK; - int local_count = local_irq_count[cpu]; + int count = MAXCOUNT; for (;;) { - /* * Wait until all interrupts are gone. Wait * for bottom half handlers unless we're * already executing in one.. */ if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + if (local_bh_count[cpu] || !spin_is_locked(&global_bh_count)) break; } @@ -267,17 +288,18 @@ static inline void wait_on_irq(int cpu, unsigned long where) spin_unlock(&global_irq_lock); for (;;) { - STUCK; - + if (!--count) { + show("wait_on_irq"); + count = ~0; + } __sti(); SYNC_OTHER_CORES(cpu); __cli(); - if (atomic_read(&global_irq_count)) continue; - if (*((unsigned char *)&global_irq_lock)) + if (spin_is_locked (&global_irq_lock)) continue; - if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + if (!local_bh_count[cpu] && spin_is_locked(&global_bh_count)) continue; if (spin_trylock(&global_irq_lock)) break; @@ -295,14 +317,8 @@ static inline void wait_on_irq(int cpu, unsigned long where) */ void synchronize_bh(void) { - unsigned long where; - - __asm__("mov %%i7, %0" : "=r" (where)); - - if (atomic_read(&global_bh_count) && !in_interrupt()) { - int cpu = smp_processor_id(); - wait_on_bh(cpu, where); - } + if (spin_is_locked (&global_bh_count) && !in_interrupt()) + wait_on_bh(); } /* @@ -321,16 +337,9 @@ void synchronize_irq(void) } } -#undef INIT_STUCK -#define INIT_STUCK 10000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} - -static inline void get_irqlock(int cpu, unsigned long where) +static inline void get_irqlock(int cpu) { - int stuck = INIT_STUCK; + int count = MAXCOUNT; if (!spin_trylock(&global_irq_lock)) { /* do we already hold the lock? */ @@ -338,23 +347,25 @@ static inline void get_irqlock(int cpu, unsigned long where) return; /* Uhhuh.. Somebody else got it. Wait.. */ do { - do { - STUCK; + while (spin_is_locked(&global_irq_lock)) { + if (!--count) { + show("get_irqlock"); + count = ~0; + } barrier(); - } while (*((volatile unsigned char *)&global_irq_lock)); + } } while (!spin_trylock(&global_irq_lock)); } /* * We also to make sure that nobody else is running * in an interrupt context. */ - wait_on_irq(cpu, where); + wait_on_irq(cpu); /* * Ok, finally.. */ global_irq_holder = cpu; - previous_irqholder = where; } /* @@ -372,9 +383,6 @@ static inline void get_irqlock(int cpu, unsigned long where) void __global_cli(void) { unsigned int flags; - unsigned long where; - - __asm__("mov %%i7, %0" : "=r" (where)); __save_flags(flags); @@ -382,7 +390,7 @@ void __global_cli(void) int cpu = smp_processor_id(); __cli(); if (!local_irq_count[cpu]) - get_irqlock(cpu, where); + get_irqlock(cpu); } } @@ -442,65 +450,14 @@ void __global_restore_flags(unsigned long flags) __sti(); break; default: - printk("global_restore_flags: %08lx (%08lx)\n", - flags, (&flags)[-1]); + { + unsigned long pc; + __asm__ __volatile__("mov %%i7, %0" : "=r" (pc)); + printk("global_restore_flags: Bogon flags(%08lx) caller %08lx\n", flags, pc); } -} - -#undef INIT_STUCK -#define INIT_STUCK 200000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;} - -#define VERBOSE_IRQLOCK_DEBUGGING - -void irq_enter(int cpu, int irq, void *_opaque) -{ -#ifdef VERBOSE_IRQLOCK_DEBUGGING - extern void smp_show_backtrace_all_cpus(void); -#endif - int stuck = INIT_STUCK; - - hardirq_enter(cpu); - barrier(); - while (*((volatile unsigned char *)&global_irq_lock)) { - if ((unsigned char) cpu == global_irq_holder) { - struct pt_regs *regs = _opaque; - int sbh_cnt = atomic_read(&global_bh_count); - int globl_locked = *((unsigned char *)&global_irq_lock); - int globl_icount = atomic_read(&global_irq_count); - int local_count = local_irq_count[cpu]; - unsigned long pc = regs->pc; - - /* It is very important that we load the state variables - * before we do the first call to printk() as printk() - * could end up changing them... - */ - - printk("CPU[%d]: BAD! Local IRQ's enabled, global disabled " - "interrupt at PC[%08lx]\n", cpu, pc); - printk("CPU[%d]: bhcnt[%d] glocked[%d] gicnt[%d] licnt[%d]\n", - cpu, sbh_cnt, globl_locked, globl_icount, local_count); -#ifdef VERBOSE_IRQLOCK_DEBUGGING - printk("Performing backtrace on all cpus, write this down!\n"); - smp_show_backtrace_all_cpus(); -#endif - break; - } - STUCK; - barrier(); } } -void irq_exit(int cpu, int irq) -{ - hardirq_exit(cpu); - release_irqlock(cpu); -} - -#endif /* DEBUG_IRQLOCK */ #endif /* __SMP__ */ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs) @@ -542,7 +499,7 @@ void handler_irq(int irq, struct pt_regs * regs) smp4m_irq_rotate(cpu); #endif #endif - irq_enter(cpu, irq, regs); + irq_enter(cpu, irq); action = *(irq + irq_action); kstat.irqs[cpu][irq]++; do { @@ -563,7 +520,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) int cpu = smp_processor_id(); disable_pil_irq(irq); - irq_enter(cpu, irq, regs); + irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; floppy_interrupt(irq, dev_id, regs); irq_exit(cpu, irq); diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index aae13c515..a2beedbf1 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $ +/* $Id: pcic.c,v 1.5 1999/03/16 00:15:20 davem Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -498,9 +498,10 @@ static void pci_do_settimeofday(struct timeval *tv) tv->tv_sec--; } xtime = *tv; - time_state = TIME_BAD; - time_maxerror = 0x70000000; - time_esterror = 0x70000000; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; sti(); } diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 3aeee6f6b..301747c22 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.126 1998/09/21 05:05:18 jj Exp $ +/* $Id: process.c,v 1.137 1999/05/08 03:00:10 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -62,7 +62,9 @@ asmlinkage int sys_idle(void) /* endless idle loop with no priority at all */ current->priority = 0; - current->counter = 0; + current->counter = -100; + init_idle(); + for (;;) { if (ARCH_SUN4C_SUN4) { static int count = HZ; @@ -108,13 +110,17 @@ out: /* This is being executed in task 0 'user space'. */ int cpu_idle(void *unused) { + /* endless idle loop with no priority at all */ current->priority = 0; + current->counter = -100; + init_idle(); + while(1) { - check_pgt_cache(); - run_task_queue(&tq_scheduler); - /* endless idle loop with no priority at all */ - current->counter = 0; - schedule(); + if(current->need_resched) { + schedule(); + check_pgt_cache(); + } + barrier(); /* or else gcc optimizes... */ } } @@ -203,8 +209,10 @@ void __show_backtrace(unsigned long fp) int cpu = smp_processor_id(); spin_lock_irqsave(&sparc_backtrace_lock, flags); - rw = (struct reg_window *) fp; - while(rw) { + + rw = (struct reg_window *)fp; + while(rw && (((unsigned long) rw) >= PAGE_OFFSET) && + !(((unsigned long) rw) & 0x7)) { printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] " "FP[%08lx] CALLER[%08lx]\n", cpu, rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], @@ -216,28 +224,21 @@ void __show_backtrace(unsigned long fp) spin_unlock_irqrestore(&sparc_backtrace_lock, flags); } +#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t") +#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t") +#define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp)) + void show_backtrace(void) { unsigned long fp; - __asm__ __volatile__( - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "save %%sp, -64, %%sp\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "restore\n\t" - "mov %%i6, %0" : "=r" (fp)); + __SAVE; __SAVE; __SAVE; __SAVE; + __SAVE; __SAVE; __SAVE; __SAVE; + __RESTORE; __RESTORE; __RESTORE; __RESTORE; + __RESTORE; __RESTORE; __RESTORE; __RESTORE; + + __GET_FP(fp); + __show_backtrace(fp); } @@ -379,8 +380,21 @@ void flush_thread(void) current->tss.current_ds = USER_DS; if (current->tss.flags & SPARC_FLAG_KTHREAD) { current->tss.flags &= ~SPARC_FLAG_KTHREAD; - switch_to_context(current); + + /* We must fixup kregs as well. */ + current->tss.kregs = (struct pt_regs *) + (((unsigned long)current) + + (TASK_UNION_SIZE - TRACEREG_SZ)); } + + /* Exec'ing out of a vfork() shared address space is + * tricky on sparc32. exec_mmap will not set the mmu + * context because it sets the new current->mm after + * calling init_new_context and activate_context is + * a nop on sparc32, so we gotta catch it here. And + * clone()'s had the same problem. -DaveM + */ + switch_to_context(current); } static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src) @@ -440,10 +454,17 @@ clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src) size = ((unsigned long)src->fp) - ((unsigned long)src); sp = (struct sparc_stackf *)(((unsigned long)dst) - size); + /* do_fork() grabs the parent semaphore, we must release it + * temporarily so we can build the child clone stack frame + * without deadlocking. + */ + up(¤t->mm->mmap_sem); if (copy_to_user(sp, src, size)) - return 0; - if (put_user(dst, &sp->fp)) - return 0; + sp = (struct sparc_stackf *) 0; + else if (put_user(dst, &sp->fp)) + sp = (struct sparc_stackf *) 0; + down(¤t->mm->mmap_sem); + return sp; } @@ -505,14 +526,24 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, p->tss.kpsr = current->tss.fork_kpsr; #endif p->tss.kwim = current->tss.fork_kwim; - p->tss.kregs = childregs; if(regs->psr & PSR_PS) { - childregs->u_regs[UREG_FP] = p->tss.ksp; + extern struct pt_regs fake_swapper_regs; + + p->tss.kregs = &fake_swapper_regs; + new_stack = (struct reg_window *) + ((((unsigned long)p) + + (TASK_UNION_SIZE)) - + (REGWIN_SZ)); + childregs->u_regs[UREG_FP] = (unsigned long) new_stack; p->tss.flags |= SPARC_FLAG_KTHREAD; p->tss.current_ds = KERNEL_DS; + memcpy((void *)new_stack, + (void *)regs->u_regs[UREG_FP], + sizeof(struct reg_window)); childregs->u_regs[UREG_G6] = (unsigned long) p; } else { + p->tss.kregs = childregs; childregs->u_regs[UREG_FP] = sp; p->tss.flags &= ~SPARC_FLAG_KTHREAD; p->tss.current_ds = USER_DS; @@ -658,3 +689,37 @@ out: unlock_kernel(); return error; } + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ +pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + + __asm__ __volatile("mov %4, %%g2\n\t" /* Set aside fn ptr... */ + "mov %5, %%g3\n\t" /* and arg. */ + "mov %1, %%g1\n\t" + "mov %2, %%o0\n\t" /* Clone flags. */ + "mov 0, %%o1\n\t" /* usp arg == 0 */ + "t 0x10\n\t" /* Linux/Sparc clone(). */ + "cmp %%o1, 0\n\t" + "be 1f\n\t" /* The parent, just return. */ + " nop\n\t" /* Delay slot. */ + "jmpl %%g2, %%o7\n\t" /* Call the function. */ + " mov %%g3, %%o0\n\t" /* Get back the arg in delay. */ + "mov %3, %%g1\n\t" + "t 0x10\n\t" /* Linux/Sparc exit(). */ + /* Notreached by child. */ + "1: mov %%o0, %0\n\t" : + "=r" (retval) : + "i" (__NR_clone), "r" (flags | CLONE_VM), + "i" (__NR_exit), "r" (fn), "r" (arg) : + "g1", "g2", "g3", "o0", "o1", "memory", "cc"); + return retval; +} diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index ed8fe6a25..7f6ec54f9 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -528,6 +528,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if (((current->personality & PER_BSD) && (request == PTRACE_SUNATTACH)) || (!(current->personality & PER_BSD) && (request == PTRACE_ATTACH))) { + unsigned long flags; + if(child == current) { /* Try this under SunOS/Solaris, bwa haha * You'll never be able to kill the process. ;-) @@ -539,8 +541,9 @@ asmlinkage void do_ptrace(struct pt_regs *regs) (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && - !capable(CAP_SYS_PTRACE)) { + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); goto out; } @@ -550,14 +553,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } child->flags |= PF_PTRACED; + write_lock_irqsave(&tasklist_lock, flags); if(child->p_pptr != current) { - unsigned long flags; - write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); - write_unlock_irqrestore(&tasklist_lock, flags); } + write_unlock_irqrestore(&tasklist_lock, flags); send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); goto out; diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 84190cf5a..d29c1cb66 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.103 1998/09/21 05:05:23 jj Exp $ +/* $Id: setup.c,v 1.105 1999/04/13 14:17:08 jj Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -271,8 +271,8 @@ extern unsigned long sun_serial_setup(unsigned long); extern unsigned short root_flags; extern unsigned short root_dev; extern unsigned short ram_flags; -extern unsigned ramdisk_image; -extern unsigned ramdisk_size; +extern unsigned sparc_ramdisk_image; +extern unsigned sparc_ramdisk_size; #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 @@ -285,7 +285,7 @@ enum sparc_cpu sparc_cpu_model; struct tt_entry *sparc_ttable; -static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } }; +struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } }; static void prom_cons_write(struct console *con, const char *str, unsigned count) { @@ -375,7 +375,7 @@ __initfunc(void setup_arch(char **cmdline_p, sun4c_probe_vac(); load_mmu(); total = prom_probe_memory(); - *memory_start_p = (((unsigned long) &end)); + *memory_start_p = PAGE_ALIGN(((unsigned long) &end)); if(!packed) { for(i=0; sp_banks[i].num_bytes != 0; i++) { @@ -404,10 +404,10 @@ __initfunc(void setup_arch(char **cmdline_p, rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); #endif #ifdef CONFIG_BLK_DEV_INITRD - if (ramdisk_image) { - initrd_start = ramdisk_image; + if (sparc_ramdisk_image) { + initrd_start = sparc_ramdisk_image; if (initrd_start < KERNBASE) initrd_start += KERNBASE; - initrd_end = initrd_start + ramdisk_size; + initrd_end = initrd_start + sparc_ramdisk_size; if (initrd_end > *memory_end_p) { printk(KERN_CRIT "initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)\ndisabling initrd\n", @@ -417,6 +417,14 @@ __initfunc(void setup_arch(char **cmdline_p, if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) { initrd_below_start_ok = 1; *memory_start_p = PAGE_ALIGN (initrd_end); + } else if (initrd_start && sparc_ramdisk_image < KERNBASE) { + switch (sparc_cpu_model) { + case sun4m: + case sun4d: + initrd_start -= KERNBASE; + initrd_end -= KERNBASE; + break; + } } } #endif diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 287ed6cdc..e6023f43b 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $ +/* $Id: signal.c,v 1.91 1999/01/26 11:00:44 jj Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -38,6 +38,8 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, /* This turned off for production... */ /* #define DEBUG_SIGNALS 1 */ +/* #define DEBUG_SIGNALS_TRACE 1 */ +/* #define DEBUG_SIGNALS_MAPS 1 */ /* Signal frames: the original one (compatible with SunOS): * @@ -1004,6 +1006,59 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, } } +#ifdef DEBUG_SIGNALS_MAPS + +#define MAPS_LINE_FORMAT "%08lx-%08lx %s %08lx %s %lu " + +static inline void read_maps (void) +{ + struct vm_area_struct * map, * next; + char * buffer; + ssize_t i; + + buffer = (char*)__get_free_page(GFP_KERNEL); + if (!buffer) + return; + + for (map = current->mm->mmap ; map ; map = next ) { + /* produce the next line */ + char *line; + char str[5], *cp = str; + int flags; + kdev_t dev; + unsigned long ino; + + /* + * Get the next vma now (but it won't be used if we sleep). + */ + next = map->vm_next; + flags = map->vm_flags; + + *cp++ = flags & VM_READ ? 'r' : '-'; + *cp++ = flags & VM_WRITE ? 'w' : '-'; + *cp++ = flags & VM_EXEC ? 'x' : '-'; + *cp++ = flags & VM_MAYSHARE ? 's' : 'p'; + *cp++ = 0; + + dev = 0; + ino = 0; + if (map->vm_file != NULL) { + dev = map->vm_file->f_dentry->d_inode->i_dev; + ino = map->vm_file->f_dentry->d_inode->i_ino; + line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE); + } + printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_offset, + kdevname(dev), ino); + if (map->vm_file != NULL) + printk("%s\n", line); + else + printk("\n"); + } + free_page((unsigned long)buffer); + return; +} +#endif + /* Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. @@ -1115,8 +1170,25 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ - printk ("Sig ILL going...\n"); + printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); show_regs (regs); +#ifdef DEBUG_SIGNALS_TRACE + { + struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP]; + unsigned int ins[8]; + + while(rw && + !(((unsigned long) rw) & 0x3)) { + copy_from_user(ins, &rw->ins[0], sizeof(ins)); + printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]); + rw = (struct reg_window *)(unsigned long)ins[6]; + } + } +#endif +#ifdef DEBUG_SIGNALS_MAPS + printk("Maps:\n"); + read_maps(); +#endif #endif /* fall through */ default: diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index f77d823aa..fb55c1ffa 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -52,6 +52,7 @@ unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */ int smp_activated = 0; volatile int cpu_number_map[NR_CPUS]; volatile int __cpu_logical_map[NR_CPUS]; +cycles_t cacheflush_time = 0; /* XXX */ /* The only guaranteed locking primitive available on all Sparc * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 43f963217..b043d647d 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.73 1998/11/06 13:49:54 jj Exp $ +/* $Id: sparc_ksyms.c,v 1.77 1999/03/21 06:37:43 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -66,6 +66,7 @@ extern char saved_command_line[]; extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); +extern int __lshrdi3(int, int); extern void dump_thread(struct pt_regs *, struct user *); @@ -91,6 +92,7 @@ __attribute__((section("__ksymtab"))) = \ /* used by various drivers */ EXPORT_SYMBOL(sparc_cpu_model); EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor); +EXPORT_SYMBOL(kernel_thread); #ifdef SPIN_LOCK_DEBUG EXPORT_SYMBOL(_do_spin_lock); EXPORT_SYMBOL(_do_spin_unlock); @@ -118,6 +120,7 @@ EXPORT_SYMBOL_PRIVATE(_global_cli); #endif EXPORT_SYMBOL(page_offset); +EXPORT_SYMBOL(sparc_valid_addr_bitmap); #ifndef CONFIG_SUN4 EXPORT_SYMBOL(stack_top); @@ -211,6 +214,7 @@ EXPORT_SYMBOL(saved_command_line); EXPORT_SYMBOL(prom_apply_obio_ranges); EXPORT_SYMBOL(prom_getname); EXPORT_SYMBOL(prom_feval); +EXPORT_SYMBOL(prom_getbool); EXPORT_SYMBOL(prom_getstring); EXPORT_SYMBOL(prom_apply_sbus_ranges); EXPORT_SYMBOL(prom_getint); @@ -268,6 +272,7 @@ EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__lshrdi3); EXPORT_SYMBOL_DOT(rem); EXPORT_SYMBOL_DOT(urem); diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 93474714a..1d0de8d23 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -1,4 +1,4 @@ -/* $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $ +/* $Id: sun4d_irq.c,v 1.18 1999/04/20 13:22:30 anton Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -193,7 +193,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs) cc_set_iclr(1 << irq); - irq_enter(cpu, irq, regs); + irq_enter(cpu, irq); kstat.irqs[cpu][irq]++; if (!sbusl) { action = *(irq + irq_action); diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index af0aaf58d..edd736b41 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -190,6 +190,7 @@ __initfunc(void smp4d_boot_cpus(void)) current->processor = boot_cpu_id; smp_store_cpu_info(boot_cpu_id); smp_setup_percpu_timer(); + init_idle(); local_flush_cache_all(); if(linux_num_cpus == 1) return; /* Not an MP box. */ @@ -211,6 +212,7 @@ __initfunc(void smp4d_boot_cpus(void)) p = task[++cpucount]; p->processor = i; + p->has_cpu = 1; /* we schedule the first task manually */ current_set[i] = p; for (no = 0; no < linux_num_cpus; no++) diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index bd6fc8e20..4d7177dac 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -253,7 +253,7 @@ __initfunc(static void sun4m_init_timers(void (*counter_fn)(int, void *, struct /* Map the per-cpu Counter registers. */ sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0, - PAGE_SIZE*NCPUS, "counters_percpu", + PAGE_SIZE*SUN4M_NCPUS, "counters_percpu", cnt_regs[0].which_io, 0x0); /* Map the system Counter register. */ @@ -334,7 +334,7 @@ __initfunc(void sun4m_init_IRQ(void)) /* Map the interrupt registers for all possible cpus. */ sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0, - PAGE_SIZE*NCPUS, "interrupts_percpu", + PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu", int_regs[0].which_io, 0x0); /* Map the system interrupt control registers. */ diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 183ea7323..c9acf609c 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -161,6 +161,7 @@ __initfunc(void smp4m_boot_cpus(void)) smp_store_cpu_info(boot_cpu_id); set_irq_udt(mid_xlate[boot_cpu_id]); smp_setup_percpu_timer(); + init_idle(); local_flush_cache_all(); if(linux_num_cpus == 1) return; /* Not an MP box. */ @@ -180,6 +181,7 @@ __initfunc(void smp4m_boot_cpus(void)) p = task[++cpucount]; p->processor = i; + p->has_cpu = 1; /* we schedule the first task manually */ current_set[i] = p; /* See trampoline.S for details... */ @@ -448,6 +450,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) if(!--prof_counter[cpu]) { int user = user_mode(regs); + irq_enter(cpu, 0); if(current->pid) { update_one_process(current, 1, user, !user, cpu); @@ -456,7 +459,6 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) current->need_resched = 1; } - spin_lock(&ticker_lock); if(user) { if(current->priority < DEF_PRIORITY) { kstat.cpu_nice++; @@ -469,9 +471,9 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) kstat.cpu_system++; kstat.per_cpu_system[cpu]++; } - spin_unlock(&ticker_lock); } prof_counter[cpu] = prof_multiplier[cpu]; + irq_exit(cpu, 0); } } diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index e5ea2e9b3..ed3918c10 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $ +/* $Id: sys_sparc.c,v 1.52 1999/05/08 08:09:48 anton Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -25,6 +25,8 @@ #include <asm/uaccess.h> #include <asm/ipc.h> +/* #define DEBUG_UNIMP_SYSCALL */ + /* XXX Make this per-binary type, this way we can detect the type of * XXX a binary. Every Sparc executable calls this very early on. */ @@ -189,6 +191,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, goto out; } retval = -ENOMEM; + len = PAGE_ALIGN(len); if(!(flags & MAP_FIXED) && !addr) { addr = get_unmapped_area(addr, len); if(!addr) @@ -202,6 +205,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, if(ARCH_SUN4C_SUN4) { if(((addr >= 0x20000000) && (addr < 0xe0000000))) { + /* VM hole */ retval = current->mm->brk; goto out_putf; } @@ -223,9 +227,14 @@ out: asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) { + static int count = 0; + + if (count++ > 5) return -ENOSYS; lock_kernel(); - printk ("Unimplemented SPARC system call %d\n",(int)regs->u_regs[1]); + printk ("%s[%d]: Unimplemented SPARC system call %d\n", current->comm, current->pid, (int)regs->u_regs[1]); +#ifdef DEBUG_UNIMP_SYSCALL show_regs (regs); +#endif unlock_kernel(); return -ENOSYS; } diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 5508f850a..4d0dfff5f 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.80 1998/09/21 05:04:59 jj Exp $ +/* $Id: systbls.S,v 1.83 1999/04/07 17:14:06 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -25,7 +25,7 @@ sys_call_table: /*30*/ .long sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice /*35*/ .long sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile /*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall -/*45*/ .long sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid +/*45*/ .long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl /*55*/ .long sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve /*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize @@ -47,7 +47,7 @@ sys_call_table: /*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit /*145*/ .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall -/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount +/*155*/ .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount /*160*/ .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall /*165*/ .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall /*170*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents @@ -129,7 +129,7 @@ sunos_sys_table: /*150*/ .long sys_getsockname, sunos_nosys, sunos_nosys .long sys_poll, sunos_nosys, sunos_nosys .long sunos_getdirentries, sys_statfs, sys_fstatfs - .long sys_umount, sunos_nosys, sunos_nosys + .long sys_oldumount, sunos_nosys, sunos_nosys .long sys_getdomainname, sys_setdomainname .long sunos_nosys, sys_quotactl, sunos_nosys .long sunos_mount, sys_ustat, sunos_semsys diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 9e5afcfcf..633ef2adb 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.39 1998/09/29 09:46:15 davem Exp $ +/* $Id: time.c,v 1.43 1999/03/15 22:13:31 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -39,6 +39,8 @@ #include <asm/sun4paddr.h> #include <asm/page.h> +extern rwlock_t xtime_lock; + enum sparc_clock_type sp_clock_typ; struct mostek48t02 *mstk48t02_regs = 0; struct mostek48t08 *mstk48t08_regs = 0; @@ -80,7 +82,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) #ifdef CONFIG_SUN4 if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) || - (idprom->id_machtype == (SM_SUN4 | SM_4_110))) { + (idprom->id_machtype == (SM_SUN4 | SM_4_110))) { int temp; intersil_read_intr(intersil_clock, temp); /* re-enable the irq */ @@ -89,6 +91,8 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) #endif clear_clock_irq(); + write_lock(&xtime_lock); + do_timer(regs); /* Determine when to update the Mostek clock. */ @@ -101,6 +105,7 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } + write_unlock(&xtime_lock); } /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. @@ -436,6 +441,9 @@ extern __inline__ unsigned long do_gettimeoffset(void) return offset + count; } +/* This need not obtain the xtime_lock as it is coded in + * an implicitly SMP safe way already. + */ void do_gettimeofday(struct timeval *tv) { #if CONFIG_AP1000 @@ -485,12 +493,13 @@ void do_gettimeofday(struct timeval *tv) void do_settimeofday(struct timeval *tv) { + write_lock_irq(&xtime_lock); bus_do_settimeofday(tv); + write_unlock_irq(&xtime_lock); } static void sbus_do_settimeofday(struct timeval *tv) { - cli(); #if !CONFIG_AP1000 tv->tv_usec -= do_gettimeoffset(); if(tv->tv_usec < 0) { @@ -501,10 +510,8 @@ static void sbus_do_settimeofday(struct timeval *tv) xtime = *tv; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; - time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); } /* @@ -544,7 +551,7 @@ static int set_rtc_mmss(unsigned long nowtime) } else { printk(KERN_WARNING "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); + mostek_minutes, real_minutes); return -1; } diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c index 86d632409..b9afa02f7 100644 --- a/arch/sparc/kernel/traps.c +++ b/arch/sparc/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.57 1998/09/17 11:04:51 jj Exp $ +/* $Id: traps.c,v 1.59 1999/03/06 12:07:31 anton Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -82,8 +82,13 @@ void instruction_dump (unsigned long *pc) printk("\n"); } +#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t") +#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t") + void die_if_kernel(char *str, struct pt_regs *regs) { + int count = 0; + /* Amuse the user. */ printk( " \\|/ ____ \\|/\n" @@ -93,6 +98,27 @@ void die_if_kernel(char *str, struct pt_regs *regs) printk("%s(%d): %s\n", current->comm, current->pid, str); show_regs(regs); + + __SAVE; __SAVE; __SAVE; __SAVE; + __SAVE; __SAVE; __SAVE; __SAVE; + __RESTORE; __RESTORE; __RESTORE; __RESTORE; + __RESTORE; __RESTORE; __RESTORE; __RESTORE; + + { + struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP]; + + /* Stop the back trace when we hit userland or we + * find some badly aligned kernel stack. Set an upper + * bound in case our stack is trashed and we loop. + */ + while(rw && + count++ < 30 && + (((unsigned long) rw) >= PAGE_OFFSET) && + !(((unsigned long) rw) & 0x7)) { + printk("Caller[%08lx]\n", rw->ins[7]); + rw = (struct reg_window *)rw->ins[6]; + } + } printk("Instruction DUMP:"); instruction_dump ((unsigned long *) regs->pc); if(regs->psr & PSR_PS) diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c index 1fb434b49..a683efb3e 100644 --- a/arch/sparc/kernel/unaligned.c +++ b/arch/sparc/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.17 1997/04/11 00:42:08 davem Exp $ +/* $Id: unaligned.c,v 1.18 1999/04/03 11:36:17 anton Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -332,7 +332,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) enum direction dir = decode_direction(insn); int size = decode_access_size(insn); - lock_kernel(); if(!ok_for_kernel(insn) || dir == both) { printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n", regs->pc); @@ -380,7 +379,6 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) } advance(regs); } - unlock_kernel(); } static inline int ok_for_user(struct pt_regs *regs, unsigned int insn, |