diff options
Diffstat (limited to 'arch')
191 files changed, 14978 insertions, 8068 deletions
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index f5a79996c..5d21e075b 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.7 1998/06/30 00:21:54 ralf Exp $ +# $Id: Makefile,v 1.8 1998/10/18 13:21:50 tsbogend Exp $ # # Makefile for MIPS-specific library files.. # @@ -10,7 +10,7 @@ L_TARGET = lib.a L_OBJS = csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ - floppy-no.o ide-std.o ide-no.o rtc-std.o rtc-no.o memset.o memcpy.o \ - strlen_user.o strncpy_user.o watch.o + floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \ + rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o watch.o include $(TOPDIR)/Rules.make diff --git a/arch/mips/lib/floppy-std.c b/arch/mips/lib/floppy-std.c index 04b32f40a..3d1c95feb 100644 --- a/arch/mips/lib/floppy-std.c +++ b/arch/mips/lib/floppy-std.c @@ -1,4 +1,4 @@ -/* $Id: floppy-std.c,v 1.2 1998/05/28 03:17:57 ralf Exp $ +/* $Id: floppy-std.c,v 1.3 1998/10/28 12:38:13 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/sched.h> -#include <linux/kbdcntrlr.h> #include <linux/kernel.h> #include <linux/linkage.h> #include <linux/types.h> diff --git a/arch/mips/lib/ide-std.c b/arch/mips/lib/ide-std.c index e6bf4dc5f..97c2c0c33 100644 --- a/arch/mips/lib/ide-std.c +++ b/arch/mips/lib/ide-std.c @@ -9,6 +9,8 @@ * * Copyright (C) 1998 by Ralf Baechle */ +#include <linux/sched.h> +#include <linux/ioport.h> #include <linux/hdreg.h> #include <asm/ptrace.h> #include <asm/ide.h> diff --git a/arch/mips/lib/kbd-no.c b/arch/mips/lib/kbd-no.c new file mode 100644 index 000000000..c94e8c000 --- /dev/null +++ b/arch/mips/lib/kbd-no.c @@ -0,0 +1,63 @@ +/* $Id: kbd-no.c,v 1.1 1998/10/28 12:38:14 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Stub keyboard and psaux routines to keep Linux from crashing on machines + * without a keyboard. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include <linux/sched.h> +#include <asm/keyboard.h> + +static void no_kbd_request_region(void) +{ + /* No I/O ports are being used on the Indy. */ +} + +static int no_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return -ENODEV; +} + +static int no_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return -ENODEV; +} + +static void no_aux_free_irq(void) +{ +} + +static unsigned char no_kbd_read_input(void) +{ + return 0; +} + +static void no_kbd_write_output(unsigned char val) +{ +} + +static void no_kbd_write_command(unsigned char val) +{ +} + +static unsigned char no_kbd_read_status(void) +{ + return 0; +} + +struct kbd_ops no_kbd_ops = { + no_kbd_request_region, + no_kbd_request_irq, + + no_aux_request_irq, + no_aux_free_irq, + + no_kbd_read_input, + no_kbd_write_output, + no_kbd_write_command, + no_kbd_read_status +}; diff --git a/arch/mips/lib/kbd-std.c b/arch/mips/lib/kbd-std.c new file mode 100644 index 000000000..9ccb49fbd --- /dev/null +++ b/arch/mips/lib/kbd-std.c @@ -0,0 +1,81 @@ +/* $Id: kbd-std.c,v 1.1 1998/10/28 12:38:14 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Routines for standard PC style keyboards accessible via I/O ports. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include <linux/pc_keyb.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <asm/keyboard.h> +#include <asm/io.h> + +#define KEYBOARD_IRQ 1 +#define AUX_IRQ 12 + +static void std_kbd_request_region(void) +{ + request_region(0x60, 16, "keyboard"); +} + +static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL); +} + +static int std_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return request_irq(AUX_IRQ, handler, 0, "PS/2 Mouse", NULL); +} + +static void std_aux_free_irq(void) +{ + free_irq(AUX_IRQ, NULL); +} + +static unsigned char std_kbd_read_input(void) +{ + return inb(KBD_DATA_REG); +} + +static void std_kbd_write_output(unsigned char val) +{ + int status; + + do { + status = inb(KBD_CNTL_REG); + } while (status & KBD_STAT_IBF); + outb(val, KBD_DATA_REG); +} + +static void std_kbd_write_command(unsigned char val) +{ + int status; + + do { + status = inb(KBD_CNTL_REG); + } while (status & KBD_STAT_IBF); + outb(val, KBD_CNTL_REG); +} + +static unsigned char std_kbd_read_status(void) +{ + return inb(KBD_STATUS_REG); +} + +struct kbd_ops std_kbd_ops = { + std_kbd_request_region, + std_kbd_request_irq, + + std_aux_request_irq, + std_aux_free_irq, + + std_kbd_read_input, + std_kbd_write_output, + std_kbd_write_command, + std_kbd_read_status +}; diff --git a/arch/mips/mm/andes.c b/arch/mips/mm/andes.c index b29dcb274..c0653eb64 100644 --- a/arch/mips/mm/andes.c +++ b/arch/mips/mm/andes.c @@ -1,9 +1,8 @@ -/* +/* $Id: andes.c,v 1.5 1998/05/04 09:12:55 ralf Exp $ + * * andes.c: MMU and cache operations for the R10000 (ANDES). * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: andes.c,v 1.4 1998/04/05 11:23:54 ralf Exp $ */ #include <linux/init.h> #include <linux/kernel.h> @@ -13,6 +12,7 @@ #include <asm/pgtable.h> #include <asm/system.h> #include <asm/sgialib.h> +#include <asm/mmu_context.h> extern unsigned long mips_tlb_entries; @@ -104,6 +104,7 @@ __initfunc(void ld_mmu_andes(void)) flush_tlb_mm = andes_flush_tlb_mm; flush_tlb_range = andes_flush_tlb_range; flush_tlb_page = andes_flush_tlb_page; + andes_asid_setup(); add_wired_entry = andes_add_wired_entry; diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index d1ec6cb4c..18bfbf80e 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -1,8 +1,10 @@ -/* $Id: fault.c,v 1.10 1998/09/16 22:50:44 ralf Exp $ +/* $Id: fault.c,v 1.8 1998/09/19 19:16:18 ralf Exp $ * - * arch/mips/mm/fault.c + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. * - * Copyright (C) 1995, 1996, 1997 by Ralf Baechle + * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle */ #include <linux/signal.h> #include <linux/sched.h> @@ -16,6 +18,7 @@ #include <linux/mm.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/version.h> #include <asm/hardirq.h> #include <asm/pgtable.h> @@ -24,9 +27,11 @@ #include <asm/system.h> #include <asm/uaccess.h> +#define development_version (LINUX_VERSION_CODE & 0x100) + extern void die(char *, struct pt_regs *, unsigned long write); -unsigned long asid_cache = ASID_FIRST_VERSION; +unsigned long asid_cache; /* * Macro for exception fixup code to access integer registers. @@ -46,9 +51,12 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, struct mm_struct *mm = tsk->mm; unsigned long fixup; - if (in_interrupt()) - die("page fault from irq handler", regs, writeaccess); - lock_kernel(); + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || mm == &init_mm) + goto no_context; #if 0 printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid, address, writeaccess, regs->cp0_epc); @@ -77,8 +85,7 @@ good_area: } handle_mm_fault(tsk, vma, address, writeaccess); up(&mm->mmap_sem); - - goto out; + return; /* * Something tried to access memory that isn't in our memory map.. @@ -100,20 +107,22 @@ bad_area: (unsigned long) regs->regs[31]); #endif force_sig(SIGSEGV, tsk); - goto out; + return; } - /* Did we have an exception handler installed? */ +no_context: + /* Are we prepared to handle this kernel fault? */ fixup = search_exception_table(regs->cp0_epc); if (fixup) { long new_epc; tsk->tss.cp0_baduaddr = address; new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); - printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", - tsk->comm, regs->cp0_epc, new_epc); + if (development_version) + printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", + tsk->comm, regs->cp0_epc, new_epc); regs->cp0_epc = new_epc; - goto out; + return; } /* @@ -125,6 +134,4 @@ bad_area: address, regs->cp0_epc, regs->regs[31]); die("Oops", regs, writeaccess); do_exit(SIGKILL); -out: - unlock_kernel(); } diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 8bdbffaf8..f7fa99a37 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.8 1998/09/04 21:21:34 ralf Exp $ +/* $Id: init.c,v 1.9 1998/09/19 19:16:18 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -33,13 +33,8 @@ #ifdef CONFIG_SGI #include <asm/sgialib.h> #endif +#include <asm/mmu_context.h> -/* - * Define this to effectivly disable the userpage colouring shit. - */ -#define CONF_GIVE_A_SHIT_ABOUT_COLOURS - -extern void deskstation_tyne_dma_init(void); extern void show_net_buffers(void); void __bad_pte_kernel(pmd_t *pmd) @@ -58,7 +53,7 @@ pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) { pte_t *page; - page = (pte_t *) __get_free_page(GFP_KERNEL); + page = (pte_t *) __get_free_page(GFP_USER); if (pmd_none(*pmd)) { if (page) { clear_page((unsigned long)page); @@ -243,83 +238,6 @@ pte_t __bad_page(void) return pte_mkdirty(mk_pte(page, PAGE_SHARED)); } -#ifdef __SMP__ -spinlock_t user_page_lock = SPIN_LOCK_UNLOCKED; -#endif -struct upcache user_page_cache[8] __attribute__((aligned(32))); -static unsigned long user_page_order; -unsigned long user_page_colours; - -unsigned long get_user_page_slow(int which) -{ - unsigned long chunk; - struct upcache *up = &user_page_cache[0]; - struct page *p, *res; - int i; - - do { - chunk = __get_free_pages(GFP_KERNEL, user_page_order); - } while(chunk==0); - - p = mem_map + MAP_NR(chunk); - res = p + which; - spin_lock(&user_page_lock); - for (i=user_page_colours; i>=0; i--,p++,up++,chunk+=PAGE_SIZE) { - atomic_set(&p->count, 1); - p->age = PAGE_INITIAL_AGE; - - if (p != res) { - if(up->count < USER_PAGE_WATER) { - p->next = up->list; - up->list = p; - up->count++; - } else - free_pages(chunk, 0); - } - } - spin_unlock(&user_page_lock); - - return page_address(res); -} - -static inline void user_page_setup(void) -{ - unsigned long assoc = 0; - unsigned long dcache_log, icache_log, cache_log; - unsigned long config = read_32bit_cp0_register(CP0_CONFIG); - - switch(mips_cputype) { - case CPU_R4000SC: - case CPU_R4000MC: - case CPU_R4400SC: - case CPU_R4400MC: - cache_log = 3; /* => 32k, sucks */ - break; - - case CPU_R4600: /* two way set associative caches? */ - case CPU_R4700: - case CPU_R5000: - case CPU_NEVADA: - assoc = 1; - /* fall through */ - default: - /* use bigger cache */ - icache_log = (config >> 9) & 7; - dcache_log = (config >> 6) & 7; - if (dcache_log > icache_log) - cache_log = dcache_log; - else - cache_log = icache_log; - } - -#ifdef CONF_GIVE_A_SHIT_ABOUT_COLOURS - cache_log = assoc = 0; -#endif - - user_page_order = cache_log - assoc; - user_page_colours = (1 << (cache_log - assoc)) - 1; -} - void show_mem(void) { int i, free = 0, total = 0, reserved = 0; @@ -423,9 +341,6 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) max_mapnr << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10)); - - /* Initialize allocator for colour matched mapped pages. */ - user_page_setup(); } extern char __init_begin, __init_end; @@ -465,3 +380,35 @@ void si_meminfo(struct sysinfo *val) val->sharedram <<= PAGE_SHIFT; return; } + +/* Fixup an immediate instruction */ +__initfunc(static void __i_insn_fixup(unsigned int **start, unsigned int **stop, + unsigned int i_const)) +{ + unsigned int **p, *ip; + + for (p = start;p < stop; p++) { + ip = *p; + *ip = (*ip & 0xffff0000) | i_const; + } +} + +#define i_insn_fixup(section, const) \ +do { \ + extern unsigned int *__start_ ## section; \ + extern unsigned int *__stop_ ## section; \ + __i_insn_fixup(&__start_ ## section, &__stop_ ## section, const); \ +} while(0) + +/* Caller is assumed to flush the caches before the first context switch. */ +__initfunc(void __asid_setup(unsigned int inc, unsigned int mask, + unsigned int version_mask, + unsigned int first_version)) +{ + i_insn_fixup(__asid_inc, inc); + i_insn_fixup(__asid_mask, mask); + i_insn_fixup(__asid_version_mask, version_mask); + i_insn_fixup(__asid_first_version, first_version); + + asid_cache = first_version; +} diff --git a/arch/mips/mm/r2300.c b/arch/mips/mm/r2300.c index 03a0c63e9..8f8e7ddfa 100644 --- a/arch/mips/mm/r2300.c +++ b/arch/mips/mm/r2300.c @@ -1,9 +1,8 @@ -/* +/* $Id: r2300.c,v 1.6 1998/08/25 09:14:46 ralf Exp $ + * * r2300.c: R2000 and R3000 specific mmu/cache code. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: r2300.c,v 1.5 1998/04/05 11:23:55 ralf Exp $ */ #include <linux/init.h> #include <linux/kernel.h> @@ -14,6 +13,7 @@ #include <asm/pgtable.h> #include <asm/system.h> #include <asm/sgialib.h> +#include <asm/mmu_context.h> extern unsigned long mips_tlb_entries; @@ -274,6 +274,7 @@ __initfunc(void ld_mmu_r2300(void)) flush_tlb_mm = r2300_flush_tlb_mm; flush_tlb_range = r2300_flush_tlb_range; flush_tlb_page = r2300_flush_tlb_page; + r3000_asid_setup(); load_pgd = r2300_load_pgd; pgd_init = r2300_pgd_init; diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c index 31b636296..1b2ac3674 100644 --- a/arch/mips/mm/r4xx0.c +++ b/arch/mips/mm/r4xx0.c @@ -1,4 +1,4 @@ -/* $Id: r4xx0.c,v 1.19 1998/08/25 09:14:46 ralf Exp $ +/* $Id: r4xx0.c,v 1.20 1998/10/14 23:40:45 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -2791,6 +2791,7 @@ __initfunc(void ld_mmu_r4xx0(void)) flush_tlb_mm = r4k_flush_tlb_mm; flush_tlb_range = r4k_flush_tlb_range; flush_tlb_page = r4k_flush_tlb_page; + r4xx0_asid_setup(); load_pgd = r4k_load_pgd; pgd_init = r4k_pgd_init; diff --git a/arch/mips/mm/r6000.c b/arch/mips/mm/r6000.c index 047cb7b2f..b8b442728 100644 --- a/arch/mips/mm/r6000.c +++ b/arch/mips/mm/r6000.c @@ -1,4 +1,5 @@ -/* $Id: r6000.c,v 1.4 1998/04/05 11:23:56 ralf Exp $ +/* $Id: r6000.c,v 1.5 1998/08/25 09:14:47 ralf Exp $ + * * r6000.c: MMU and cache routines for the R6000 processors. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) @@ -13,6 +14,7 @@ #include <asm/pgtable.h> #include <asm/system.h> #include <asm/sgialib.h> +#include <asm/mmu_context.h> __asm__(".set mips3"); /* because we know... */ @@ -180,6 +182,7 @@ __initfunc(void ld_mmu_r6000(void)) flush_tlb_mm = r6000_flush_tlb_mm; flush_tlb_range = r6000_flush_tlb_range; flush_tlb_page = r6000_flush_tlb_page; + r6000_asid_setup(); load_pgd = r6000_load_pgd; pgd_init = r6000_pgd_init; diff --git a/arch/mips/mm/tfp.c b/arch/mips/mm/tfp.c index dab618b3e..0d8ab7c86 100644 --- a/arch/mips/mm/tfp.c +++ b/arch/mips/mm/tfp.c @@ -1,4 +1,5 @@ -/* +/* $Id: tfp.c,v 1.6 1998/10/16 19:22:44 ralf Exp $ + * * tfp.c: MMU and cache routines specific to the r8000 (TFP). * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) @@ -13,6 +14,7 @@ #include <asm/pgtable.h> #include <asm/system.h> #include <asm/sgialib.h> +#include <asm/mmu_context.h> extern unsigned long mips_tlb_entries; @@ -104,6 +106,7 @@ __initfunc(void ld_mmu_tfp(void)) flush_tlb_mm = tfp_flush_tlb_mm; flush_tlb_range = tfp_flush_tlb_range; flush_tlb_page = tfp_flush_tlb_page; + tfp_asid_setup(); add_wired_entry = tfp_add_wired_entry; diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c index fcc7e7092..f1f2bbc9f 100644 --- a/arch/mips/sgi/kernel/indy_int.c +++ b/arch/mips/sgi/kernel/indy_int.c @@ -1,4 +1,4 @@ -/* $Id: indy_int.c,v 1.9 1998/06/30 00:21:57 ralf Exp $ +/* $Id: indy_int.c,v 1.10 1998/08/25 09:14:49 ralf Exp $ * * indy_int.c: Routines for generic manipulation of the INT[23] ASIC * found on INDY workstations.. @@ -274,7 +274,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) int do_random, cpu; cpu = smp_processor_id(); - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[0][irq]++; printk("Got irq %d, press a key.", irq); @@ -310,7 +310,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) add_interrupt_randomness(irq); __cli(); } - irq_exit(cpu, irq); + hardirq_exit(cpu); /* unmasking and bottom half handling is done magically for us. */ } @@ -448,10 +448,10 @@ void indy_local0_irqdispatch(struct pt_regs *regs) action = local_irq_action[irq]; } - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[0][irq + 16]++; action->handler(irq, action->dev_id, regs); - irq_exit(cpu, irq); + hardirq_exit(cpu); } void indy_local1_irqdispatch(struct pt_regs *regs) @@ -472,10 +472,10 @@ void indy_local1_irqdispatch(struct pt_regs *regs) irq = lc1msk_to_irqnr[mask]; action = local_irq_action[irq]; } - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[0][irq + 24]++; action->handler(irq, action->dev_id, regs); - irq_exit(cpu, irq); + hardirq_exit(cpu); } void indy_buserror_irq(struct pt_regs *regs) @@ -483,13 +483,13 @@ void indy_buserror_irq(struct pt_regs *regs) int cpu = smp_processor_id(); int irq = 6; - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[0][irq]++; printk("Got a bus error IRQ, shouldn't happen yet\n"); show_regs(regs); printk("Spinning...\n"); while(1); - irq_exit(cpu, irq); + hardirq_exit(cpu); } /* Misc. crap just to keep the kernel linking... */ diff --git a/arch/mips/sgi/kernel/indy_sc.c b/arch/mips/sgi/kernel/indy_sc.c index ddac55816..9e78a2963 100644 --- a/arch/mips/sgi/kernel/indy_sc.c +++ b/arch/mips/sgi/kernel/indy_sc.c @@ -1,11 +1,10 @@ -/* $Id: indy_sc.c,v 1.9 1998/08/17 12:14:55 ralf Exp $ +/* $Id: indy_sc.c,v 1.5 1998/08/25 09:14:49 ralf Exp $ * * indy_sc.c: Indy cache managment functions. * * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org), * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). */ -#include <linux/config.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/sched.h> diff --git a/arch/mips/sgi/kernel/indy_timer.c b/arch/mips/sgi/kernel/indy_timer.c index e71441085..0920b9d2c 100644 --- a/arch/mips/sgi/kernel/indy_timer.c +++ b/arch/mips/sgi/kernel/indy_timer.c @@ -1,4 +1,4 @@ -/* $Id: indy_timer.c,v 1.9 1998/06/25 20:15:02 ralf Exp $ +/* $Id: indy_timer.c,v 1.10 1998/08/25 09:14:49 ralf Exp $ * * indy_timer.c: Setting up the clock on the INDY 8254 controller. * @@ -261,12 +261,12 @@ void indy_8254timer_irq(void) int cpu = smp_processor_id(); int irq = 4; - irq_enter(cpu, irq); + hardirq_enter(cpu); kstat.irqs[0][irq]++; printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); prom_getchar(); prom_imode(); - irq_exit(cpu, irq); + hardirq_exit(cpu); } void do_gettimeofday(struct timeval *tv) diff --git a/arch/mips/sgi/kernel/setup.c b/arch/mips/sgi/kernel/setup.c index 99cd9946f..dd1a67bfd 100644 --- a/arch/mips/sgi/kernel/setup.c +++ b/arch/mips/sgi/kernel/setup.c @@ -1,10 +1,11 @@ -/* $Id: setup.c,v 1.15 1998/09/26 12:25:03 tsbogend Exp $ +/* $Id: setup.c,v 1.16 1998/10/02 22:06:11 tsbogend Exp $ * * setup.c: SGI specific setup, including init of the feature struct. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) */ +#include <linux/config.h> #include <linux/init.h> #include <linux/kbd_ll.h> #include <linux/kernel.h> @@ -13,6 +14,7 @@ #include <linux/console.h> #include <linux/sched.h> #include <linux/mc146818rtc.h> +#include <linux/pc_keyb.h> #include <asm/addrspace.h> #include <asm/bcache.h> @@ -28,10 +30,38 @@ extern struct rtc_ops indy_rtc_ops; void indy_reboot_setup(void); -static volatile struct hpc_keyb *sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64); +#define sgi_kh ((struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64)) #define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ +static void sgi_request_region(void) +{ + /* No I/O ports are being used on the Indy. */ +} + +static int sgi_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + /* Dirty hack, this get's called as a callback from the keyboard + driver. We piggyback the initialization of the front panel + button handling on it even though they're technically not + related with the keyboard driver in any way. Doing it from + indy_setup wouldn't work since kmalloc isn't initialized yet. */ + indy_reboot_setup(); + + return request_irq(SGI_KEYBOARD_IRQ, handler, 0, "keyboard", NULL); +} + +static int sgi_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + /* Nothing to do, interrupt is shared with the keyboard hw */ + return 0; +} + +static void sgi_aux_free_irq(void) +{ + /* Nothing to do, interrupt is shared with the keyboard hw */ +} + static unsigned char sgi_read_input(void) { return sgi_kh->data; @@ -62,23 +92,18 @@ static unsigned char sgi_read_status(void) return sgi_kh->command; } -__initfunc(static void sgi_keyboard_setup(void)) -{ - kbd_read_input = sgi_read_input; - kbd_write_output = sgi_write_output; - kbd_write_command = sgi_write_command; - kbd_read_status = sgi_read_status; +struct kbd_ops sgi_kbd_ops = { + sgi_request_region, + sgi_request_irq, - request_irq(SGI_KEYBOARD_IRQ, keyboard_interrupt, - 0, "keyboard", NULL); + sgi_aux_request_irq, + sgi_aux_free_irq, - /* Dirty hack, this get's called as a callback from the keyboard - driver. We piggyback the initialization of the front panel - button handling on it even though they're technically not - related with the keyboard driver in any way. Doing it from - indy_setup wouldn't work since kmalloc isn't initialized yet. */ - indy_reboot_setup(); -} + sgi_read_input, + sgi_write_output, + sgi_write_command, + sgi_read_status +}; __initfunc(static void sgi_irq_setup(void)) { @@ -92,7 +117,6 @@ __initfunc(void sgi_setup(void)) #endif irq_setup = sgi_irq_setup; - keyboard_setup = sgi_keyboard_setup; /* Init the INDY HPC I/O controller. Need to call this before * fucking with the memory controller because it needs to know the @@ -124,4 +148,8 @@ __initfunc(void sgi_setup(void)) conswitchp = &newport_con; #endif rtc_ops = &indy_rtc_ops; + kbd_ops = &sgi_kbd_ops; +#ifdef CONFIG_PSMOUSE + aux_device_present = 0xaa; +#endif } diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile index 84622b55f..f3bb81704 100644 --- a/arch/mips/sni/Makefile +++ b/arch/mips/sni/Makefile @@ -1,3 +1,4 @@ +# $Id: Makefile,v 1.3 1998/10/28 12:38:16 ralf Exp $ # # Makefile for the SNI specific part of the kernel # @@ -5,8 +6,6 @@ # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # -# $Id: Makefile,v 1.2 1997/12/20 13:27:14 ralf Exp $ -# .S.s: $(CPP) $(CFLAGS) $< -o $*.s @@ -15,7 +14,7 @@ all: sni.o O_TARGET := sni.o -O_OBJS := hw-access.o int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o +O_OBJS := int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o int-handler.o: int-handler.S diff --git a/arch/mips/sni/hw-access.c b/arch/mips/sni/hw-access.c deleted file mode 100644 index c2c121318..000000000 --- a/arch/mips/sni/hw-access.c +++ /dev/null @@ -1,70 +0,0 @@ -/* $Id: hw-access.c,v 1.6 1998/06/30 00:21:59 ralf Exp $ - * - * Low-level hardware access stuff for SNI RM200 PCI - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1996, 1997, 1998 by Ralf Baechle - */ -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/kbd_ll.h> -#include <linux/kbdcntrlr.h> -#include <linux/kernel.h> -#include <linux/linkage.h> -#include <linux/types.h> -#include <linux/mm.h> -#include <asm/bootinfo.h> -#include <asm/cachectl.h> -#include <asm/dma.h> -#include <asm/keyboard.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/mc146818rtc.h> -#include <asm/pgtable.h> -#include <asm/sni.h> - -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ - -static unsigned char sni_read_input(void) -{ - return inb(KBD_DATA_REG); -} - -static void sni_write_output(unsigned char val) -{ - int status; - - do { - status = inb(KBD_CNTL_REG); - } while (status & KBD_STAT_IBF); - outb(val, KBD_DATA_REG); -} - -static void sni_write_command(unsigned char val) -{ - int status; - - do { - status = inb(KBD_CNTL_REG); - } while (status & KBD_STAT_IBF); - outb(val, KBD_CNTL_REG); -} - -static unsigned char sni_read_status(void) -{ - return inb(KBD_STATUS_REG); -} - -__initfunc(void sni_rm200_keyboard_setup(void)) -{ - kbd_read_input = sni_read_input; - kbd_write_output = sni_write_output; - kbd_write_command = sni_write_command; - kbd_read_status = sni_read_status; - request_irq(PCIMT_KEYBOARD_IRQ, keyboard_interrupt, - 0, "keyboard", NULL); - request_region(0x60, 16, "keyboard"); -} diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S index 3c920954d..fbda9cb26 100644 --- a/arch/mips/sni/int-handler.S +++ b/arch/mips/sni/int-handler.S @@ -1,17 +1,22 @@ -/* $Id: int-handler.S,v 1.2 1997/12/01 17:57:40 ralf Exp $ +/* $Id: int-handler.S,v 1.3 1998/05/07 23:44:01 ralf Exp $ * * SNI RM200 PCI specific interrupt handler code. * * Copyright (C) 1994 - 1997 by Ralf Baechle */ #include <asm/asm.h> -#include <linux/config.h> #include <asm/mipsconfig.h> #include <asm/mipsregs.h> #include <asm/regdef.h> #include <asm/sni.h> #include <asm/stackframe.h> +/* The PCI ASIC has the nasty property that it may delay writes if it is busy. + As a consequence from writes that have not graduated when we exit from the + interrupt handler we might catch a spurious interrupt. To avoid this we + force the PCI ASIC to graduate all writes by executing a read from the + PCI bus. */ + .set noreorder .set noat .align 5 @@ -20,34 +25,38 @@ CLI .set at - lb t0,led_cache - addiu t0,1 - sb t0,led_cache - sb t0,PCIMT_CSLED + /* Blinken light ... */ + lb t0, led_cache + addiu t0, 1 + sb t0, led_cache + sb t0, PCIMT_CSLED # write only register .data led_cache: .byte 0 .text - mfc0 t0,CP0_STATUS - mfc0 t1,CP0_CAUSE - and t0,t1 - - andi t1,t0,0x0800 # hardware interrupt 1 - bnez t1,hwint1 - andi t1,t0,0x4000 # hardware interrupt 4 - bnez t1,eth_int - - andi t1,t0,0x1000 # hardware interrupt 2 - bnez t1,hwint2 - andi t1,t0,0x2000 # hardware interrupt 3 - bnez t1,hwint3 - andi t1,t0,0x8000 # hardware interrupt 5 - bnez t1,hwint5 - andi t1,t0,0x0400 # hardware interrupt 0 - bnez t1,hwint0 + mfc0 t0, CP0_STATUS + mfc0 t1, CP0_CAUSE + and t0, t1 + + /* The following interrupt dispatch tests for hwint 1 / + EISA bridge first such that the timer interrupt get the + highest priority. */ + andi t1, t0, 0x0800 # hardware interrupt 1 + bnez t1, hwint1 + andi t1, t0, 0x4000 # hardware interrupt 4 + bnez t1, hwint4 + + andi t1, t0, 0x1000 # hardware interrupt 2 + bnez t1, hwint2 + andi t1, t0, 0x2000 # hardware interrupt 3 + bnez t1, hwint3 + andi t1, t0, 0x8000 # hardware interrupt 5 + bnez t1, hwint5 + andi t1, t0, 0x0400 # hardware interrupt 0 + bnez t1, hwint0 nop - j spurious_interrupt # Nothing up ... + j return # spurious interrupt nop ############################################################################## @@ -57,146 +66,61 @@ swint1: PANIC("swint1") /* ------------------------------------------------------------------------ */ -hwint1: lbu t0,PCIMT_CSITPEND - - andi t1,t0,0x20 - bnez t1,eisa_int - -#ifdef CONFIG_SCSI_NCR53C8XX - andi t1,t0,0x40 - beqz t1,scsi_int -#endif - nop - - j spurious_interrupt - nop - - /* ------------------------------------------------------------------------ */ - -hwint0: lbu t0,PCIMT_CSITPEND - - andi t1,t0,0x01 - beqz t1,int2 +/* hwint1 deals with EISA and SCSI interrupts. */ +hwint1: lbu s0, PCIMT_CSITPEND -go_spurious: j spurious_interrupt # we got fooled + andi t1, s0, 0x20 + beqz t1, 1f + andi s1, s0, 0x40 + lbu a0, PCIMT_INT_ACKNOWLEDGE # IACK cycle + xori t0, a0, 0xff + beqz t0, 1f # spurious interrupt? nop + jal i8259_do_irq # call real handler + move a1, sp -eisa_int: lui s0,%hi(SNI_PORT_BASE) - li a0,0x0f - sb a0,%lo(SNI_PORT_BASE+0x20)(s0) # poll command - lb a0,%lo(SNI_PORT_BASE+0x20)(s0) # read result - bgtz a0,poll_second - andi a0,7 - beq a0,2,poll_second # cascade? - li s1,1 - /* - * Acknowledge first pic - */ - lb t2,%lo(SNI_PORT_BASE+0x21)(s0) - lui s4,%hi(cache_21) - lb t0,%lo(cache_21)(s4) - sllv s1,s1,a0 - or t0,s1 - sb t0,%lo(cache_21)(s4) - sb t0,%lo(SNI_PORT_BASE+0x21)(s0) - li t2,0x20 - sb t2,%lo(SNI_PORT_BASE+0x20)(s0) - /* - * Now call the real handler - */ +1: bnez s1, 1f + li a0, PCIMT_IRQ_SCSI jal do_IRQ - move a1,sp - /* - * Unblock first pic - */ - lbu t1,%lo(SNI_PORT_BASE+0x21)(s0) - lb t1,%lo(cache_21)(s4) - nor s1,zero,s1 - and t1,s1 - sb t1,%lo(cache_21)(s4) - j ret_from_irq - sb t1,%lo(SNI_PORT_BASE+0x21)(s0) + move a1, sp - /* - * Cascade interrupt from second PIC - */ - .align 5 -poll_second: li a0,0x0f - sb a0,%lo(SNI_PORT_BASE+0xa0)(s0) # poll command - lb a0,%lo(SNI_PORT_BASE+0xa0)(s0) # read result - bgtz a0,go_spurious - andi a0,7 - /* - * Acknowledge second pic - */ - lbu t2,%lo(SNI_PORT_BASE+0xa1)(s0) - lui s4,%hi(cache_A1) - lb t3,%lo(cache_A1)(s4) - sllv s1,s1,a0 - or t3,s1 - sb t3,%lo(cache_A1)(s4) - sb t3,%lo(SNI_PORT_BASE+0xa1)(s0) - li t3,0x20 - sb t3,%lo(SNI_PORT_BASE+0xa0)(s0) - sb t3,%lo(SNI_PORT_BASE+0x20)(s0) - /* - * Now call the real handler - */ - addiu a0,8 - jal do_IRQ - move a1,sp - /* - * Unblock second pic - */ - lb t1,%lo(SNI_PORT_BASE+0xa1)(s0) - lb t1,%lo(cache_A1)(s4) - subu t0,1 - nor s1,zero,s1 - and t1,t1,s1 - sb t1,%lo(cache_A1)(s4) +1: lui t0, %hi(PCIMT_CSITPEND) j ret_from_irq - sb t1,%lo(SNI_PORT_BASE+0xa1)(s0) - -/* - * ... check if we were interrupted by the Lance ... - */ -eth_int: mfc0 s0,CP0_STATUS - ori t0,s0,0x4000 - xori t0,0x4000 - mtc0 t0,CP0_STATUS + lbu zero, %lo(PCIMT_CSITPEND)(t0) - li a0,PCIMT_IRQ_ETHERNET - jal do_IRQ - move a1,sp + /* ------------------------------------------------------------------------ */ - mtc0 s0,CP0_STATUS +/* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug + button interrupts. */ +hwint0: PANIC("Received int0 but no handler yet ...\n") +1: j 1b + nop - j ret_from_irq +go_spurious: j spurious_interrupt # we got fooled nop -#ifdef CONFIG_SCSI_NCR53C8XX +/* hwint4 is used for only the onboard PCnet 32. */ +hwint4: mfc0 s0, CP0_STATUS + ori t0, s0, 0x4000 + xori t0, 0x4000 + mtc0 t0, CP0_STATUS -/* - * ... check if we were interrupted by the NCR ... - */ -scsi_int: li a0,PCIMT_IRQ_SCSI + li a0, PCIMT_IRQ_ETHERNET jal do_IRQ - move a1,sp - j ret_from_irq - nop - -#endif /* CONFIG_SCSI_NCR53C8XX */ + move a1, sp -pci_int: PANIC("Received PCI interrupt but no handler yet ...\n") -1: j 1b - nop + mtc0 s0, CP0_STATUS -int2: PANIC("Received int2 but no handler yet ...\n") -1: j 1b + j ret_from_irq nop +/* This interrupt was used for the com1 console on the first prototypes. */ hwint2: PANIC("hwint2 and no handler yet") + +/* hwint3 should deal with the PCI A - D interrupts. */ hwint3: PANIC("hwint3 and no handler yet") + +/* hwint5 is the r4k count / compare interrupt */ hwint5: PANIC("hwint5 and no handler yet") END(sni_rm200_pci_handle_int) diff --git a/arch/mips/sni/io.c b/arch/mips/sni/io.c index 8a97b80a8..a59df4565 100644 --- a/arch/mips/sni/io.c +++ b/arch/mips/sni/io.c @@ -1,11 +1,10 @@ -/* +/* $Id: io.c,v 1.2 1998/04/05 11:24:06 ralf Exp $ + * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Low level I/O functions for SNI. - * - * $Id: io.c,v 1.2 1998/03/27 08:53:50 ralf Exp $ */ #include <linux/string.h> #include <asm/mipsconfig.h> @@ -14,46 +13,42 @@ #include <asm/spinlock.h> #include <asm/sni.h> -unsigned char sni_map_isa_cache; - -#define unused __attribute__((unused)) - -/* - * The PCIMT_CSMAPISA is shared by all processors; we need locking. - * - * XXX It's legal to use all the I/O memory access functions in interrupt - * code, so we need to use the _irq locking stuff which may result in - * significant IRQ latencies. - */ -static spinlock_t csmapisa_lock unused = SPIN_LOCK_UNLOCKED; - /* * Urgs... We only can see a 16mb window of the 4gb EISA address space * at PCIMT_EISA_BASE. Maladia segmentitis ... * - * XXX Check out if accessing PCIMT_CSMAPISA really is slow. - * For now assume so. + * To avoid locking and all the related headacke we implement this such + * that accessing the bus address space nests, so we're treating this + * correctly even for interrupts. This is going to suck seriously for + * the SMP members of the RM family. + * + * Making things worse the PCIMT_CSMAPISA register resides on the X bus with + * it's unbeatable 1.4 mb/s transfer rate. */ -static inline void update_isa_cache(unsigned long address) + +static inline void eisa_map(unsigned long address) { unsigned char upper; upper = address >> 24; - if (sni_map_isa_cache != upper) { - sni_map_isa_cache = upper; - *(volatile unsigned char *)PCIMT_CSMAPISA = ~upper; - } + *(volatile unsigned char *)PCIMT_CSMAPISA = ~upper; } +#define save_eisa_map() \ + (*(volatile unsigned char *)PCIMT_CSMAPISA) +#define restore_eisa_map(val) \ + do { (*(volatile unsigned char *)PCIMT_CSMAPISA) = val; } while(0) + static unsigned char sni_readb(unsigned long addr) { unsigned char res; + unsigned int save_map; - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); return res; } @@ -61,12 +56,13 @@ static unsigned char sni_readb(unsigned long addr) static unsigned short sni_readw(unsigned long addr) { unsigned short res; + unsigned int save_map; - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); return res; } @@ -74,101 +70,111 @@ static unsigned short sni_readw(unsigned long addr) static unsigned int sni_readl(unsigned long addr) { unsigned int res; + unsigned int save_map; - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr); - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); return res; } static void sni_writeb(unsigned char val, unsigned long addr) { - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + unsigned int save_map; + + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_writew(unsigned short val, unsigned long addr) { - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + unsigned int save_map; + + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_writel(unsigned int val, unsigned long addr) { - spin_lock_irq(&csmapisa_lock); - update_isa_cache(addr); + unsigned int save_map; + + save_map = save_eisa_map(); + eisa_map(addr); addr &= 0xffffff; *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val; - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_memset_io(unsigned long addr, int val, unsigned long len) { unsigned long waddr; + unsigned int save_map; + save_map = save_eisa_map(); waddr = PCIMT_EISA_BASE | (addr & 0xffffff); - spin_lock_irq(&csmapisa_lock); while(len) { unsigned long fraglen; fraglen = (~addr + 1) & 0xffffff; fraglen = (fraglen < len) ? fraglen : len; - update_isa_cache(addr); + eisa_map(addr); memset((char *)waddr, val, fraglen); addr += fraglen; waddr = waddr + fraglen - 0x1000000; len -= fraglen; } - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len) { unsigned long waddr; + unsigned int save_map; + save_map = save_eisa_map(); waddr = PCIMT_EISA_BASE | (from & 0xffffff); - spin_lock_irq(&csmapisa_lock); while(len) { unsigned long fraglen; fraglen = (~from + 1) & 0xffffff; fraglen = (fraglen < len) ? fraglen : len; - update_isa_cache(from); + eisa_map(from); memcpy((void *)to, (void *)waddr, fraglen); to += fraglen; from += fraglen; waddr = waddr + fraglen - 0x1000000; len -= fraglen; } - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } static void sni_memcpy_toio(unsigned long to, unsigned long from, unsigned long len) { unsigned long waddr; + unsigned int save_map; + save_map = save_eisa_map(); waddr = PCIMT_EISA_BASE | (to & 0xffffff); - spin_lock_irq(&csmapisa_lock); while(len) { unsigned long fraglen; fraglen = (~to + 1) & 0xffffff; fraglen = (fraglen < len) ? fraglen : len; - update_isa_cache(to); + eisa_map(to); memcpy((char *)to + PCIMT_EISA_BASE, (void *)from, fraglen); to += fraglen; from += fraglen; waddr = waddr + fraglen - 0x1000000; len -= fraglen; } - spin_unlock_irq(&csmapisa_lock); + restore_eisa_map(save_map); } diff --git a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c index fe538d277..0da6b8004 100644 --- a/arch/mips/sni/pci.c +++ b/arch/mips/sni/pci.c @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.5 1998/05/07 02:57:22 ralf Exp $ +/* $Id: pci.c,v 1.6 1998/05/07 23:44:02 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -9,6 +9,7 @@ * Copyright (C) 1997, 1998 Ralf Baechle */ #include <linux/config.h> +#include <linux/kernel.h> #include <linux/pci.h> #include <linux/types.h> #include <asm/byteorder.h> @@ -28,13 +29,37 @@ do { \ static void sni_rm200_pcibios_fixup (void) { - /* - * TODO: Fix PCI_INTERRUPT_LINE register for onboard cards. - * Take care of RM300 revision D boards for where the network - * slot became an ordinary PCI slot. - */ - pcibios_write_config_byte(0, PCI_DEVFN(1, 0), PCI_INTERRUPT_LINE, - PCIMT_IRQ_SCSI); + struct pci_dev *dev; + + for (dev=pci_devices; dev; dev=dev->next) { + /* + * TODO: Take care of RM300 revision D boards for where the + * network slot became an ordinary PCI slot. + */ + if (dev->devfn == PCI_DEVFN(1, 0)) { + /* Evil hack ... */ + set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NO_WA); + dev->irq = PCIMT_IRQ_SCSI; + continue; + } + if (dev->devfn == PCI_DEVFN(2, 0)) { + dev->irq = PCIMT_IRQ_ETHERNET; + continue; + } + + switch(dev->irq) { + case 1 ... 4: + dev->irq += PCIMT_IRQ_INTA - 1; + break; + case 0: + break; + default: + printk("PCI device on bus %d, dev %d, function %d " + "impossible interrupt configured.\n", + dev->bus->number, PCI_SLOT(dev->devfn), + PCI_SLOT(dev->devfn)); + } + } } /* diff --git a/arch/mips/sni/pcimt_scache.c b/arch/mips/sni/pcimt_scache.c index feec16967..55c96b939 100644 --- a/arch/mips/sni/pcimt_scache.c +++ b/arch/mips/sni/pcimt_scache.c @@ -1,35 +1,38 @@ -/* +/* $Id: pcimt_scache.c,v 1.3 1998/08/25 09:14:51 ralf Exp $ + * * arch/mips/sni/pcimt_scache.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1997 by Ralf Baechle - * - * $Id: pcimt_scache.c,v 1.2 1998/05/28 03:18:02 ralf Exp $ + * Copyright (c) 1997, 1998 by Ralf Baechle */ #include <linux/init.h> #include <linux/kernel.h> #include <asm/bcache.h> #include <asm/sni.h> +#define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF) +#define invspace (*(volatile unsigned int *)PCIMT_INVSPACE) + __initfunc(void sni_pcimt_sc_init(void)) { - unsigned int cacheconf, sc_size; + unsigned int scsiz, sc_size; - cacheconf = *(volatile unsigned int *)PCIMT_CACHECONF; - if ((cacheconf & 7) == 0) { - printk("No second level cache detected\n"); - printk("WARNING: not activating second level cache, " - "tell ralf@gnu.org\n"); + scsiz = cacheconf & 7; + if (scsiz == 0) { + printk("Second level cache is deactived.\n"); return; } - if ((cacheconf & 7) >= 6) { - printk("Invalid second level cache size detected\n"); + if (scsiz >= 6) { + printk("Invalid second level cache size configured, " + "deactivating second level cache.\n"); + cacheconf = 0; return; } - - sc_size = 128 << (cacheconf & 7); - printk("%dkb second level cache detected.\n", sc_size); + + sc_size = 128 << scsiz; + printk("%dkb second level cache detected, deactivating.\n", sc_size); + cacheconf = 0; } diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 2f3499707..0652c171b 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.13 1998/08/17 13:57:45 ralf Exp $ +/* $Id: setup.c,v 1.9 1998/08/25 09:14:51 ralf Exp $ * * Setup pointers to hardware-dependent routines. * @@ -17,6 +17,11 @@ #include <linux/interrupt.h> #include <linux/timex.h> #include <linux/pci.h> +#include <linux/mc146818rtc.h> +#include <linux/console.h> +#include <linux/fb.h> +#include <linux/pc_keyb.h> + #include <asm/bcache.h> #include <asm/bootinfo.h> #include <asm/keyboard.h> @@ -39,7 +44,6 @@ static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; extern asmlinkage void sni_rm200_pci_handle_int(void); -extern void sni_rm200_keyboard_setup(void); extern void sni_machine_restart(char *command); extern void sni_machine_halt(void); @@ -47,19 +51,20 @@ extern void sni_machine_power_off(void); extern struct ide_ops std_ide_ops; extern struct rtc_ops std_rtc_ops; +extern struct kbd_ops std_kbd_ops; __initfunc(static void sni_irq_setup(void)) { set_except_vector(0, sni_rm200_pci_handle_int); request_region(0x20,0x20, "pic1"); request_region(0xa0,0x20, "pic2"); - setup_x86_irq(2, &irq2); + i8259_setup_irq(2, &irq2); /* * IRQ0 seems to be the irq for PC style stuff. * I don't know how to handle the debug button interrupt, so * don't use this button yet or bad things happen ... */ - set_cp0_status(ST0_IM, IE_IRQ1 | IE_IRQ4); + set_cp0_status(ST0_IM, IE_IRQ1 | IE_IRQ3 | IE_IRQ4); } void (*board_time_init)(struct irqaction *irq); @@ -70,7 +75,7 @@ __initfunc(static void sni_rm200_pci_time_init(struct irqaction *irq)) outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb_p(LATCH & 0xff , 0x40); /* LSB */ outb(LATCH >> 8 , 0x40); /* MSB */ - setup_x86_irq(0, irq); + i8259_setup_irq(0, irq); } unsigned char aux_device_present; @@ -132,7 +137,6 @@ __initfunc(void sni_rm200_pci_setup(void)) irq_setup = sni_irq_setup; mips_io_port_base = SNI_PORT_BASE; - keyboard_setup = sni_rm200_keyboard_setup; /* * Setup (E)ISA I/O memory access stuff @@ -165,6 +169,10 @@ __initfunc(void sni_rm200_pci_setup(void)) #ifdef CONFIG_BLK_DEV_IDE ide_ops = &std_ide_ops; #endif - + conswitchp = &vga_con; rtc_ops = &std_rtc_ops; + kbd_ops = &std_kbd_ops; +#ifdef CONFIG_PSMOUSE + aux_device_present = 0xaa; +#endif } diff --git a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile index b33919a5d..0da0a492d 100644 --- a/arch/ppc/8xx_io/Makefile +++ b/arch/ppc/8xx_io/Makefile @@ -8,6 +8,12 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := 8xx_io.a -O_OBJS = commproc.o uart.o enet.o +O_OBJS = commproc.o uart.o +ifdef CONFIG_MBX +O_OBJS += enet.o +endif +ifdef CONFIG_FADS +O_OBJS += fec.o +endif include $(TOPDIR)/Rules.make diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index 00bbbe72d..b1ea955ed 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -21,6 +21,7 @@ * applications that require more DP ram, we can expand the boundaries * but then we have to be careful of any downloaded microcode. */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -29,7 +30,12 @@ #include <linux/mm.h> #include <linux/interrupt.h> #include <asm/irq.h> +#ifdef CONFIG_MBX #include <asm/mbx.h> +#endif +#ifdef CONFIG_FADS +#include <asm/fads.h> +#endif #include <asm/page.h> #include <asm/pgtable.h> #include <asm/8xx_immap.h> @@ -52,13 +58,13 @@ static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs); static void cpm_error_interrupt(void *); void -mbx_cpm_reset(uint host_page_addr) +m8xx_cpm_reset(uint host_page_addr) { volatile immap_t *imp; volatile cpm8xx_t *commproc; pte_t *pte; - imp = (immap_t *)MBX_IMAP_ADDR; + imp = (immap_t *)IMAP_ADDR; commproc = (cpm8xx_t *)&imp->im_cpm; #ifdef notdef @@ -78,6 +84,10 @@ mbx_cpm_reset(uint host_page_addr) #endif /* Set SDMA Bus Request priority 5. + * On 860T, this also enables FEC priority 6. I am not sure + * this is what we realy want for some applications, but the + * manual recommends it. + * Bit 25, FAM can also be set to use FEC aggressive mode (860T). */ imp->im_siu_conf.sc_sdcr = 1; @@ -99,10 +109,10 @@ mbx_cpm_reset(uint host_page_addr) /* Initialize the CPM interrupt controller. */ - ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cicr = + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr = (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK; - ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr = 0; + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0; /* Set our interrupt handler with the core CPU. */ if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) @@ -111,7 +121,7 @@ mbx_cpm_reset(uint host_page_addr) /* Install our own error handler. */ cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); - ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN; + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN; } /* CPM interrupt controller interrupt. @@ -124,19 +134,19 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs) /* Get the vector by setting the ACK bit and then reading * the register. */ - ((volatile immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_civr = 1; - vec = ((volatile immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_civr; + ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1; + vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr; vec >>= 11; if (cpm_vecs[vec].handler != 0) (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id); else - ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); /* After servicing the interrupt, we have to remove the status * indicator. */ - ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec); + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec); } @@ -160,7 +170,7 @@ cpm_install_handler(int vec, void (*handler)(void *), void *dev_id) (uint)handler, (uint)cpm_vecs[vec].handler); cpm_vecs[vec].handler = handler; cpm_vecs[vec].dev_id = dev_id; - ((immap_t *)MBX_IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); } /* Allocate some memory from the dual ported ram. We may want to @@ -168,7 +178,7 @@ cpm_install_handler(int vec, void (*handler)(void *), void *dev_id) * citizen. */ uint -mbx_cpm_dpalloc(uint size) +m8xx_cpm_dpalloc(uint size) { uint retloc; @@ -185,7 +195,7 @@ mbx_cpm_dpalloc(uint size) * UART "fifos" and the like. */ uint -mbx_cpm_hostalloc(uint size) +m8xx_cpm_hostalloc(uint size) { uint retloc; @@ -201,13 +211,13 @@ mbx_cpm_hostalloc(uint size) /* Set a baud rate generator. This needs lots of work. There are * four BRGs, any of which can be wired to any channel. * The internal baud rate clock is the system clock divided by 16. - * I need to find a way to get this system clock frequency, which is - * part of the VPD....... + * This assumes the baudrate is 16x oversampled by the uart. */ -#define BRG_INT_CLK (40000000/16) +#define BRG_INT_CLK (((bd_t *)res)->bi_intfreq * 1000000) +#define BRG_UART_CLK (BRG_INT_CLK/16) void -mbx_cpm_setbrg(uint brg, uint rate) +m8xx_cpm_setbrg(uint brg, uint rate) { volatile uint *bp; @@ -215,5 +225,6 @@ mbx_cpm_setbrg(uint brg, uint rate) */ bp = (uint *)&cpmp->cp_brgc1; bp += brg; - *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN; + *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN; } + diff --git a/arch/ppc/8xx_io/commproc.h b/arch/ppc/8xx_io/commproc.h index 38046a31c..50140ab26 100644 --- a/arch/ppc/8xx_io/commproc.h +++ b/arch/ppc/8xx_io/commproc.h @@ -62,9 +62,9 @@ * and dual port ram. */ extern cpm8xx_t *cpmp; /* Pointer to comm processor */ -uint mbx_cpm_dpalloc(uint size); -uint mbx_cpm_hostalloc(uint size); -void mbx_cpm_setbrg(uint brg, uint rate); +uint m8xx_cpm_dpalloc(uint size); +uint m8xx_cpm_hostalloc(uint size); +void m8xx_cpm_setbrg(uint brg, uint rate); /* Buffer descriptors used by many of the CPM protocols. */ @@ -87,8 +87,16 @@ typedef struct cpm_buf_desc { #define BD_SC_OV ((ushort)0x0002) /* Overrun */ #define BD_SC_CD ((ushort)0x0001) /* ?? */ -/* Define enough so I can at least use the MBX serial port as a UART. - * The MBX uses SMC1 as the host serial port. +/* Parameter RAM offsets. +*/ +#define PROFF_SCC1 ((uint)0x0000) +#define PROFF_SCC2 ((uint)0x0100) +#define PROFF_SCC3 ((uint)0x0200) +#define PROFF_SMC1 ((uint)0x0280) +#define PROFF_SCC4 ((uint)0x0300) +#define PROFF_SMC2 ((uint)0x0380) + +/* Define enough so I can at least use the serial port as a UART. */ typedef struct smc_uart { ushort smc_rbase; /* Rx Buffer descriptor base address */ @@ -114,9 +122,6 @@ typedef struct smc_uart { ushort smc_rmask; /* Temporary bit mask */ } smc_uart_t; -#define PROFF_SMC1 ((uint)0x0280) /* Offset in Parameter RAM */ -#define PROFF_SMC2 ((uint)0x0380) - /* Function code bits. */ #define SMC_EB ((u_char)0x10) /* Set big endian byte order */ @@ -139,7 +144,7 @@ typedef struct smc_uart { /* SMC Event and Mask register. */ #define SMCM_TXE ((unsigned char)0x10) -#define SMCM_BSY ((unsigned char)0x14) +#define SMCM_BSY ((unsigned char)0x04) #define SMCM_TX ((unsigned char)0x02) #define SMCM_RX ((unsigned char)0x01) @@ -238,6 +243,13 @@ typedef struct smc_uart { #define SCC_TODR_TOD ((ushort)0x8000) +/* SCC Event and Mask register. +*/ +#define SCCM_TXE ((unsigned char)0x10) +#define SCCM_BSY ((unsigned char)0x04) +#define SCCM_TX ((unsigned char)0x02) +#define SCCM_RX ((unsigned char)0x01) + typedef struct scc_param { ushort scc_rbase; /* Rx Buffer descriptor base address */ ushort scc_tbase; /* Tx Buffer descriptor base address */ @@ -317,8 +329,6 @@ typedef struct scc_enet { ushort sen_taddrl; /* temp address (LSB) */ } scc_enet_t; -#define PROFF_SCC1 ((uint)0x0000) /* Offset in Parameter RAM */ - /* Bits in parallel I/O port registers that have to be set/cleared * to configure the pins for SCC1 use. The TCLK and RCLK seem unique * to the MBX860 board. Any two of the four available clocks could be @@ -397,6 +407,37 @@ typedef struct scc_enet { #define BD_ENET_TX_CSL ((ushort)0x0001) #define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */ +/* SCC as UART +*/ +typedef struct scc_uart { + sccp_t scc_genscc; + uint scc_res1; /* Reserved */ + uint scc_res2; /* Reserved */ + ushort scc_maxidl; /* Maximum idle chars */ + ushort scc_idlc; /* temp idle counter */ + ushort scc_brkcr; /* Break count register */ + ushort scc_parec; /* receive parity error counter */ + ushort scc_frmec; /* receive framing error counter */ + ushort scc_nosec; /* receive noise counter */ + ushort scc_brkec; /* receive break condition counter */ + ushort scc_brkln; /* last received break length */ + ushort scc_uaddr1; /* UART address character 1 */ + ushort scc_uaddr2; /* UART address character 2 */ + ushort scc_rtemp; /* Temp storage */ + ushort scc_toseq; /* Transmit out of sequence char */ + ushort scc_char1; /* control character 1 */ + ushort scc_char2; /* control character 2 */ + ushort scc_char3; /* control character 3 */ + ushort scc_char4; /* control character 4 */ + ushort scc_char5; /* control character 5 */ + ushort scc_char6; /* control character 6 */ + ushort scc_char7; /* control character 7 */ + ushort scc_char8; /* control character 8 */ + ushort scc_rccm; /* receive control character mask */ + ushort scc_rccr; /* receive control character register */ + ushort scc_rlbc; /* receive last break character */ +} scc_uart_t; + /* SCC Event and Mask registers when it is used as a UART. */ #define UART_SCCM_GLR ((ushort)0x1000) @@ -411,6 +452,30 @@ typedef struct scc_enet { #define UART_SCCM_TX ((ushort)0x0002) #define UART_SCCM_RX ((ushort)0x0001) +/* The SCC PMSR when used as a UART. +*/ +#define SCU_PMSR_FLC ((ushort)0x8000) +#define SCU_PMSR_SL ((ushort)0x4000) +#define SCU_PMSR_CL ((ushort)0x3000) +#define SCU_PMSR_UM ((ushort)0x0c00) +#define SCU_PMSR_FRZ ((ushort)0x0200) +#define SCU_PMSR_RZS ((ushort)0x0100) +#define SCU_PMSR_SYN ((ushort)0x0080) +#define SCU_PMSR_DRT ((ushort)0x0040) +#define SCU_PMSR_PEN ((ushort)0x0010) +#define SCU_PMSR_RPM ((ushort)0x000c) +#define SCU_PMSR_REVP ((ushort)0x0008) +#define SCU_PMSR_TPM ((ushort)0x0003) +#define SCU_PMSR_TEVP ((ushort)0x0003) + +/* CPM Transparent mode SCC. + */ +typedef struct scc_trans { + sccp_t st_genscc; + uint st_cpres; /* Preset CRC */ + uint st_cmask; /* Constant mask for CRC */ +} scc_trans_t; + /* CPM interrupts. There are nearly 32 interrupts generated by CPM * channels or devices. All of these are presented to the PPC core * as a single interrupt. The CPM interrupt handler dispatches its diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c index 0b5f0452c..8c3401d6f 100644 --- a/arch/ppc/8xx_io/enet.c +++ b/arch/ppc/8xx_io/enet.c @@ -96,7 +96,7 @@ */ /* The number of Tx and Rx buffers. These are allocated from the page - * pool. The code may assume these are power of two, so it it best + * pool. The code may assume these are power of two, so it is best * to keep them that size. * We don't need to allocate pages for the transmitter. We just use * the skbuffer directly. diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c new file mode 100644 index 000000000..2b797a498 --- /dev/null +++ b/arch/ppc/8xx_io/fec.c @@ -0,0 +1,985 @@ +/* + * Fast Ethernet Controller (FECC) driver for Motorola MPC8xx. + * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * + * This version of the driver is specific to the FADS implementation, + * since the board contains control registers external to the processor + * for the control of the LevelOne LXT970 transceiver. The MPC860T manual + * describes connections using the internal parallel port I/O, which + * is basically all of Port D. + * + * Right now, I am very watseful with the buffers. I allocate memory + * pages and then divide them into 2K frame buffers. This way I know I + * have buffers large enough to hold one frame within one buffer descriptor. + * Once I get this working, I will use 64 or 128 byte CPM buffers, which + * will be much more memory efficient and will easily handle lots of + * small packets. + * + */ +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/malloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> + +#include <asm/8xx_immap.h> +#include <asm/pgtable.h> +#include <asm/fads.h> +#include <asm/irq.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> +#include "commproc.h" + +/* The number of Tx and Rx buffers. These are allocated from the page + * pool. The code may assume these are power of two, so it it best + * to keep them that size. + * We don't need to allocate pages for the transmitter. We just use + * the skbuffer directly. + */ +#if 1 +#define FEC_ENET_RX_PAGES 4 +#define FEC_ENET_RX_FRSIZE 2048 +#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) +#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) +#define TX_RING_SIZE 8 /* Must be power of two */ +#define TX_RING_MOD_MASK 7 /* for this to work */ +#else +#define FEC_ENET_RX_PAGES 16 +#define FEC_ENET_RX_FRSIZE 2048 +#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) +#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) +#define TX_RING_SIZE 16 /* Must be power of two */ +#define TX_RING_MOD_MASK 15 /* for this to work */ +#endif + +/* Interrupt events/masks. +*/ +#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ +#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ +#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ +#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */ +#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */ +#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */ +#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */ +#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ +#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ +#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ + +/* The FEC stores dest/src/type, data, and checksum for receive packets. + */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 +#define PKT_MAXBLR_SIZE 1520 + +/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and + * tx_bd_base always point to the base of the buffer descriptors. The + * cur_rx and cur_tx point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct fec_enet_private { + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + ushort skb_cur; + ushort skb_dirty; + + /* CPM dual port RAM relative addresses. + */ + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t *tx_bd_base; + cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ + cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + scc_t *sccp; + struct net_device_stats stats; + char tx_full; + unsigned long lock; +}; + +static int fec_enet_open(struct device *dev); +static int fec_enet_start_xmit(struct sk_buff *skb, struct device *dev); +static int fec_enet_rx(struct device *dev); +static void fec_enet_mii(struct device *dev); +static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static int fec_enet_close(struct device *dev); +static struct net_device_stats *fec_enet_get_stats(struct device *dev); +static void set_multicast_list(struct device *dev); + +static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 }; + +/* MII processing. We keep this as simple as possible. Requests are + * placed on the list (if there is room). When the request is finished + * by the MII, an optional function may be called. + */ +typedef struct mii_list { + uint mii_regval; + void (*mii_func)(uint val); + struct mii_list *mii_next; +} mii_list_t; + +#define NMII 10 +mii_list_t mii_cmds[NMII]; +mii_list_t *mii_free; +mii_list_t *mii_head; +mii_list_t *mii_tail; + +static int mii_queue(int request, void (*func)(int)); + +/* Make MII read/write commands for the FEC. +*/ +#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) +#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \ + (VAL & 0xffff)) + +static int +fec_enet_open(struct device *dev) +{ + + /* I should reset the ring buffers here, but I don't yet know + * a simple way to do that. + */ + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + return 0; /* Always succeed */ +} + +static int +fec_enet_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; + volatile cbd_t *bdp; + unsigned long flags; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 20) + return 1; + printk("%s: transmit timed out.\n", dev->name); + fep->stats.tx_errors++; +#ifndef final_version + { + int i; + cbd_t *bdp; + printk(" Ring data dump: cur_tx %x%s cur_rx %x.\n", + fep->cur_tx, fep->tx_full ? " (full)" : "", + fep->cur_rx); + bdp = fep->tx_bd_base; + for (i = 0 ; i < TX_RING_SIZE; i++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp = fep->rx_bd_base; + for (i = 0 ; i < RX_RING_SIZE; i++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + } +#endif + + dev->tbusy=0; + dev->trans_start = jiffies; + + return 0; + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + return 1; + } + + if (test_and_set_bit(0, (void*)&fep->lock) != 0) { + printk("%s: tx queue lock!.\n", dev->name); + /* don't clear dev->tbusy flag. */ + return 1; + } + + /* Fill in a Tx ring entry */ + bdp = fep->cur_tx; + +#ifndef final_version + if (bdp->cbd_sc & BD_ENET_TX_READY) { + /* Ooops. All transmit buffers are full. Bail out. + * This should not happen, since dev->tbusy should be set. + */ + printk("%s: tx queue full!.\n", dev->name); + fep->lock = 0; + return 1; + } +#endif + + /* Clear all of the status flags. + */ + bdp->cbd_sc &= ~BD_ENET_TX_STATS; + + /* Set buffer length and buffer pointer. + */ + bdp->cbd_bufaddr = __pa(skb->data); + bdp->cbd_datlen = skb->len; + + /* Save skb pointer. + */ + fep->tx_skbuff[fep->skb_cur] = skb; + + fep->stats.tx_bytes += skb->len; + fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; + + /* Push the data cache so the CPM does not get stale memory + * data. + */ + /*flush_dcache_range(skb->data, skb->data + skb->len);*/ + + /* Send it on its way. Tell CPM its ready, interrupt when done, + * its the last BD of the frame, and to put the CRC on the end. + */ + save_flags(flags); + cli(); + + bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); + + dev->trans_start = jiffies; + (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_x_des_active = 0x01000000; + + /* If this was the last BD in the ring, start at the beginning again. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = fep->tx_bd_base; + else + bdp++; + + fep->lock = 0; + if (bdp->cbd_sc & BD_ENET_TX_READY) + fep->tx_full = 1; + else + dev->tbusy=0; + restore_flags(flags); + + fep->cur_tx = (cbd_t *)bdp; + + return 0; +} + +/* The interrupt handler. + * This is called from the MPC core interrupt. + */ +static void +fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct device *dev = dev_id; + struct fec_enet_private *fep; + volatile cbd_t *bdp; + volatile fec_t *ep; + uint int_events; + int c=0; + + fep = (struct fec_enet_private *)dev->priv; + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + /* Get the interrupt events that caused us to be here. + */ + while ((int_events = ep->fec_ievent) != 0) { + ep->fec_ievent = int_events; + if ((int_events & + (FEC_ENET_HBERR | FEC_ENET_BABR | + FEC_ENET_BABT | FEC_ENET_EBERR)) != 0) + printk("FEC ERROR %x\n", int_events); + + /* Handle receive event in its own function. + */ + if (int_events & (FEC_ENET_RXF | FEC_ENET_RXB)) + fec_enet_rx(dev_id); + + /* Transmit OK, or non-fatal error. Update the buffer descriptors. + * FEC handles all errors, we just discover them as part of the + * transmit process. + */ + if (int_events & (FEC_ENET_TXF | FEC_ENET_TXB)) { + bdp = fep->dirty_tx; + while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { +#if 1 + if (bdp==fep->cur_tx) + break; +#endif + if (++c>1) {/*we go here when an it has been lost*/}; + + + if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ + fep->stats.tx_heartbeat_errors++; + if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + fep->stats.tx_window_errors++; + if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ + fep->stats.tx_aborted_errors++; + if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + fep->stats.tx_fifo_errors++; + if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ + fep->stats.tx_carrier_errors++; + + fep->stats.tx_errors++; + + fep->stats.tx_packets++; + +#ifndef final_version + if (bdp->cbd_sc & BD_ENET_TX_READY) + printk("HEY! Enet xmit interrupt and TX_READY.\n"); +#endif + /* Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (bdp->cbd_sc & BD_ENET_TX_DEF) + fep->stats.collisions++; + + /* Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb(fep->tx_skbuff[fep->skb_dirty]/*, FREE_WRITE*/); + fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; + + /* Update pointer to next buffer descriptor to be transmitted. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = fep->tx_bd_base; + else + bdp++; + + /* Since we have freed up a buffer, the ring is no longer + * full. + */ + if (fep->tx_full && dev->tbusy) { + fep->tx_full = 0; + dev->tbusy = 0; + mark_bh(NET_BH); + } + + fep->dirty_tx = (cbd_t *)bdp; +#if 0 + if (bdp==fep->cur_tx) + break; +#endif + }/*while (bdp->cbd_sc&BD_ENET_TX_READY)==0*/ + } /* if tx events */ + + if (int_events & FEC_ENET_MII) + fec_enet_mii(dev_id); + + } /* while any events */ + + dev->interrupt = 0; + + return; +} + +/* During a receive, the cur_rx points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has + * not been given to the system, we just set the empty indicator, + * effectively tossing the packet. + */ +static int +fec_enet_rx(struct device *dev) +{ + struct fec_enet_private *fep; + volatile cbd_t *bdp; + struct sk_buff *skb; + ushort pkt_len; + volatile fec_t *ep; + + fep = (struct fec_enet_private *)dev->priv; + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = fep->cur_rx; + +for (;;) { + if (bdp->cbd_sc & BD_ENET_RX_EMPTY) + break; + +#ifndef final_version + /* Since we have allocated space to hold a complete frame, + * the last indicator should be set. + */ + if ((bdp->cbd_sc & BD_ENET_RX_LAST) == 0) + printk("FEC ENET: rcv is not +last\n"); +#endif + + /* Frame too long or too short. + */ + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + fep->stats.rx_length_errors++; + if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ + fep->stats.rx_frame_errors++; + if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ + fep->stats.rx_crc_errors++; + if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ + fep->stats.rx_crc_errors++; + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (bdp->cbd_sc & BD_ENET_RX_CL) { + fep->stats.rx_frame_errors++; + } + else { + + /* Process the incoming frame. + */ + fep->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + fep->stats.rx_bytes += pkt_len; + + /* This does 16 byte alignment, exactly what we need. + */ + skb = dev_alloc_skb(pkt_len); + + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + fep->stats.rx_dropped++; + } + else { + skb->dev = dev; + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)__va(bdp->cbd_bufaddr), + pkt_len, 0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + } + } + + /* Clear the status flags for this buffer. + */ + bdp->cbd_sc &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty. + */ + bdp->cbd_sc |= BD_ENET_RX_EMPTY; + + /* Update BD pointer to next entry. + */ + if (bdp->cbd_sc & BD_ENET_RX_WRAP) + bdp = fep->rx_bd_base; + else + bdp++; + +#if 1 + /* Doing this here will keep the FEC running while we process + * incoming frames. On a heavily loaded network, we should be + * able to keep up at the expense of system resources. + */ + ep->fec_r_des_active = 0x01000000; +#endif + } + fep->cur_rx = (cbd_t *)bdp; + +#if 0 + /* Doing this here will allow us to process all frames in the + * ring before the FEC is allowed to put more there. On a heavily + * loaded network, some frames may be lost. Unfortunately, this + * increases the interrupt overhead since we can potentially work + * our way back to the interrupt return only to come right back + * here. + */ + ep->fec_r_des_active = 0x01000000; +#endif + + return 0; +} + +static void +fec_enet_mii(struct device *dev) +{ + struct fec_enet_private *fep; + volatile fec_t *ep; + mii_list_t *mip; + uint mii_reg; + + fep = (struct fec_enet_private *)dev->priv; + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + mii_reg = ep->fec_mii_data; + + if ((mip = mii_head) == NULL) { + printk("MII and no head!\n"); + return; + } + + if (mip->mii_func != NULL) + (*(mip->mii_func))(mii_reg); + + mii_head = mip->mii_next; + mip->mii_next = mii_free; + mii_free = mip; + + if ((mip = mii_head) != NULL) + ep->fec_mii_data = mip->mii_regval; +} + +static int +mii_queue(int regval, void (*func)(int)) +{ + unsigned long flags; + mii_list_t *mip; + int retval; + + retval = 0; + + save_flags(flags); + cli(); + + if ((mip = mii_free) != NULL) { + mii_free = mip->mii_next; + mip->mii_regval = regval; + mip->mii_func = func; + mip->mii_next = NULL; + if (mii_head) { + mii_tail->mii_next = mip; + mii_tail = mip; + } + else { + mii_head = mii_tail = mip; + (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval; + } + } + else { + retval = 1; + } + + restore_flags(flags); + + return(retval); +} + +static void +mii_status(uint mii_reg) +{ + if (((mii_reg >> 18) & 0x1f) == 1) { + /* status register. + */ + printk("fec: "); + if (mii_reg & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_reg & 0x0010) + printk(",remote fault"); + if (mii_reg & 0x0020) + printk(",auto complete"); + printk("\n"); + } + if (((mii_reg >> 18) & 0x1f) == 0x14) { + /* Extended chip status register. + */ + printk("fec: "); + if (mii_reg & 0x0800) + printk("100 Mbps"); + else + printk("10 Mbps"); + + if (mii_reg & 0x1000) + printk(", Full-Duplex\n"); + else + printk(", Half-Duplex\n"); + } +} + +static void +mii_startup_cmds(void) +{ + + /* Read status registers to clear any pending interrupt. + */ + mii_queue(mk_mii_read(1), mii_status); + mii_queue(mk_mii_read(18), mii_status); + + /* Read extended chip status register. + */ + mii_queue(mk_mii_read(0x14), mii_status); + + /* Enable Link status change interrupts. + mii_queue(mk_mii_write(0x11, 0x0002), NULL); + */ +} + +/* This supports the mii_link interrupt below. + * We should get called three times. Once for register 1, once for + * register 18, and once for register 20. + */ +static uint mii_saved_reg1; + +static void +mii_relink(uint mii_reg) +{ + if (((mii_reg >> 18) & 0x1f) == 1) { + /* Just save the status register and get out. + */ + mii_saved_reg1 = mii_reg; + return; + } + if (((mii_reg >> 18) & 0x1f) == 18) { + /* Not much here, but has to be read to clear the + * interrupt condition. + */ + if ((mii_reg & 0x8000) == 0) + printk("fec: re-link and no IRQ?\n"); + if ((mii_reg & 0x4000) == 0) + printk("fec: no PHY power?\n"); + } + if (((mii_reg >> 18) & 0x1f) == 20) { + /* Extended chip status register. + * OK, now we have it all, so figure out what is going on. + */ + printk("fec: "); + if (mii_saved_reg1 & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_saved_reg1 & 0x0010) + printk(", remote fault"); + if (mii_saved_reg1 & 0x0020) + printk(", auto complete"); + + if (mii_reg & 0x0800) + printk(", 100 Mbps"); + else + printk(", 10 Mbps"); + + if (mii_reg & 0x1000) + printk(", Full-Duplex\n"); + else + printk(", Half-Duplex\n"); + } +} + +/* This interrupt occurs when the LTX970 detects a link change. +*/ +static void +mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct device *dev = dev_id; + struct fec_enet_private *fep; + volatile fec_t *ep; + + fep = (struct fec_enet_private *)dev->priv; + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + + /* We need to sequentially read registers 1 and 18 to clear + * the interrupt. We don't need to do that here because this + * is an edge triggered interrupt that has already been acknowledged + * by the top level handler. We also read the extended status + * register 20. We just queue the commands and let them happen + * as part of the "normal" processing. + */ + mii_queue(mk_mii_read(1), mii_relink); + mii_queue(mk_mii_read(18), mii_relink); + mii_queue(mk_mii_read(20), mii_relink); +} + +static int +fec_enet_close(struct device *dev) +{ + /* Don't know what to do yet. + */ + + return 0; +} + +static struct net_device_stats *fec_enet_get_stats(struct device *dev) +{ + struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; + + return &fep->stats; +} + +/* Set or clear the multicast filter for this adaptor. + * Skeleton taken from sunlance driver. + * The CPM Ethernet implementation allows Multicast as well as individual + * MAC address filtering. Some of the drivers check to make sure it is + * a group multicast address, and discard those that are not. I guess I + * will do the same for now, but just remove the test if you want + * individual filtering as well (do the upper net layers want or support + * this kind of feature?). + */ + +static void set_multicast_list(struct device *dev) +{ + struct fec_enet_private *fep; + struct dev_mc_list *dmi; + u_char *mcptr, *tdptr; + volatile fec_t *ep; + int i, j; + + fep = (struct fec_enet_private *)dev->priv; + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + + if (dev->flags&IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + ep->fec_r_cntrl |= 0x0008; + } else { + + ep->fec_r_cntrl &= ~0x0008; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + ep->fec_hash_table_high = 0xffffffff; + ep->fec_hash_table_low = 0xffffffff; + } +#if 0 + else { + /* Clear filter and add the addresses in the list. + */ + ep->sen_gaddr1 = 0; + ep->sen_gaddr2 = 0; + ep->sen_gaddr3 = 0; + ep->sen_gaddr4 = 0; + + dmi = dev->mc_list; + + for (i=0; i<dev->mc_count; i++) { + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* The address in dmi_addr is LSB first, + * and taddr is MSB first. We have to + * copy bytes MSB first from dmi_addr. + */ + mcptr = (u_char *)dmi->dmi_addr + 5; + tdptr = (u_char *)&ep->sen_taddrh; + for (j=0; j<6; j++) + *tdptr++ = *mcptr--; + + /* Ask CPM to run CRC and set bit in + * filter mask. + */ + cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_SET_GADDR) | CPM_CR_FLG; + /* this delay is necessary here -- Cort */ + udelay(10); + while (cpmp->cp_cpcr & CPM_CR_FLG); + } + } +#endif + } +} + +/* Initialize the FECC Ethernet on 860T. + */ +__initfunc(int m8xx_enet_init(void)) +{ + struct device *dev; + struct fec_enet_private *fep; + int i, j; + unsigned char *eap; + unsigned long mem_addr; + pte_t *pte; + volatile cbd_t *bdp; + cbd_t *cbd_base; + volatile immap_t *immap; + volatile fec_t *fecp; + unsigned char rtc_save_cfg, rtc_val; + + immap = (immap_t *)IMAP_ADDR; /* pointer to internal registers */ + + /* Allocate some private information. + */ + fep = (struct fec_enet_private *)kmalloc(sizeof(*fep), GFP_KERNEL); + __clear_user(fep,sizeof(*fep)); + + /* Create an Ethernet device instance. + */ + dev = init_etherdev(0, 0); + + fecp = &(immap->im_cpm.cp_fec); + + /* Whack a reset. We should wait for this. + */ + fecp->fec_ecntrl = 1; + udelay(10); + + /* Enable interrupts we wish to service. + */ + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); + + /* Clear any outstanding interrupt. + */ + fecp->fec_ievent = 0xffc0; + + fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; + + /* Set station address. + */ + fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1]; + fecp->fec_addr_high = my_enet_addr[2]; + + eap = (unsigned char *)&my_enet_addr[0]; + for (i=0; i<6; i++) + dev->dev_addr[i] = *eap++; + + /* Reset all multicast. + */ + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; + + /* Set maximum receive buffer size. + */ + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + fecp->fec_r_hash = PKT_MAXBUF_SIZE; + + /* Allocate memory for buffer descriptors. + */ + if (((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) > PAGE_SIZE) { + printk("FECC init error. Need more space.\n"); + printk("FECC initialization failed.\n"); + return 1; + } + mem_addr = __get_free_page(GFP_KERNEL); + cbd_base = (cbd_t *)mem_addr; + + /* Make it uncached. + */ + pte = va_to_pte(&init_task, (int)mem_addr); + pte_val(*pte) |= _PAGE_NO_CACHE; + flush_tlb_page(current->mm->mmap, mem_addr); + + /* Set receive and transmit descriptor base. + */ + fecp->fec_r_des_start = __pa(mem_addr); + fep->rx_bd_base = cbd_base; + fecp->fec_x_des_start = __pa((unsigned long)(cbd_base + RX_RING_SIZE)); + fep->tx_bd_base = cbd_base + RX_RING_SIZE; + + fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; + fep->cur_rx = fep->rx_bd_base; + + fep->skb_cur = fep->skb_dirty = 0; + + /* Initialize the receive buffer descriptors. + */ + bdp = fep->rx_bd_base; + for (i=0; i<FEC_ENET_RX_PAGES; i++) { + + /* Allocate a page. + */ + mem_addr = __get_free_page(GFP_KERNEL); + + /* Make it uncached. + */ + pte = va_to_pte(&init_task, mem_addr); + pte_val(*pte) |= _PAGE_NO_CACHE; + flush_tlb_page(current->mm->mmap, mem_addr); + + /* Initialize the BD for every fragment in the page. + */ + for (j=0; j<FEC_ENET_RX_FRPPG; j++) { + bdp->cbd_sc = BD_ENET_RX_EMPTY; + bdp->cbd_bufaddr = __pa(mem_addr); + mem_addr += FEC_ENET_RX_FRSIZE; + bdp++; + } + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* ...and the same for transmmit. + */ + bdp = fep->tx_bd_base; + for (i=0; i<TX_RING_SIZE; i++) { + + /* Initialize the BD for every fragment in the page. + */ + bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Enable MII mode, half-duplex until we know better.. + */ + fecp->fec_r_cntrl = 0x0c; + fecp->fec_x_cntrl = 0x00; + + /* Enable big endian and don't care about SDMA FC. + */ + fecp->fec_fun_code = 0x78000000; + + /* Set MII speed (50 MHz core). + */ + fecp->fec_mii_speed = 0x14; + + /* Configure all of port D for MII. + */ + immap->im_ioport.iop_pdpar = 0x1fff; + immap->im_ioport.iop_pddir = 0x1c58; + + /* Install our interrupt handlers. The 860T FADS board uses + * IRQ2 for the MII interrupt. + */ + if (request_irq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0) + panic("Could not allocate FEC IRQ!"); + if (request_irq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0) + panic("Could not allocate MII IRQ!"); + + dev->base_addr = (unsigned long)fecp; + dev->priv = fep; + dev->name = "fec"; + + /* The FEC Ethernet specific entries in the device structure. */ + dev->open = fec_enet_open; + dev->hard_start_xmit = fec_enet_start_xmit; + dev->stop = fec_enet_close; + dev->get_stats = fec_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + + /* And last, enable the transmit and receive processing. + */ + fecp->fec_ecntrl = 2; + fecp->fec_r_des_active = 0x01000000; + + printk("FEC ENET Version 0.1, "); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + + for (i=0; i<NMII-1; i++) + mii_cmds[i].mii_next = &mii_cmds[i+1]; + mii_free = mii_cmds; + + mii_startup_cmds(); + + return 0; +} + diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c index 9d859a46b..fdbd0c796 100644 --- a/arch/ppc/8xx_io/uart.c +++ b/arch/ppc/8xx_io/uart.c @@ -37,7 +37,14 @@ #include <linux/init.h> #include <linux/delay.h> #include <asm/uaccess.h> +#include <asm/8xx_immap.h> +#ifdef CONFIG_MBX +#include <asm/mbx.h> +#endif +#ifdef CONFIG_FADS +#include <asm/fads.h> +#endif #include "commproc.h" #ifdef CONFIG_SERIAL_CONSOLE @@ -53,7 +60,7 @@ #define TX_WAKEUP ASYNC_SHARE_IRQ static char *serial_name = "CPM UART driver"; -static char *serial_version = "0.01"; +static char *serial_version = "0.02"; static DECLARE_TASK_QUEUE(tq_serial); @@ -96,10 +103,16 @@ static int serial_console_setup(struct console *co, char *options); #define smc_scc_num hub6 #define SCC_NUM_BASE 2 +/* The index into the CPM registers for the first SCC in the table. +*/ +#define SCC_IDX_BASE 1 + static struct serial_state rs_table[] = { /* UART CLK PORT IRQ FLAGS NUM */ { 0, 0, PROFF_SMC1, CPMVEC_SMC1, 0, 0 }, /* SMC1 ttyS0 */ { 0, 0, PROFF_SMC2, CPMVEC_SMC2, 0, 1 }, /* SMC1 ttyS0 */ + { 0, 0, PROFF_SCC2, CPMVEC_SCC2, 0, 2 }, /* SCC2 ttyS2 */ + { 0, 0, PROFF_SCC3, CPMVEC_SCC3, 0, 3 }, /* SCC3 ttyS3 */ }; #define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) @@ -212,7 +225,7 @@ static void rs_8xx_stop(struct tty_struct *tty) smcp->smc_smcm &= ~SMCM_TX; } else { - sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE]; + sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE]; sccp->scc_sccm &= ~UART_SCCM_TX; } restore_flags(flags); @@ -235,7 +248,7 @@ static void rs_8xx_start(struct tty_struct *tty) smcp->smc_smcm |= SMCM_TX; } else { - sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE]; + sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE]; sccp->scc_sccm |= UART_SCCM_TX; } restore_flags(flags); @@ -507,26 +520,33 @@ static void rs_8xx_interrupt(void *dev_id) int idx; ser_info_t *info; volatile smc_t *smcp; + volatile scc_t *sccp; info = (ser_info_t *)dev_id; if ((idx = info->state->smc_scc_num) < SCC_NUM_BASE) { smcp = &cpmp->cp_smc[idx]; + events = smcp->smc_smce; + if (events & SMCM_RX) + receive_chars(info); + if (events & SMCM_TX) + transmit_chars(info); + smcp->smc_smce = events; } else { - panic("SCC UART Interrupt....not ready"); + sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE]; + events = sccp->scc_scce; + if (events & SCCM_RX) + receive_chars(info); + if (events & SCCM_TX) + transmit_chars(info); + sccp->scc_scce = events; } - events = smcp->smc_smce; #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_single(%d, %x)...", info->state->smc_scc_num, events); #endif - if (events & SMCM_RX) - receive_chars(info); - if (events & SMCM_TX) - transmit_chars(info); - smcp->smc_smce = events; #ifdef modem_control check_modem_status(info); #endif @@ -610,6 +630,7 @@ static int startup(ser_info_t *info) volatile smc_t *smcp; volatile scc_t *sccp; volatile smc_uart_t *up; + volatile scc_uart_t *scup; save_flags(flags); cli(); @@ -662,13 +683,28 @@ static int startup(ser_info_t *info) * are coming. */ up = (smc_uart_t *)&cpmp->cp_dparam[state->port]; +#if 0 up->smc_mrblr = 1; /* receive buffer length */ up->smc_maxidl = 0; /* wait forever for next char */ +#else + up->smc_mrblr = RX_BUF_SIZE; + up->smc_maxidl = RX_BUF_SIZE; +#endif up->smc_brkcr = 1; /* number of break chars */ } else { - sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE]; - sccp->scc_sccm |= UART_SCCM_RX; + sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE]; + scup = (scc_uart_t *)&cpmp->cp_dparam[state->port]; +#if 0 + scup->scc_genscc.scc_mrblr = 1; /* receive buffer length */ + scup->scc_maxidl = 0; /* wait forever for next char */ +#else + scup->scc_genscc.scc_mrblr = RX_BUF_SIZE; + scup->scc_maxidl = RX_BUF_SIZE; +#endif + + sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX); + sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); } info->flags |= ASYNC_INITIALIZED; @@ -719,10 +755,10 @@ static void shutdown(ser_info_t * info) smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); } else { - sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE]; - sccp->scc_sccm &= ~UART_SCCM_RX; + sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE]; + sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); + sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); } - if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -738,8 +774,8 @@ static void shutdown(ser_info_t * info) static void change_speed(ser_info_t *info) { int baud_rate; - unsigned cflag, cval, prev_mode; - int i, bits, idx; + unsigned cflag, cval, scval, prev_mode; + int i, bits, sbits, idx; unsigned long flags; volatile smc_t *smcp; volatile scc_t *sccp; @@ -754,6 +790,7 @@ static void change_speed(ser_info_t *info) * The value 'bits' counts this for us. */ cval = 0; + scval = 0; /* byte size and parity */ switch (cflag & CSIZE) { @@ -764,16 +801,22 @@ static void change_speed(ser_info_t *info) /* Never happens, but GCC is too dumb to figure it out */ default: bits = 8; break; } + sbits = bits - 5; + if (cflag & CSTOPB) { cval |= SMCMR_SL; /* Two stops */ + scval |= SCU_PMSR_SL; bits++; } if (cflag & PARENB) { cval |= SMCMR_PEN; + scval |= SCU_PMSR_PEN; bits++; } - if (!(cflag & PARODD)) + if (!(cflag & PARODD)) { cval |= SMCMR_PM_EVEN; + scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP); + } /* Determine divisor based on baud rate */ i = cflag & CBAUD; @@ -859,11 +902,11 @@ static void change_speed(ser_info_t *info) smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN)); } else { - sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE]; - sccp->scc_sccm &= ~UART_SCCM_RX; + sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE]; + sccp->scc_pmsr = (sbits << 12) | scval; } - mbx_cpm_setbrg(info->state->smc_scc_num, baud_rate); + m8xx_cpm_setbrg(info->state->smc_scc_num, baud_rate); restore_flags(flags); } @@ -1271,12 +1314,11 @@ static void end_break(ser_info_t *info) static void send_break(ser_info_t *info, int duration) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; #ifdef SERIAL_DEBUG_SEND_BREAK printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); #endif begin_break(info); - schedule(); + schedule_timeout(duration); end_break(info); #ifdef SERIAL_DEBUG_SEND_BREAK printk("done jiffies=%lu\n", jiffies); @@ -1568,8 +1610,9 @@ static void rs_8xx_close(struct tty_struct *tty, struct file * filp) smcp->smc_smcmr &= ~SMCMR_REN; } else { - sccp = &cpmp->cp_scc[idx - SCC_NUM_BASE]; + sccp = &cpmp->cp_scc[idx - SCC_IDX_BASE]; sccp->scc_sccm &= ~UART_SCCM_RX; + sccp->scc_gsmrl &= ~SCC_GSMRL_ENR; } /* * Before we drop DTR, make sure the UART transmitter @@ -1589,8 +1632,7 @@ static void rs_8xx_close(struct tty_struct *tty, struct file * filp) if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } @@ -1647,8 +1689,7 @@ static void rs_8xx_wait_until_sent(struct tty_struct *tty, int timeout) #endif current->state = TASK_INTERRUPTIBLE; /* current->counter = 0; make us low-priority */ - current->timeout = jiffies + char_time; - schedule(); + schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && ((orig_jiffies + timeout) < jiffies)) @@ -2218,12 +2259,15 @@ __initfunc(int rs_8xx_init(void)) struct serial_state * state; ser_info_t *info; uint mem_addr, dp_addr; - int i, j; + int i, j, idx; ushort chan; volatile cbd_t *bdp; volatile cpm8xx_t *cp; volatile smc_t *sp; volatile smc_uart_t *up; + volatile scc_t *scp; + volatile scc_uart_t *sup; + volatile immap_t *immap; init_bh(SERIAL_BH, do_serial_bh); #if 0 @@ -2289,6 +2333,7 @@ __initfunc(int rs_8xx_init(void)) panic("Couldn't register callout driver\n"); cp = cpmp; /* Get pointer to Communication Processor */ + immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ /* Configure SMCs Tx/Rx instead of port B parallel I/O. */ @@ -2296,10 +2341,41 @@ __initfunc(int rs_8xx_init(void)) cp->cp_pbdir &= ~0x00000cc0; cp->cp_pbodr &= ~0x00000cc0; + /* Configure SCC2 and SCC3 instead of port A parallel I/O. + */ +#ifndef CONFIG_MBX + /* The "standard" configuration through the 860. + */ + immap->im_ioport.iop_papar |= 0x003c; + immap->im_ioport.iop_padir &= ~0x003c; + immap->im_ioport.iop_paodr &= ~0x003c; +#else + /* On the MBX, SCC3 is through Port D. + */ + immap->im_ioport.iop_papar |= 0x000c; /* SCC2 on port A */ + immap->im_ioport.iop_padir &= ~0x000c; + immap->im_ioport.iop_paodr &= ~0x000c; + + immap->im_ioport.iop_pdpar |= 0x0030; /* SCC3 on port D */ +#endif + + /* Since we don't yet do modem control, connect the port C pins + * as general purpose I/O. This will assert CTS and CD for the + * SCC ports. + */ + immap->im_ioport.iop_pcdir |= 0x03c6; + immap->im_ioport.iop_pcpar &= ~0x03c6; + /* Wire BRG1 to SMC1 and BRG2 to SMC2. */ cp->cp_simode = 0x10000000; + /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and + * BRG4 to SCC3. + */ + cp->cp_sicr &= ~0x00ffff00; + cp->cp_sicr |= 0x001b1200; + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { state->magic = SSTATE_MAGIC; state->line = i; @@ -2340,28 +2416,21 @@ __initfunc(int rs_8xx_init(void)) info->state = state; state->info = (struct async_struct *)info; - /* Right now, assume we are using SMCs. - */ - sp = &cp->cp_smc[state->smc_scc_num]; - - up = (smc_uart_t *)&cp->cp_dparam[state->port]; - /* We need to allocate a transmit and receive buffer * descriptors from dual port ram, and a character * buffer area from host mem. */ - dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO); + dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO); /* Allocate space for FIFOs in the host memory. */ - mem_addr = mbx_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); + mem_addr = m8xx_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the * virtual address for us to work with. */ bdp = (cbd_t *)&cp->cp_dpmem[dp_addr]; - up->smc_rbase = dp_addr; info->rx_cur = info->rx_bd_base = (cbd_t *)bdp; for (j=0; j<(RX_NUM_FIFO-1); j++) { @@ -2373,18 +2442,28 @@ __initfunc(int rs_8xx_init(void)) bdp->cbd_bufaddr = __pa(mem_addr); bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; - dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO); + if ((idx = state->smc_scc_num) < SCC_NUM_BASE) { + sp = &cp->cp_smc[idx]; + up = (smc_uart_t *)&cp->cp_dparam[state->port]; + up->smc_rbase = dp_addr; + } + else { + scp = &cp->cp_scc[idx - SCC_IDX_BASE]; + sup = (scc_uart_t *)&cp->cp_dparam[state->port]; + sup->scc_genscc.scc_rbase = dp_addr; + } + + dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO); /* Allocate space for FIFOs in the host memory. */ - mem_addr = mbx_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); + mem_addr = m8xx_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the * virtual address for us to work with. */ bdp = (cbd_t *)&cp->cp_dpmem[dp_addr]; - up->smc_tbase = dp_addr; info->tx_cur = info->tx_bd_base = (cbd_t *)bdp; for (j=0; j<(TX_NUM_FIFO-1); j++) { @@ -2396,39 +2475,104 @@ __initfunc(int rs_8xx_init(void)) bdp->cbd_bufaddr = __pa(mem_addr); bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT); - /* Set up the uart parameters in the parameter ram. - */ - up->smc_rfcr = SMC_EB; - up->smc_tfcr = SMC_EB; + if (idx < SCC_NUM_BASE) { + up->smc_tbase = dp_addr; - /* Set this to 1 for now, so we get single character - * interrupts. Using idle charater time requires - * some additional tuning. - */ - up->smc_mrblr = 1; /* receive buffer length */ - up->smc_maxidl = 0; /* wait forever for next char */ - up->smc_brkcr = 1; /* number of break chars */ + /* Set up the uart parameters in the + * parameter ram. + */ + up->smc_rfcr = SMC_EB; + up->smc_tfcr = SMC_EB; - /* Send the CPM an initialize command. - */ - if (state->smc_scc_num == 0) - chan = CPM_CR_CH_SMC1; - else - chan = CPM_CR_CH_SMC2; - cp->cp_cpcr = mk_cr_cmd(chan, + /* Set this to 1 for now, so we get single + * character interrupts. Using idle charater + * time requires some additional tuning. + */ + up->smc_mrblr = 1; + up->smc_maxidl = 0; + up->smc_brkcr = 1; + + /* Send the CPM an initialize command. + */ + if (state->smc_scc_num == 0) + chan = CPM_CR_CH_SMC1; + else + chan = CPM_CR_CH_SMC2; + + cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG; - while (cp->cp_cpcr & CPM_CR_FLG); + while (cp->cp_cpcr & CPM_CR_FLG); - /* Set UART mode, 8 bit, no parity, one stop. - * Enable receive and transmit. - */ - sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART; - /* Disable all interrupts and clear all pending - * events. - */ - sp->smc_smcm = 0; - sp->smc_smce = 0xff; + /* Disable all interrupts and clear all pending + * events. + */ + sp->smc_smcm = 0; + sp->smc_smce = 0xff; + } + else { + sup->scc_genscc.scc_tbase = dp_addr; + + /* Set up the uart parameters in the + * parameter ram. + */ + sup->scc_genscc.scc_rfcr = SMC_EB; + sup->scc_genscc.scc_tfcr = SMC_EB; + + /* Set this to 1 for now, so we get single + * character interrupts. Using idle charater + * time requires some additional tuning. + */ + sup->scc_genscc.scc_mrblr = 1; + sup->scc_maxidl = 0; + sup->scc_brkcr = 1; + sup->scc_parec = 0; + sup->scc_frmec = 0; + sup->scc_nosec = 0; + sup->scc_brkec = 0; + sup->scc_uaddr1 = 0; + sup->scc_uaddr2 = 0; + sup->scc_toseq = 0; + sup->scc_char1 = 0x8000; + sup->scc_char2 = 0x8000; + sup->scc_char3 = 0x8000; + sup->scc_char4 = 0x8000; + sup->scc_char5 = 0x8000; + sup->scc_char6 = 0x8000; + sup->scc_char7 = 0x8000; + sup->scc_char8 = 0x8000; + sup->scc_rccm = 0xc0ff; + + /* Send the CPM an initialize command. + */ + if (state->smc_scc_num == 2) + chan = CPM_CR_CH_SCC2; + else + chan = CPM_CR_CH_SCC3; + + cp->cp_cpcr = mk_cr_cmd(chan, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + /* Set UART mode, 8 bit, no parity, one stop. + * Enable receive and transmit. + */ + scp->scc_gsmrh = 0; + scp->scc_gsmrl = + (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16); + + /* Disable all interrupts and clear all pending + * events. + */ + scp->scc_sccm = 0; + scp->scc_scce = 0xffff; + scp->scc_dsr = 0x7e7e; + scp->scc_pmsr = 0x3000; + } /* Install interrupt handler. */ @@ -2436,7 +2580,7 @@ __initfunc(int rs_8xx_init(void)) /* Set up the baud rate generator. */ - mbx_cpm_setbrg(state->smc_scc_num, 9600); + m8xx_cpm_setbrg(state->smc_scc_num, 9600); /* If the port is the console, enable Rx and Tx. */ @@ -2479,11 +2623,11 @@ __initfunc(static int serial_console_setup(struct console *co, char *options)) /* Allocate space for two buffer descriptors in the DP ram. */ - dp_addr = mbx_cpm_dpalloc(sizeof(cbd_t) * 2); + dp_addr = m8xx_cpm_dpalloc(sizeof(cbd_t) * 2); /* Allocate space for two 2 byte FIFOs in the host memory. */ - mem_addr = mbx_cpm_hostalloc(4); + mem_addr = m8xx_cpm_hostalloc(4); /* Set the physical address of the host memory buffers in * the buffer descriptors. @@ -2526,7 +2670,7 @@ __initfunc(static int serial_console_setup(struct console *co, char *options)) /* Set up the baud rate generator. */ - mbx_cpm_setbrg(ser->smc_scc_num, 9600); + m8xx_cpm_setbrg(ser->smc_scc_num, 9600); /* And finally, enable Rx and Tx. */ diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 38c6e01e4..cd98b4513 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -14,11 +14,10 @@ KERNELLOAD =0xc0000000 -# PowerPC (cross) tools -ifneq ($(shell uname -m),ppc) -CROSS_COMPILE = ppc-linux-elf- -else +ifeq ($(shell uname -m),ppc) CHECKS = checks +else +CROSS_COMPILE = ppc-linux-elf- endif ASFLAGS = diff --git a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c index a9a6b218d..690173cc9 100644 --- a/arch/ppc/amiga/amiints.c +++ b/arch/ppc/amiga/amiints.c @@ -2,4 +2,551 @@ #define amiga_request_irq request_irq #define amiga_free_irq free_irq -#include "../../m68k/amiga/amiints.c" +/* + * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + * 11/07/96: rewritten interrupt handling, irq lists are exists now only for + * this sources where it makes sense (VERTB/PORTS/EXTER) and you must + * be careful that dev_id for this sources is unique since this the + * only possibility to distinguish between different handlers for + * free_irq. irq lists also have different irq flags: + * - IRQ_FLG_FAST: handler is inserted at top of list (after other + * fast handlers) + * - IRQ_FLG_SLOW: handler is inserted at bottom of list and before + * they're executed irq level is set to the previous + * one, but handlers don't need to be reentrant, if + * reentrance occured, slow handlers will be just + * called again. + * The whole interrupt handling for CIAs is moved to cia.c + * /Roman Zippel + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/kernel_stat.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/traps.h> +#include <asm/amigahw.h> +#include <asm/amigaints.h> +#include <asm/amipcmcia.h> + +#ifdef CONFIG_APUS +#include <asm/amigappc.h> +#endif + +extern int cia_request_irq(struct ciabase *base,int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id); +extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id); +extern void cia_init_IRQ(struct ciabase *base); +extern int cia_get_irq_list(struct ciabase *base, char *buf); + +/* irq node variables for amiga interrupt sources */ +static irq_node_t *ami_irq_list[AMI_STD_IRQS]; + +unsigned short ami_intena_vals[AMI_STD_IRQS] = { + IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT, + IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER +}; +static const unsigned char ami_servers[AMI_STD_IRQS] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 +}; + +static short ami_ablecount[AMI_IRQS]; + +static void ami_badint(int irq, void *dev_id, struct pt_regs *fp) +{ + num_spurious += 1; +} + +/* + * void amiga_init_IRQ(void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function should be called during kernel startup to initialize + * the amiga IRQ handling routines. + */ + +__initfunc(void amiga_init_IRQ(void)) +{ + int i; + + /* initialize handlers */ + for (i = 0; i < AMI_STD_IRQS; i++) { + if (ami_servers[i]) { + ami_irq_list[i] = NULL; + } else { + ami_irq_list[i] = new_irq_node(); + ami_irq_list[i]->handler = ami_badint; + ami_irq_list[i]->flags = IRQ_FLG_STD; + ami_irq_list[i]->dev_id = NULL; + ami_irq_list[i]->devname = NULL; + ami_irq_list[i]->next = NULL; + } + } + for (i = 0; i < AMI_IRQS; i++) + ami_ablecount[i] = 0; + + /* turn off PCMCIA interrupts */ + if (AMIGAHW_PRESENT(PCMCIA)) + pcmcia_disable_irq(); + + /* turn off all interrupts... */ + custom.intena = 0x7fff; + custom.intreq = 0x7fff; + +#ifdef CONFIG_APUS + /* Clear any inter-CPU interupt requests. Circumvents bug in + Blizzard IPL emulation HW (or so it appears). */ + APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); + + /* Init IPL emulation. */ + APUS_WRITE(APUS_REG_INT, REGINT_INTMASTER | REGINT_ENABLEIPL); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK); +#endif + /* ... and enable the master interrupt bit */ + custom.intena = IF_SETCLR | IF_INTEN; + + cia_init_IRQ(&ciaa_base); + cia_init_IRQ(&ciab_base); +} + +static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node) +{ + unsigned long flags; + irq_node_t *cur; + + if (!node->dev_id) + printk("%s: Warning: dev_id of %s is zero\n", + __FUNCTION__, node->devname); + + save_flags(flags); + cli(); + + cur = *list; + + if (node->flags & IRQ_FLG_FAST) { + node->flags &= ~IRQ_FLG_SLOW; + while (cur && cur->flags & IRQ_FLG_FAST) { + list = &cur->next; + cur = cur->next; + } + } else if (node->flags & IRQ_FLG_SLOW) { + while (cur) { + list = &cur->next; + cur = cur->next; + } + } else { + while (cur && !(cur->flags & IRQ_FLG_SLOW)) { + list = &cur->next; + cur = cur->next; + } + } + + node->next = cur; + *list = node; + + restore_flags(flags); +} + +static inline void amiga_delete_irq(irq_node_t **list, void *dev_id) +{ + unsigned long flags; + irq_node_t *node; + + save_flags(flags); + cli(); + + for (node = *list; node; list = &node->next, node = *list) { + if (node->dev_id == dev_id) { + *list = node->next; + /* Mark it as free. */ + node->handler = NULL; + restore_flags(flags); + return; + } + } + restore_flags(flags); + printk ("%s: tried to remove invalid irq\n", __FUNCTION__); +} + +/* + * amiga_request_irq : add an interrupt service routine for a particular + * machine specific interrupt source. + * If the addition was successful, it returns 0. + */ + +int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + irq_node_t *node; + + if (irq >= AMI_IRQS) { + printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); + return -ENXIO; + } + + if (irq >= IRQ_AMIGA_AUTO) + return sys_request_irq(irq - IRQ_AMIGA_AUTO, handler, + flags, devname, dev_id); + + if (irq >= IRQ_AMIGA_CIAB) + return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, + handler, flags, devname, dev_id); + + if (irq >= IRQ_AMIGA_CIAA) + return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, + handler, flags, devname, dev_id); + + if (ami_servers[irq]) { + if (!(node = new_irq_node())) + return -ENOMEM; + node->handler = handler; + node->flags = flags; + node->dev_id = dev_id; + node->devname = devname; + node->next = NULL; + amiga_insert_irq(&ami_irq_list[irq], node); + } else { + if (!(ami_irq_list[irq]->flags & IRQ_FLG_STD)) { + if (ami_irq_list[irq]->flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, ami_irq_list[irq]->devname); + return -EBUSY; + } + if (!(flags & IRQ_FLG_REPLACE)) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, ami_irq_list[irq]->devname); + return -EBUSY; + } + } + ami_irq_list[irq]->handler = handler; + ami_irq_list[irq]->flags = flags; + ami_irq_list[irq]->dev_id = dev_id; + ami_irq_list[irq]->devname = devname; + } + + /* enable the interrupt */ + if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq]) + custom.intena = IF_SETCLR | ami_intena_vals[irq]; + + return 0; +} + +void amiga_free_irq(unsigned int irq, void *dev_id) +{ + if (irq >= AMI_IRQS) { + printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (irq >= IRQ_AMIGA_AUTO) + sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id); + + if (irq >= IRQ_AMIGA_CIAB) { + cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id); + return; + } + + if (irq >= IRQ_AMIGA_CIAA) { + cia_free_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, dev_id); + return; + } + + if (ami_servers[irq]) { + amiga_delete_irq(&ami_irq_list[irq], dev_id); + /* if server list empty, disable the interrupt */ + if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS) + custom.intena = ami_intena_vals[irq]; + } else { + if (ami_irq_list[irq]->dev_id != dev_id) + printk("%s: removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, ami_irq_list[irq]->devname); + ami_irq_list[irq]->handler = ami_badint; + ami_irq_list[irq]->flags = IRQ_FLG_STD; + ami_irq_list[irq]->dev_id = NULL; + ami_irq_list[irq]->devname = NULL; + custom.intena = ami_intena_vals[irq]; + } +} + +/* + * Enable/disable a particular machine specific interrupt source. + * Note that this may affect other interrupts in case of a shared interrupt. + * This function should only be called for a _very_ short time to change some + * internal data, that may not be changed by the interrupt at the same time. + * ami_(enable|disable)_irq calls may also be nested. + */ + +void amiga_enable_irq(unsigned int irq) +{ + if (irq >= AMI_IRQS) { + printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (--ami_ablecount[irq]) + return; + + /* No action for auto-vector interrupts */ + if (irq >= IRQ_AMIGA_AUTO){ + printk("%s: Trying to enable auto-vector IRQ %i\n", + __FUNCTION__, irq - IRQ_AMIGA_AUTO); + return; + } + + if (irq >= IRQ_AMIGA_CIAB) { + cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB))); + cia_able_irq(&ciab_base, CIA_ICR_SETCLR | + (1 << (irq - IRQ_AMIGA_CIAB))); + return; + } + + if (irq >= IRQ_AMIGA_CIAA) { + cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA))); + cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | + (1 << (irq - IRQ_AMIGA_CIAA))); + return; + } + + /* enable the interrupt */ + custom.intena = IF_SETCLR | ami_intena_vals[irq]; +} + +void amiga_disable_irq(unsigned int irq) +{ + if (irq >= AMI_IRQS) { + printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (ami_ablecount[irq]++) + return; + + /* No action for auto-vector interrupts */ + if (irq >= IRQ_AMIGA_AUTO) { + printk("%s: Trying to disable auto-vector IRQ %i\n", + __FUNCTION__, irq - IRQ_AMIGA_AUTO); + return; + } + + if (irq >= IRQ_AMIGA_CIAB) { + cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB)); + return; + } + + if (irq >= IRQ_AMIGA_CIAA) { + cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA)); + return; + } + + /* disable the interrupt */ + custom.intena = ami_intena_vals[irq]; +} + +inline void amiga_do_irq(int irq, struct pt_regs *fp) +{ + kstat.irqs[0][SYS_IRQS + irq]++; + ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp); +} + +void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server) +{ + irq_node_t *node, *slow_nodes; + unsigned short flags; + + kstat.irqs[0][SYS_IRQS + irq]++; + if (server->count++) + server->reentrance = 1; + /* serve first fast and normal handlers */ + for (node = ami_irq_list[irq]; + node && (!(node->flags & IRQ_FLG_SLOW)); + node = node->next) + node->handler(irq, node->dev_id, fp); + custom.intreq = ami_intena_vals[irq]; + if (!node) { + server->count--; + return; + } +#ifdef CONFIG_APUS + APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK); + APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET + | (~(fp->mq) & IPLEMU_IPLMASK))); + APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); +#else + save_flags(flags); + restore_flags((flags & ~0x0700) | (fp->sr & 0x0700)); +#endif + /* if slow handlers exists, serve them now */ + slow_nodes = node; + for (;;) { + for (; node; node = node->next) + node->handler(irq, node->dev_id, fp); + /* if reentrance occured, serve slow handlers again */ + custom.intena = ami_intena_vals[irq]; + if (!server->reentrance) { + server->count--; + custom.intena = IF_SETCLR | ami_intena_vals[irq]; + return; + } + server->reentrance = 0; + custom.intena = IF_SETCLR | ami_intena_vals[irq]; + node = slow_nodes; + } +} + +/* + * The builtin Amiga hardware interrupt handlers. + */ + +static void ami_int1(int irq, void *dev_id, struct pt_regs *fp) +{ + unsigned short ints = custom.intreqr & custom.intenar; + + /* if serial transmit buffer empty, interrupt */ + if (ints & IF_TBE) { + custom.intreq = IF_TBE; + amiga_do_irq(IRQ_AMIGA_TBE, fp); + } + + /* if floppy disk transfer complete, interrupt */ + if (ints & IF_DSKBLK) { + custom.intreq = IF_DSKBLK; + amiga_do_irq(IRQ_AMIGA_DSKBLK, fp); + } + + /* if software interrupt set, interrupt */ + if (ints & IF_SOFT) { + custom.intreq = IF_SOFT; + amiga_do_irq(IRQ_AMIGA_SOFT, fp); + } +} + +static void ami_int3(int irq, void *dev_id, struct pt_regs *fp) +{ + unsigned short ints = custom.intreqr & custom.intenar; + static struct irq_server server = {0, 0}; + + /* if a blitter interrupt */ + if (ints & IF_BLIT) { + custom.intreq = IF_BLIT; + amiga_do_irq(IRQ_AMIGA_BLIT, fp); + } + + /* if a copper interrupt */ + if (ints & IF_COPER) { + custom.intreq = IF_COPER; + amiga_do_irq(IRQ_AMIGA_COPPER, fp); + } + + /* if a vertical blank interrupt */ + if (ints & IF_VERTB) + amiga_do_irq_list(IRQ_AMIGA_VERTB, fp, &server); +} + +static void ami_int4(int irq, void *dev_id, struct pt_regs *fp) +{ + unsigned short ints = custom.intreqr & custom.intenar; + + /* if audio 0 interrupt */ + if (ints & IF_AUD0) { + custom.intreq = IF_AUD0; + amiga_do_irq(IRQ_AMIGA_AUD0, fp); + } + + /* if audio 1 interrupt */ + if (ints & IF_AUD1) { + custom.intreq = IF_AUD1; + amiga_do_irq(IRQ_AMIGA_AUD1, fp); + } + + /* if audio 2 interrupt */ + if (ints & IF_AUD2) { + custom.intreq = IF_AUD2; + amiga_do_irq(IRQ_AMIGA_AUD2, fp); + } + + /* if audio 3 interrupt */ + if (ints & IF_AUD3) { + custom.intreq = IF_AUD3; + amiga_do_irq(IRQ_AMIGA_AUD3, fp); + } +} + +static void ami_int5(int irq, void *dev_id, struct pt_regs *fp) +{ + unsigned short ints = custom.intreqr & custom.intenar; + + /* if serial receive buffer full interrupt */ + if (ints & IF_RBF) { + /* acknowledge of IF_RBF must be done by the serial interrupt */ + amiga_do_irq(IRQ_AMIGA_RBF, fp); + } + + /* if a disk sync interrupt */ + if (ints & IF_DSKSYN) { + custom.intreq = IF_DSKSYN; + amiga_do_irq(IRQ_AMIGA_DSKSYN, fp); + } +} + +static void ami_int7(int irq, void *dev_id, struct pt_regs *fp) +{ + panic ("level 7 interrupt received\n"); +} + +void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { + ami_badint, ami_int1, ami_badint, ami_int3, + ami_int4, ami_int5, ami_badint, ami_int7 +}; + +int amiga_get_irq_list(char *buf) +{ + int i, len = 0; + irq_node_t *node; + + for (i = 0; i < AMI_STD_IRQS; i++) { + if (!(node = ami_irq_list[i])) + continue; + if (node->flags & IRQ_FLG_STD) + continue; + len += sprintf(buf+len, "ami %2d: %10u ", i, + kstat.irqs[0][SYS_IRQS + i]); + do { + if (ami_servers[i]) { + if (node->flags & IRQ_FLG_FAST) + len += sprintf(buf+len, "F "); + else if (node->flags & IRQ_FLG_SLOW) + len += sprintf(buf+len, "S "); + else + len += sprintf(buf+len, " "); + } else { + if (node->flags & IRQ_FLG_LOCK) + len += sprintf(buf+len, "L "); + else + len += sprintf(buf+len, " "); + } + len += sprintf(buf+len, "%s\n", node->devname); + if ((node = node->next)) + len += sprintf(buf+len, " "); + } while (node); + } + + len += cia_get_irq_list(&ciaa_base, buf+len); + len += cia_get_irq_list(&ciab_base, buf+len); + return len; +} diff --git a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c index d24aeb621..f79172390 100644 --- a/arch/ppc/amiga/config.c +++ b/arch/ppc/amiga/config.c @@ -2,6 +2,923 @@ #define m68k_num_memory num_memory #define m68k_memory memory +#include <linux/init.h> + +/* machine dependent "kbd-reset" setup function */ +void (*kbd_reset_setup) (char *, int) __initdata = 0; + #include <asm/io.h> -#include "../../m68k/amiga/config.c" +/* + * linux/arch/m68k/amiga/config.c + * + * Copyright (C) 1993 Hamish Macdonald + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +/* + * Miscellaneous Amiga stuff + */ + +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/kd.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/init.h> + +#include <asm/bootinfo.h> +#include <asm/setup.h> +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/amigahw.h> +#include <asm/amigaints.h> +#include <asm/irq.h> +#include <asm/machdep.h> +#include <linux/zorro.h> + +unsigned long amiga_model; +unsigned long amiga_eclock; +unsigned long amiga_masterclock; +unsigned long amiga_colorclock; +unsigned long amiga_chipset; +unsigned char amiga_vblank; +unsigned char amiga_psfreq; +struct amiga_hw_present amiga_hw_present; + +static const char *amiga_models[] = { + "A500", "A500+", "A600", "A1000", "A1200", "A2000", "A2500", "A3000", + "A3000T", "A3000+", "A4000", "A4000T", "CDTV", "CD32", "Draco" +}; + +extern char m68k_debug_device[]; + +static void amiga_sched_init(void (*handler)(int, void *, struct pt_regs *)); +/* amiga specific keyboard functions */ +extern int amiga_keyb_init(void); +extern int amiga_kbdrate (struct kbd_repeat *); +extern void amiga_kbd_reset_setup(char*, int); +/* amiga specific irq functions */ +extern void amiga_init_IRQ (void); +extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); +extern int amiga_request_irq (unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id); +extern void amiga_free_irq (unsigned int irq, void *dev_id); +extern void amiga_enable_irq (unsigned int); +extern void amiga_disable_irq (unsigned int); +static void amiga_get_model(char *model); +static int amiga_get_hardware_list(char *buffer); +extern int amiga_get_irq_list (char *); +/* amiga specific timer functions */ +static unsigned long amiga_gettimeoffset (void); +static void a3000_gettod (int *, int *, int *, int *, int *, int *); +static void a2000_gettod (int *, int *, int *, int *, int *, int *); +static int amiga_hwclk (int, struct hwclk_time *); +static int amiga_set_clock_mmss (unsigned long); +extern void amiga_mksound( unsigned int count, unsigned int ticks ); +#ifdef CONFIG_AMIGA_FLOPPY +extern void amiga_floppy_setup(char *, int *); +#endif +static void amiga_reset (void); +static int amiga_wait_key (struct console *co); +extern void amiga_init_sound(void); +static void amiga_savekmsg_init(void); +static void amiga_mem_console_write(struct console *co, const char *b, + unsigned int count); +void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count); +static void amiga_debug_init(void); +#ifdef CONFIG_HEARTBEAT +static void amiga_heartbeat(int on); +#endif + +static struct console amiga_console_driver = { + "debug", + NULL, /* write */ + NULL, /* read */ + NULL, /* device */ + amiga_wait_key, /* wait_key */ + NULL, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +#ifdef CONFIG_MAGIC_SYSRQ +static char amiga_sysrq_xlate[128] = + "\0001234567890-=\\\000\000" /* 0x00 - 0x0f */ + "qwertyuiop[]\000123" /* 0x10 - 0x1f */ + "asdfghjkl;'\000\000456" /* 0x20 - 0x2f */ + "\000zxcvbnm,./\000+789" /* 0x30 - 0x3f */ + " \177\t\r\r\000\177\000\000\000-\000\000\000\000\000" /* 0x40 - 0x4f */ + "\000\201\202\203\204\205\206\207\210\211()/*+\000" /* 0x50 - 0x5f */ + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */ + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ +#endif + +extern void (*kd_mksound)(unsigned int, unsigned int); + + /* + * Parse an Amiga-specific record in the bootinfo + */ + +int amiga_parse_bootinfo(const struct bi_record *record) +{ + int unknown = 0; + const unsigned long *data = record->data; + + switch (record->tag) { + case BI_AMIGA_MODEL: + amiga_model = *data; + break; + + case BI_AMIGA_ECLOCK: + amiga_eclock = *data; + break; + + case BI_AMIGA_CHIPSET: + amiga_chipset = *data; + break; + + case BI_AMIGA_CHIP_SIZE: + amiga_chip_size = *(const int *)data; + break; + + case BI_AMIGA_VBLANK: + amiga_vblank = *(const unsigned char *)data; + break; + + case BI_AMIGA_PSFREQ: + amiga_psfreq = *(const unsigned char *)data; + break; + + case BI_AMIGA_AUTOCON: + if (zorro_num_autocon < ZORRO_NUM_AUTO) + memcpy(&zorro_autocon[zorro_num_autocon++], + (const struct ConfigDev *)data, + sizeof(struct ConfigDev)); + else + printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); + break; + + case BI_AMIGA_SERPER: + /* serial port period: ignored here */ + break; + + default: + unknown = 1; + } + return(unknown); +} + + /* + * Identify builtin hardware + */ + +__initfunc(static void amiga_identify(void)) +{ + /* Fill in some default values, if necessary */ + if (amiga_eclock == 0) + amiga_eclock = 709379; + + memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); + + printk("Amiga hardware found: "); + if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) + printk("[%s] ", amiga_models[amiga_model-AMI_500]); + + switch(amiga_model) { + case AMI_UNKNOWN: + goto Generic; + + case AMI_600: + case AMI_1200: + AMIGAHW_SET(A1200_IDE); + AMIGAHW_SET(PCMCIA); + case AMI_500: + case AMI_500PLUS: + case AMI_1000: + case AMI_2000: + case AMI_2500: + AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ + goto Generic; + + case AMI_3000: + case AMI_3000T: + AMIGAHW_SET(AMBER_FF); + AMIGAHW_SET(MAGIC_REKICK); + /* fall through */ + case AMI_3000PLUS: + AMIGAHW_SET(A3000_SCSI); + AMIGAHW_SET(A3000_CLK); + AMIGAHW_SET(ZORRO3); + goto Generic; + + case AMI_4000T: + AMIGAHW_SET(A4000_SCSI); + /* fall through */ + case AMI_4000: + AMIGAHW_SET(A4000_IDE); + AMIGAHW_SET(A3000_CLK); + AMIGAHW_SET(ZORRO3); + goto Generic; + + case AMI_CDTV: + case AMI_CD32: + AMIGAHW_SET(CD_ROM); + AMIGAHW_SET(A2000_CLK); /* Is this correct? */ + goto Generic; + + Generic: + AMIGAHW_SET(AMI_VIDEO); + AMIGAHW_SET(AMI_BLITTER); + AMIGAHW_SET(AMI_AUDIO); + AMIGAHW_SET(AMI_FLOPPY); + AMIGAHW_SET(AMI_KEYBOARD); + AMIGAHW_SET(AMI_MOUSE); + AMIGAHW_SET(AMI_SERIAL); + AMIGAHW_SET(AMI_PARALLEL); + AMIGAHW_SET(CHIP_RAM); + AMIGAHW_SET(PAULA); + + switch(amiga_chipset) { + case CS_OCS: + case CS_ECS: + case CS_AGA: + switch (custom.deniseid & 0xf) { + case 0x0c: + AMIGAHW_SET(DENISE_HR); + break; + case 0x08: + AMIGAHW_SET(LISA); + break; + } + break; + default: + AMIGAHW_SET(DENISE); + break; + } + switch ((custom.vposr>>8) & 0x7f) { + case 0x00: + AMIGAHW_SET(AGNUS_PAL); + break; + case 0x10: + AMIGAHW_SET(AGNUS_NTSC); + break; + case 0x20: + case 0x21: + AMIGAHW_SET(AGNUS_HR_PAL); + break; + case 0x30: + case 0x31: + AMIGAHW_SET(AGNUS_HR_NTSC); + break; + case 0x22: + case 0x23: + AMIGAHW_SET(ALICE_PAL); + break; + case 0x32: + case 0x33: + AMIGAHW_SET(ALICE_NTSC); + break; + } + AMIGAHW_SET(ZORRO); + break; + + case AMI_DRACO: + panic("No support for Draco yet"); + + default: + panic("Unknown Amiga Model"); + } + +#define AMIGAHW_ANNOUNCE(name, str) \ + if (AMIGAHW_PRESENT(name)) \ + printk(str) + + AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); + AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); + AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); + AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); + AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); + AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); + AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); + AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); + AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); + AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); + AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); + AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); + AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); + AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); + AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); + AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); + AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); + AMIGAHW_ANNOUNCE(PAULA, "PAULA "); + AMIGAHW_ANNOUNCE(DENISE, "DENISE "); + AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); + AMIGAHW_ANNOUNCE(LISA, "LISA "); + AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); + AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); + AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); + AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); + AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); + AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); + AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); + if (AMIGAHW_PRESENT(ZORRO)) + printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); + printk("\n"); + +#undef AMIGAHW_ANNOUNCE +} + + /* + * Setup the Amiga configuration info + */ + +__initfunc(void config_amiga(void)) +{ + amiga_debug_init(); + amiga_identify(); + + mach_sched_init = amiga_sched_init; + mach_keyb_init = amiga_keyb_init; + mach_kbdrate = amiga_kbdrate; + kbd_reset_setup = amiga_kbd_reset_setup; + mach_init_IRQ = amiga_init_IRQ; + mach_default_handler = &amiga_default_handler; +#ifndef CONFIG_APUS + mach_request_irq = amiga_request_irq; + mach_free_irq = amiga_free_irq; + enable_irq = amiga_enable_irq; + disable_irq = amiga_disable_irq; +#endif + mach_get_model = amiga_get_model; + mach_get_hardware_list = amiga_get_hardware_list; + mach_get_irq_list = amiga_get_irq_list; + mach_gettimeoffset = amiga_gettimeoffset; + if (AMIGAHW_PRESENT(A3000_CLK)){ + mach_gettod = a3000_gettod; + } + else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */ + mach_gettod = a2000_gettod; + } + + mach_max_dma_address = 0xffffffff; /* + * default MAX_DMA=0xffffffff + * on all machines. If we don't + * do so, the SCSI code will not + * be able to allocate any mem + * for transfers, unless we are + * dealing with a Z2 mem only + * system. /Jes + */ + + mach_hwclk = amiga_hwclk; + mach_set_clock_mmss = amiga_set_clock_mmss; +#ifdef CONFIG_AMIGA_FLOPPY + mach_floppy_setup = amiga_floppy_setup; +#endif + mach_reset = amiga_reset; + conswitchp = &dummy_con; + kd_mksound = amiga_mksound; +#ifdef CONFIG_MAGIC_SYSRQ + mach_sysrq_key = 0x5f; /* HELP */ + mach_sysrq_shift_state = 0x03; /* SHIFT+ALTGR */ + mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ + mach_sysrq_xlate = amiga_sysrq_xlate; +#endif +#ifdef CONFIG_HEARTBEAT + mach_heartbeat = amiga_heartbeat; +#endif + + /* Fill in the clock values (based on the 700 kHz E-Clock) */ + amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ + amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ + + /* clear all DMA bits */ + custom.dmacon = DMAF_ALL; + /* ensure that the DMA master bit is set */ + custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + + /* initialize chipram allocator */ + amiga_chip_init (); + + /* debugging using chipram */ + if (!strcmp( m68k_debug_device, "mem" )){ + if (!AMIGAHW_PRESENT(CHIP_RAM)) + printk("Warning: no chipram present for debugging\n"); + else { + amiga_savekmsg_init(); + amiga_console_driver.write = amiga_mem_console_write; + register_console(&amiga_console_driver); + } + } + + /* our beloved beeper */ + if (AMIGAHW_PRESENT(AMI_AUDIO)) + amiga_init_sound(); + + /* + * if it is an A3000, set the magic bit that forces + * a hard rekick + */ + if (AMIGAHW_PRESENT(MAGIC_REKICK)) + *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; +} + +static unsigned short jiffy_ticks; + +__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *, + struct pt_regs *))) +{ + jiffy_ticks = (amiga_eclock+HZ/2)/HZ; + + ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ + ciab.talo = jiffy_ticks % 256; + ciab.tahi = jiffy_ticks / 256; + + /* install interrupt service routine for CIAB Timer A + * + * Please don't change this to use ciaa, as it interferes with the + * SCSI code. We'll have to take a look at this later + */ + request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK, + "timer", NULL); + /* start timer */ + ciab.cra |= 0x11; +} + +#define TICK_SIZE 10000 + +/* This is always executed with interrupts disabled. */ +static unsigned long amiga_gettimeoffset (void) +{ + unsigned short hi, lo, hi2; + unsigned long ticks, offset = 0; + + /* read CIA B timer A current value */ + hi = ciab.tahi; + lo = ciab.talo; + hi2 = ciab.tahi; + + if (hi != hi2) { + lo = ciab.talo; + hi = hi2; + } + + ticks = hi << 8 | lo; + + if (ticks > jiffy_ticks / 2) + /* check for pending interrupt */ + if (cia_set_irq(&ciab_base, 0) & CIA_ICR_TA) + offset = 10000; + + ticks = jiffy_ticks - ticks; + ticks = (10000 * ticks) / jiffy_ticks; + + return ticks + offset; +} + +static void a3000_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + volatile struct tod3000 *tod = TOD_3000; + + tod->cntrl1 = TOD3000_CNTRL1_HOLD; + + *secp = tod->second1 * 10 + tod->second2; + *minp = tod->minute1 * 10 + tod->minute2; + *hourp = tod->hour1 * 10 + tod->hour2; + *dayp = tod->day1 * 10 + tod->day2; + *monp = tod->month1 * 10 + tod->month2; + *yearp = tod->year1 * 10 + tod->year2; + + tod->cntrl1 = TOD3000_CNTRL1_FREE; +} + +static void a2000_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + volatile struct tod2000 *tod = TOD_2000; + + tod->cntrl1 = TOD2000_CNTRL1_HOLD; + + while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) + ; + + *secp = tod->second1 * 10 + tod->second2; + *minp = tod->minute1 * 10 + tod->minute2; + *hourp = (tod->hour1 & 3) * 10 + tod->hour2; + *dayp = tod->day1 * 10 + tod->day2; + *monp = tod->month1 * 10 + tod->month2; + *yearp = tod->year1 * 10 + tod->year2; + + if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ + if (!(tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12) + *hourp = 0; + else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12) + *hourp += 12; + } + + tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; +} + +static int amiga_hwclk(int op, struct hwclk_time *t) +{ + if (AMIGAHW_PRESENT(A3000_CLK)) { + volatile struct tod3000 *tod = TOD_3000; + + tod->cntrl1 = TOD3000_CNTRL1_HOLD; + + if (!op) { /* read */ + t->sec = tod->second1 * 10 + tod->second2; + t->min = tod->minute1 * 10 + tod->minute2; + t->hour = tod->hour1 * 10 + tod->hour2; + t->day = tod->day1 * 10 + tod->day2; + t->wday = tod->weekday; + t->mon = tod->month1 * 10 + tod->month2 - 1; + t->year = tod->year1 * 10 + tod->year2; + } else { + tod->second1 = t->sec / 10; + tod->second2 = t->sec % 10; + tod->minute1 = t->min / 10; + tod->minute2 = t->min % 10; + tod->hour1 = t->hour / 10; + tod->hour2 = t->hour % 10; + tod->day1 = t->day / 10; + tod->day2 = t->day % 10; + if (t->wday != -1) + tod->weekday = t->wday; + tod->month1 = (t->mon + 1) / 10; + tod->month2 = (t->mon + 1) % 10; + tod->year1 = t->year / 10; + tod->year2 = t->year % 10; + } + + tod->cntrl1 = TOD3000_CNTRL1_FREE; + } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { + volatile struct tod2000 *tod = TOD_2000; + + tod->cntrl1 = TOD2000_CNTRL1_HOLD; + + while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) + ; + + if (!op) { /* read */ + t->sec = tod->second1 * 10 + tod->second2; + t->min = tod->minute1 * 10 + tod->minute2; + t->hour = (tod->hour1 & 3) * 10 + tod->hour2; + t->day = tod->day1 * 10 + tod->day2; + t->wday = tod->weekday; + t->mon = tod->month1 * 10 + tod->month2 - 1; + t->year = tod->year1 * 10 + tod->year2; + + if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ + if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12) + t->hour = 0; + else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->hour != 12) + t->hour += 12; + } + } else { + tod->second1 = t->sec / 10; + tod->second2 = t->sec % 10; + tod->minute1 = t->min / 10; + tod->minute2 = t->min % 10; + if (tod->cntrl3 & TOD2000_CNTRL3_24HMODE) + tod->hour1 = t->hour / 10; + else if (t->hour >= 12) + tod->hour1 = TOD2000_HOUR1_PM + + (t->hour - 12) / 10; + else + tod->hour1 = t->hour / 10; + tod->hour2 = t->hour % 10; + tod->day1 = t->day / 10; + tod->day2 = t->day % 10; + if (t->wday != -1) + tod->weekday = t->wday; + tod->month1 = (t->mon + 1) / 10; + tod->month2 = (t->mon + 1) % 10; + tod->year1 = t->year / 10; + tod->year2 = t->year % 10; + } + + tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; + } + + return 0; +} + +static int amiga_set_clock_mmss (unsigned long nowtime) +{ + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + + if (AMIGAHW_PRESENT(A3000_CLK)) { + volatile struct tod3000 *tod = TOD_3000; + + tod->cntrl1 = TOD3000_CNTRL1_HOLD; + + tod->second1 = real_seconds / 10; + tod->second2 = real_seconds % 10; + tod->minute1 = real_minutes / 10; + tod->minute2 = real_minutes % 10; + + tod->cntrl1 = TOD3000_CNTRL1_FREE; + } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { + volatile struct tod2000 *tod = TOD_2000; + + tod->cntrl1 = TOD2000_CNTRL1_HOLD; + + while (tod->cntrl1 & TOD2000_CNTRL1_BUSY) + ; + + tod->second1 = real_seconds / 10; + tod->second2 = real_seconds % 10; + tod->minute1 = real_minutes / 10; + tod->minute2 = real_minutes % 10; + + tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; + } + + return 0; +} + +static int amiga_wait_key (struct console *co) +{ + int i; + + while (1) { + while (ciaa.pra & 0x40); + + /* debounce */ + for (i = 0; i < 1000; i++); + + if (!(ciaa.pra & 0x40)) + break; + } + + /* wait for button up */ + while (1) { + while (!(ciaa.pra & 0x40)); + + /* debounce */ + for (i = 0; i < 1000; i++); + + if (ciaa.pra & 0x40) + break; + } + return 0; +} + +void dbprintf(const char *fmt , ...) +{ + static char buf[1024]; + va_list args; + extern void console_print (const char *str); + extern int vsprintf(char * buf, const char * fmt, va_list args); + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + console_print (buf); +} + +static NORET_TYPE void amiga_reset( void ) + ATTRIB_NORET; + +static void amiga_reset (void) +{ + for (;;); +} + + + /* + * Debugging + */ + +#define SAVEKMSG_MAXMEM 128*1024 + +#define SAVEKMSG_MAGIC1 0x53415645 /* 'SAVE' */ +#define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ + +struct savekmsg { + unsigned long magic1; /* SAVEKMSG_MAGIC1 */ + unsigned long magic2; /* SAVEKMSG_MAGIC2 */ + unsigned long magicptr; /* address of magic1 */ + unsigned long size; + char data[0]; +}; + +static struct savekmsg *savekmsg = NULL; + +static void amiga_mem_console_write(struct console *co, const char *s, + unsigned int count) +{ + if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { + memcpy(savekmsg->data+savekmsg->size, s, count); + savekmsg->size += count; + } +} + +static void amiga_savekmsg_init(void) +{ + savekmsg = (struct savekmsg *)amiga_chip_alloc(SAVEKMSG_MAXMEM); + savekmsg->magic1 = SAVEKMSG_MAGIC1; + savekmsg->magic2 = SAVEKMSG_MAGIC2; + savekmsg->magicptr = virt_to_phys(savekmsg); + savekmsg->size = 0; +} + +static void amiga_serial_putc(char c) +{ + custom.serdat = (unsigned char)c | 0x100; + iobarrier (); + while (!(custom.serdatr & 0x2000)) + ; +} + +void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count) +{ +#if 0 /* def CONFIG_KGDB */ + /* FIXME:APUS GDB doesn't seem to like O-packages before it is + properly connected with the target. */ + __gdb_output_string (s, count); +#else + while (count--) { + if (*s == '\n') + amiga_serial_putc('\r'); + amiga_serial_putc(*s++); + } +#endif +} + +#ifdef CONFIG_SERIAL_CONSOLE +void amiga_serial_puts(const char *s) +{ + amiga_serial_console_write(NULL, s, strlen(s)); +} + +int amiga_serial_console_wait_key(struct console *co) +{ + int ch; + + while (!(custom.intreqr & IF_RBF)) + barrier(); + ch = custom.serdatr & 0xff; + /* clear the interrupt, so that another character can be read */ + custom.intreq = IF_RBF; + return ch; +} + +void amiga_serial_gets(struct console *co, char *s, int len) +{ + int ch, cnt = 0; + + while (1) { + ch = amiga_serial_console_wait_key(co); + + /* Check for backspace. */ + if (ch == 8 || ch == 127) { + if (cnt == 0) { + amiga_serial_putc('\007'); + continue; + } + cnt--; + amiga_serial_puts("\010 \010"); + continue; + } + + /* Check for enter. */ + if (ch == 10 || ch == 13) + break; + + /* See if line is too long. */ + if (cnt >= len + 1) { + amiga_serial_putc(7); + cnt--; + continue; + } + + /* Store and echo character. */ + s[cnt++] = ch; + amiga_serial_putc(ch); + } + /* Print enter. */ + amiga_serial_puts("\r\n"); + s[cnt] = 0; +} +#endif + +__initfunc(static void amiga_debug_init(void)) +{ + if (!strcmp( m68k_debug_device, "ser" )) { + /* no initialization required (?) */ + amiga_console_driver.write = amiga_serial_console_write; + register_console(&amiga_console_driver); + } +} + +#ifdef CONFIG_HEARTBEAT +static void amiga_heartbeat(int on) +{ + if (on) + ciaa.pra &= ~2; + else + ciaa.pra |= 2; +} +#endif + + /* + * Amiga specific parts of /proc + */ + +static void amiga_get_model(char *model) +{ + strcpy(model, "Amiga "); + if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) + strcat(model, amiga_models[amiga_model-AMI_500]); +} + + +static int amiga_get_hardware_list(char *buffer) +{ + int len = 0; + + if (AMIGAHW_PRESENT(CHIP_RAM)) + len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); + len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", + amiga_psfreq, amiga_eclock); + if (AMIGAHW_PRESENT(AMI_VIDEO)) { + char *type; + switch(amiga_chipset) { + case CS_OCS: + type = "OCS"; + break; + case CS_ECS: + type = "ECS"; + break; + case CS_AGA: + type = "AGA"; + break; + default: + type = "Old or Unknown"; + break; + } + len += sprintf(buffer+len, "Graphics:\t%s\n", type); + } + +#define AMIGAHW_ANNOUNCE(name, str) \ + if (AMIGAHW_PRESENT(name)) \ + len += sprintf (buffer+len, "\t%s\n", str) + + len += sprintf (buffer + len, "Detected hardware:\n"); + + AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); + AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); + AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); + AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); + AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); + AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); + AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); + AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); + AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); + AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); + AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); + AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); + AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); + AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); + AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); + AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); + AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); + AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); + AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); + AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); + AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); + AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); + AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); + AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); + AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); + AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); + AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); + AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); + if (AMIGAHW_PRESENT(ZORRO)) + len += sprintf(buffer+len, "\tZorro%s AutoConfig: %d Expansion Device%s\n", + AMIGAHW_PRESENT(ZORRO3) ? " III" : "", + zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); + +#undef AMIGAHW_ANNOUNCE + + return(len); +} diff --git a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c index b14a59b53..65f94d778 100644 --- a/arch/ppc/amiga/time.c +++ b/arch/ppc/amiga/time.c @@ -1,3 +1,4 @@ +#include <linux/config.h> /* CONFIG_HEARTBEAT */ #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -68,3 +69,24 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon, } +void apus_heartbeat (void) +{ +#ifdef CONFIG_HEARTBEAT + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; + dist = period / 4; + } +#endif +} diff --git a/arch/ppc/apus_defconfig b/arch/ppc/apus_defconfig index a5f0d2e3c..1e9499a9c 100644 --- a/arch/ppc/apus_defconfig +++ b/arch/ppc/apus_defconfig @@ -8,11 +8,11 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_8xx is not set -# CONFIG_PMAC is not set +CONFIG_PMAC=y # CONFIG_PREP is not set # CONFIG_CHRP is not set # CONFIG_ALL_PPC is not set -CONFIG_APUS=y +# CONFIG_APUS is not set # CONFIG_MBX is not set CONFIG_MACH_SPECIFIC=y @@ -20,42 +20,33 @@ CONFIG_MACH_SPECIFIC=y # General setup # CONFIG_EXPERIMENTAL=y -# CONFIG_MODULES is not set -# CONFIG_PCI is not set -# CONFIG_PCI_OLD_PROC is not set +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y +CONFIG_PCI=y +# CONFIG_PCI_QUIRKS is not set +CONFIG_PCI_OLD_PROC=y CONFIG_NET=y -# CONFIG_SYSCTL is not set +CONFIG_SYSCTL=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_MISC=m # CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set -CONFIG_ABSTRACT_CONSOLE=y -CONFIG_FB=y # CONFIG_VGA_CONSOLE is not set -# CONFIG_FB_COMPAT_XPMAC is not set -# CONFIG_MAC_KEYBOARD is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MACMOUSE is not set -# CONFIG_PROC_DEVICETREE is not set +CONFIG_FB=y +CONFIG_FB_COMPAT_XPMAC=y +CONFIG_PMAC_PBOOK=y +CONFIG_MAC_KEYBOARD=y +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +CONFIG_ADBMOUSE=y +CONFIG_PROC_DEVICETREE=y # CONFIG_KGDB is not set # CONFIG_XMON is not set -CONFIG_FB_CONSOLE=y -CONFIG_AMIGA=y -CONFIG_ZORRO=y -CONFIG_AMIGAMOUSE=y -CONFIG_ABSTRACT_CONSOLE=y -CONFIG_FB=y -CONFIG_AMIGA_FLOPPY=y -CONFIG_AMIGA_BUILTIN_SERIAL=y -CONFIG_GVPIOEXT=y -# CONFIG_GVPIOEXT_LP is not set -# CONFIG_GVPIOEXT_PLIP is not set -CONFIG_MULTIFACE_III_TTY=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_PROC_HARDWARE is not set +# CONFIG_TOTALMP is not set # # Plug and Play support @@ -63,7 +54,7 @@ CONFIG_MULTIFACE_III_TTY=y # CONFIG_PNP is not set # -# Floppy, IDE, and other block devices +# Block devices # # CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y @@ -71,20 +62,27 @@ CONFIG_BLK_DEV_IDE=y # # Please see Documentation/ide.txt for help/info on IDE drives # -CONFIG_BLK_DEV_GAYLE=y # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_PMAC_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set # # Additional Block Devices # # CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y @@ -96,30 +94,30 @@ CONFIG_PARIDE_PARPORT=y # # Networking options # -# CONFIG_PACKET is not set -# CONFIG_NETLINK is not set +CONFIG_PACKET=y +CONFIG_NETLINK=y +# CONFIG_RTNETLINK is not set +# CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set -# CONFIG_NET_ALIAS is not set +CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_PNP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -# CONFIG_IP_ACCT is not set +# CONFIG_IP_PNP is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_ALIAS=y # CONFIG_SYN_COOKIES is not set # # (it is safe to leave these untouched) # CONFIG_INET_RARP=y -# CONFIG_IP_NOSR is not set +CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set @@ -127,7 +125,7 @@ CONFIG_SKB_LARGE=y # # # CONFIG_IPX is not set -# CONFIG_ATALK is not set +CONFIG_ATALK=m # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set @@ -138,7 +136,6 @@ CONFIG_SKB_LARGE=y # CONFIG_NET_HW_FLOWCONTROL is not set # CONFIG_CPU_IS_SLOW is not set # CONFIG_NET_SCHED is not set -# CONFIG_NET_PROFILE is not set # # SCSI support @@ -149,7 +146,7 @@ CONFIG_SCSI=y # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set +CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set @@ -158,7 +155,7 @@ CONFIG_BLK_DEV_SR_VENDOR=y # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # # CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set +CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set # @@ -168,7 +165,10 @@ CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -# CONFIG_SCSI_AIC7XXX is not set +CONFIG_SCSI_AIC7XXX=y +# CONFIG_OVERRIDE_CMDS is not set +CONFIG_AIC7XXX_PROC_STATS=y +CONFIG_AIC7XXX_RESET_DELAY=15 # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -181,24 +181,23 @@ CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set # CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_MESH is not set -CONFIG_A3000_SCSI=y -CONFIG_A2091_SCSI=y -CONFIG_GVP11_SCSI=y -CONFIG_FASTLANE_SCSI=y -# CONFIG_A4000T_SCSI is not set -# CONFIG_A4091_SCSI is not set -# CONFIG_SCSI_MAC53C94 is not set +CONFIG_SCSI_MESH=y +CONFIG_SCSI_MESH_SYNC_RATE=5 +CONFIG_SCSI_MAC53C94=y # # Network device support @@ -207,31 +206,51 @@ CONFIG_NETDEVICES=y # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set +# CONFIG_ETHERTAP is not set CONFIG_NET_ETHERNET=y -CONFIG_ARIADNE=y -CONFIG_A2065=y -CONFIG_HYDRA=y +CONFIG_MACE=y +CONFIG_BMAC=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_RTL8139 is not set +# CONFIG_YELLOWFIN is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +CONFIG_NET_EISA=y +# CONFIG_PCNET32 is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +CONFIG_DE4X5=y +CONFIG_DEC_ELCP=m +# CONFIG_DGRS is not set +# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set +# CONFIG_HIPPI is not set # CONFIG_DLCI is not set +# CONFIG_LTPC is not set +# CONFIG_COPS is not set +# CONFIG_IPDDP is not set CONFIG_PPP=y # # CCP compressors for PPP are only built as modules. # -CONFIG_SLIP=y -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -# CONFIG_SLIP_MODE_SLIP6 is not set +# CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set # CONFIG_TR is not set # CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set # # Amateur Radio support @@ -249,21 +268,71 @@ CONFIG_SLIP_SMART=y # CONFIG_CD_NO_IDESCSI is not set # +# Console drivers +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_ATY=y +CONFIG_FB_IMSTT=y +CONFIG_FB_CT65550=y +# CONFIG_FB_S3TRIO is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_SUN8x16=y +CONFIG_FONT_SUN12x22=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +CONFIG_NVRAM=y +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# # Filesystems # # CONFIG_QUOTA is not set -CONFIG_MINIX_FS=y +# CONFIG_MINIX_FS is not set CONFIG_EXT2_FS=y CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -CONFIG_VFAT_FS=y +CONFIG_VFAT_FS=m CONFIG_PROC_FS=y CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set -# CONFIG_NFSD is not set +CONFIG_NFSD=y CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_CODA_FS is not set @@ -271,27 +340,24 @@ CONFIG_LOCKD=y # CONFIG_HPFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_SYSV_FS is not set -CONFIG_AFFS_FS=y -# CONFIG_HFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_HFS_FS=y # CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set +CONFIG_AUTOFS_FS=y # CONFIG_UFS_FS is not set - -# -# Partition Tables -# -CONFIG_AMIGA_PARTITION=y -# CONFIG_FOREIGN_PARTITIONS is not set # CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set # CONFIG_SOLARIS_X86_PARTITION is not set +CONFIG_DEVPTS_FS=y # CONFIG_ADFS_FS is not set -# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_MAC_PARTITION=y CONFIG_NLS=y # # Native Language Support # -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set # CONFIG_NLS_CODEPAGE_850 is not set @@ -319,55 +385,13 @@ CONFIG_NLS=y # CONFIG_NLS_KOI8_R is not set # -# Frame buffer devices -# -CONFIG_FB_AMIGA=y -CONFIG_FB_AMIGA_OCS=y -CONFIG_FB_AMIGA_ECS=y -CONFIG_FB_AMIGA_AGA=y -CONFIG_FB_CYBER=y -CONFIG_FB_VIRGE=y -CONFIG_FB_RETINAZ3=y -# CONFIG_FB_OF is not set -# CONFIG_FB_S3TRIO is not set -CONFIG_FB_VIRTUAL=y -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_MFB=y -CONFIG_FBCON_ILBM=y -CONFIG_FBCON_AFB=y -CONFIG_FBCON_MAC=y -CONFIG_FBCON_CFB2=y -CONFIG_FBCON_CFB4=y -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_CFB24=y -CONFIG_FBCON_CFB32=y - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_MOUSE is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set -# CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_VIDEO_DEV is not set -# CONFIG_NVRAM is not set -# CONFIG_JOYSTICK is not set -# CONFIG_MISC_RADIO is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set - -# # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +CONFIG_DMASOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index f0843e17c..fde1ad4c6 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -20,20 +20,25 @@ .S.o: $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< - ZOFF = 0 ZSZ = 0 IOFF = 0 ISZ = 0 + +ifeq ($(CONFIG_ALL_PPC),y) +# yes, we want to build prep stuff +CONFIG_PREP = y +endif + ifeq ($(CONFIG_MBX),y) ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00100000 else -#ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000 ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00600000 endif + GZIP_FLAGS = -v9 -OBJECTS := head.o misc.o ../coffboot/zlib.o # inflate.o unzip.o +OBJECTS := head.o misc.o ../coffboot/zlib.o CFLAGS = -O2 -DSTDC_HEADERS -fno-builtin -I$(TOPDIR)/include OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY_ARGS = -O elf32-powerpc @@ -47,10 +52,6 @@ endif all: zImage -ifeq ($(CONFIG_ALL_PPC),y) -CONFIG_PREP = y -endif - ifeq ($(CONFIG_PREP),y) zvmlinux.initrd: zvmlinux $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) @@ -58,10 +59,10 @@ zvmlinux.initrd: zvmlinux --add-section=initrd=ramdisk.image.gz \ --add-section=image=../coffboot/vmlinux.gz \ zvmlinux.initrd.tmp zvmlinux.initrd - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset zvmlinux.initrd initrd` \ - -DINITRD_SIZE=`sh size zvmlinux.initrd initrd` \ - -DZIMAGE_OFFSET=`sh offset zvmlinux.initrd image` \ - -DZIMAGE_SIZE=`sh size zvmlinux.initrd image` \ + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \ + -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ @@ -77,10 +78,10 @@ zvmlinux.initrd: zvmlinux --add-section=initrd=ramdisk.image.gz \ --add-section=image=../coffboot/vmlinux.gz \ zvmlinux.initrd.tmp zvmlinux.initrd - $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset zvmlinux.initrd initrd` \ - -DINITRD_SIZE=`sh size zvmlinux.initrd initrd` \ - -DZIMAGE_OFFSET=`sh offset zvmlinux.initrd image` \ - -DZIMAGE_SIZE=`sh size zvmlinux.initrd image` \ + $(CC) $(CFLAGS) -DINITRD_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd initrd` \ + -DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \ -DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \ @@ -90,19 +91,24 @@ zvmlinux.initrd: zvmlinux rm zvmlinux.initrd.tmp endif -zImage: zvmlinux mkprep ifeq ($(CONFIG_PREP),y) +zImage: zvmlinux mkprep ./mkprep -pbp zvmlinux zImage -endif +else ifeq ($(CONFIG_MBX),y) +zImage: zvmlinux ln -sf zvmlinux zImage +else +zImage: +endif endif -zImage.initrd: zvmlinux.initrd mkprep ifeq ($(CONFIG_PREP),y) +zImage.initrd: zvmlinux.initrd mkprep ./mkprep -pbp zvmlinux.initrd zImage.initrd endif ifeq ($(CONFIG_MBX),y) +zImage.initrd: zvmlinux.initrd ln -sf zvmlinux.initrd zImage.initrd endif @@ -118,8 +124,8 @@ zvmlinux: $(OBJECTS) ../coffboot/vmlinux.gz # then with the offset rebuild the bootloader so we know where the kernel is # $(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \ - -DZIMAGE_OFFSET=`sh offset zvmlinux image` \ - -DZIMAGE_SIZE=`sh size zvmlinux image` -DKERNELBASE=$(KERNELBASE) \ + -DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \ + -DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \ -c -o misc.o misc.c $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS) $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \ @@ -131,17 +137,21 @@ ifeq ($(CONFIG_PREP),y) dd if=zImage of=/dev/fd0H1440 bs=64b endif -mkprep : mkprep.c ifeq ($(CONFIG_PREP),y) +mkprep : mkprep.c $(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c endif -znetboot : zImage ifeq ($(CONFIG_PREP),y) +znetboot : zImage cp zImage /tftpboot/zImage.prep -endif +else ifeq ($(CONFIG_MBX),y) +znetboot : zImage cp zImage /tftpboot/zImage.mbx +else +znetboot : +endif endif znetboot.initrd : zImage.initrd diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S index fe03a46f7..43facf7e2 100644 --- a/arch/ppc/boot/head.S +++ b/arch/ppc/boot/head.S @@ -7,7 +7,7 @@ .text /* - * $Id: head.S,v 1.24 1998/07/21 02:43:50 cort Exp $ + * $Id: head.S,v 1.26 1998/09/19 01:21:20 cort Exp $ * * This code is loaded by the ROM loader at some arbitrary location. * Move it to high memory so that it can load the kernel at 0x0000. @@ -144,6 +144,11 @@ start_ldr: mr r3, r11 mr r21, r11 bl serial_init /* Init MBX serial port */ + + lis r8, 0xfa200000@h /* Disable Ethernet SCC */ + li r0, 0 + stw r0, 0x0a00(r8) + mr r11, r21 lis r8,start@h ori r8,r8,start@l @@ -166,6 +171,7 @@ start_ldr: as ptr to residual -- Cort*/ lis r6,cmd_line@h ori r6,r6,cmd_line@l + lwz r6, 0(r6) subi r7,r6,1 00: lbzu r2,1(r7) cmpi 0,r2,0 diff --git a/arch/ppc/boot/mbxtty.c b/arch/ppc/boot/mbxtty.c index 3d4105034..e5566dc32 100644 --- a/arch/ppc/boot/mbxtty.c +++ b/arch/ppc/boot/mbxtty.c @@ -12,14 +12,22 @@ * I f**ked around for a day trying to figure out how to make EPPC-Bug * use SMC1, but gave up and decided to fix it here. */ +#include <linux/config.h> #include <linux/types.h> +#ifdef CONFIG_MBX #include <asm/mbx.h> +#endif +#ifdef CONFIG_FADS +#include <asm/fads.h> +#endif #include "../8xx_io/commproc.h" +#ifdef CONFIG_MBX #define MBX_CSR1 ((volatile u_char *)0xfa100000) #define CSR1_COMEN (u_char)0x02 +#endif -static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)MBX_IMAP_ADDR)->im_cpm); +static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); void serial_init(bd_t *bd) @@ -38,6 +46,7 @@ serial_init(bd_t *bd) */ sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); +#ifdef CONFIG_MBX if (*MBX_CSR1 & CSR1_COMEN) { /* COM1 is enabled. Initialize SMC1 and use it for * the console port. @@ -45,7 +54,7 @@ serial_init(bd_t *bd) /* Enable SDMA. */ - ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; + ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1; /* Use Port B for SMCs instead of other functions. */ @@ -103,6 +112,7 @@ serial_init(bd_t *bd) *MBX_CSR1 &= ~CSR1_COMEN; } else { +#endif /* SMC1 is used as console port. */ tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase]; @@ -113,7 +123,9 @@ serial_init(bd_t *bd) cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC1, CPM_CR_STOP_TX) | CPM_CR_FLG; while (cp->cp_cpcr & CPM_CR_FLG); +#ifdef CONFIG_MBX } +#endif /* Make the first buffer the only buffer. */ diff --git a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c index 869fb9f1d..42cb533da 100644 --- a/arch/ppc/boot/misc.c +++ b/arch/ppc/boot/misc.c @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.49 1998/07/26 21:29:15 geert Exp $ + * $Id: misc.c,v 1.52 1998/09/19 01:21:24 cort Exp $ * * Adapted for PowerPC by Gary Thomas * @@ -9,6 +9,7 @@ * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort */ +#include <linux/types.h> #include "../coffboot/zlib.h" #include "asm/residual.h" #include <elf.h> @@ -18,7 +19,9 @@ #include <asm/mmu.h> #ifdef CONFIG_MBX #include <asm/mbx.h> -bd_t hold_board_info; +#endif +#ifdef CONFIG_FADS +#include <asm/fads.h> #endif /* @@ -31,8 +34,30 @@ bd_t hold_board_info; char *avail_ram; char *end_avail; -char cmd_line[256]; -RESIDUAL hold_residual; +/* Because of the limited amount of memory on the MBX, it presents + * loading problems. The biggest is that we load this boot program + * into a relatively low memory address, and the Linux kernel Bss often + * extends into this space when it get loaded. When the kernel starts + * and zeros the BSS space, it also writes over the information we + * save here and pass to the kernel (command line and board info). + * On the MBX we grab some known memory holes to hold this information. + */ +char cmd_buf[256]; +char *cmd_line = cmd_buf; + +#if defined(CONFIG_MBX) || defined(CONFIG_FADS) +char *root_string = "root=/dev/nfs"; +char *nfsaddrs_string = "nfsaddrs="; +char *nfsroot_string = "nfsroot="; +char *defroot_string = "/sys/mbxroot"; +int do_ipaddrs(char **cmd_cp, int echo); +void do_nfsroot(char **cmd_cp, char *dp); +int strncmp(const char * cs,const char * ct,size_t count); +char *strrchr(const char * s, int c); +#endif + +RESIDUAL hold_resid_buf; +RESIDUAL *hold_residual = &hold_resid_buf; unsigned long initrd_start = 0, initrd_end = 0; char *zimage_start; int zimage_size; @@ -60,7 +85,7 @@ void exit() while(1); } -#ifndef CONFIG_MBX +#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS) static void clear_screen() { int i, j; @@ -311,6 +336,9 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R unsigned long i; BATU *u; BATL *l; +#if defined(CONFIG_MBX) || defined(CONFIG_KB) + char *dp; +#endif lines = 25; cols = 80; @@ -318,7 +346,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R orig_y = 24; -#ifndef CONFIG_MBX +#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS) /* * IBM's have the MMU on, so we have to disable it or * things get really unhappy in the kernel when @@ -331,18 +359,30 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R vga_init(0xC0000000); if (residual) - memcpy(&hold_residual,residual,sizeof(RESIDUAL)); + memcpy(hold_residual,residual,sizeof(RESIDUAL)); #else /* CONFIG_MBX */ + + /* Grab some space for the command line and board info. Since + * we no longer use the ELF header, but it was loaded, grab + * that space. + */ + cmd_line = (char *)(load_addr - 0x10000); + hold_residual = (RESIDUAL *)(cmd_line + sizeof(cmd_buf)); /* copy board data */ if (residual) - _bcopy((char *)residual, (char *)&hold_board_info, - sizeof(hold_board_info)); + memcpy(hold_residual,residual,sizeof(bd_t)); #endif /* CONFIG_MBX */ /* MBX/prep sometimes put the residual/board info at the end of mem * assume 16M for now -- Cort + * To boot on standard MBX boards with 4M, we can't use initrd, + * and we have to assume less memory. -- Dan */ - end_avail = (char *)0x01000000; + if ( INITRD_OFFSET ) + end_avail = (char *)0x01000000; + else + end_avail = (char *)0x00400000; + /* let residual data tell us it's higher */ if ( (unsigned long)residual > 0x00800000 ) end_avail = (char *)PAGE_ALIGN((unsigned long)residual); @@ -361,23 +401,19 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R { puts("board data at: "); puthex((unsigned long)residual); puts(" "); -#ifdef CONFIG_MBX +#if defined(CONFIG_MBX) || defined(CONFIG_FADS) puthex((unsigned long)((unsigned long)residual + sizeof(bd_t))); #else puthex((unsigned long)((unsigned long)residual + sizeof(RESIDUAL))); #endif puts("\n"); puts("relocated to: "); -#ifdef CONFIG_MBX - puthex((unsigned long)&hold_board_info); -#else - puthex((unsigned long)&hold_residual); -#endif + puthex((unsigned long)hold_residual); puts(" "); -#ifdef CONFIG_MBX - puthex((unsigned long)((unsigned long)&hold_board_info + sizeof(bd_t))); +#if defined(CONFIG_MBX) || defined(CONFIG_FADS) + puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t))); #else - puthex((unsigned long)((unsigned long)&hold_residual + sizeof(RESIDUAL))); + puthex((unsigned long)((unsigned long)hold_residual + sizeof(RESIDUAL))); #endif puts("\n"); } @@ -411,8 +447,11 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R /* * don't relocate the zimage if it was loaded above 16M since * things get weird if we try to relocate -- Cort + * We don't relocate zimage on a base MBX board because of + * insufficient memory. In this case we don't have initrd either, + * so use that as an indicator. -- Dan */ - if ( (unsigned long)zimage_start <= 0x01000000 ) + if (( (unsigned long)zimage_start <= 0x01000000 ) && initrd_start) { memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-zimage_size), (void *)zimage_start, zimage_size ); @@ -439,6 +478,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R * max ram is. * -- Cort */ +#if 0 memcpy ((void *)PAGE_ALIGN(-PAGE_SIZE+(unsigned long)end_avail-INITRD_SIZE), (void *)initrd_start, INITRD_SIZE ); @@ -447,20 +487,26 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R end_avail = (char *)initrd_start; puts("relocated to: "); puthex(initrd_start); puts(" "); puthex(initrd_end); puts("\n"); +#endif } +#ifndef CONFIG_MBX /* this is safe, just use it */ + /* I don't know why it didn't work for me on the MBX with 20 MB + * memory. I guess something was saved up there, but I can't + * figure it out......we are running on luck. -- Dan. + */ avail_ram = (char *)0x00400000; end_avail = (char *)0x00600000; +#endif puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" "); puthex((unsigned long)end_avail); puts("\n"); -#ifndef CONFIG_MBX +#if !defined(CONFIG_MBX) && !defined(CONFIG_FADS) CRT_tstc(); /* Forces keyboard to be initialized */ #endif -#ifdef CONFIG_PREP -/* I need to fix this for mbx -- Cort */ + puts("\nLinux/PPC load: "); timer = 0; cp = cmd_line; @@ -472,6 +518,13 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R cp--; puts("\b \b"); } +#ifdef CONFIG_MBX + } else if (ch == '?') { + if (!do_ipaddrs(&cp, 1)) { + *cp++ = ch; + putc(ch); + } +#endif } else { *cp++ = ch; putc(ch); @@ -482,12 +535,38 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R udelay(1000); /* 1 msec */ } *cp = 0; +#ifdef CONFIG_MBX + /* The MBX does not currently have any default boot strategy. + * If the command line is not filled in, we will automatically + * create the default network boot. + */ + if (cmd_line[0] == 0) { + dp = root_string; + while (*dp != 0) + *cp++ = *dp++; + *cp++ = ' '; + + dp = nfsaddrs_string; + while (*dp != 0) + *cp++ = *dp++; + dp = cp; + do_ipaddrs(&cp, 0); + *cp++ = ' '; + + /* Add the server address to the root file system path. + */ + dp = strrchr(dp, ':'); + dp++; + do_nfsroot(&cp, dp); + *cp = 0; + } +#endif puts("\n"); -#endif /* CONFIG_PREP */ + /* mappings on early boot can only handle 16M */ - if ( (int)(&cmd_line[0]) > (16<<20)) + if ( (int)(cmd_line[0]) > (16<<20)) puts("cmd_line located > 16M\n"); - if ( (int)&hold_residual > (16<<20)) + if ( (int)hold_residual > (16<<20)) puts("hold_residual located > 16M\n"); if ( initrd_start > (16<<20)) puts("initrd_start located > 16M\n"); @@ -497,13 +576,153 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R gunzip(0, 0x400000, zimage_start, &zimage_size); puts("done.\n"); puts("Now booting the kernel\n"); -#ifndef CONFIG_MBX - return (unsigned long)&hold_residual; -#else - return (unsigned long)&hold_board_info; -#endif + return (unsigned long)hold_residual; +} + +#ifdef CONFIG_MBX +int +do_ipaddrs(char **cmd_cp, int echo) +{ + char *cp, *ip, ch; + unsigned char ipd; + int i, j, retval; + + /* We need to create the string: + * <my_ip>:<serv_ip> + */ + cp = *cmd_cp; + retval = 0; + + if ((cp - 9) >= cmd_line) { + if (strncmp(cp - 9, "nfsaddrs=", 9) == 0) { + ip = (char *)0xfa000060; + retval = 1; + for (j=0; j<2; j++) { + for (i=0; i<4; i++) { + ipd = *ip++; + + ch = ipd/100; + if (ch) { + ch += '0'; + if (echo) + putc(ch); + *cp++ = ch; + ipd -= 100 * (ch - '0'); + } + + ch = ipd/10; + if (ch) { + ch += '0'; + if (echo) + putc(ch); + *cp++ = ch; + ipd -= 10 * (ch - '0'); + } + + ch = ipd + '0'; + if (echo) + putc(ch); + *cp++ = ch; + + ch = '.'; + if (echo) + putc(ch); + *cp++ = ch; + } + + /* At the end of the string, remove the + * '.' and replace it with a ':'. + */ + *(cp - 1) = ':'; + if (echo) { + putc('\b'); putc(':'); + } + } + + /* At the end of the second string, remove the + * '.' from both the command line and the + * screen. + */ + --cp; + putc('\b'); putc(' '); putc('\b'); + } + } + *cmd_cp = cp; + return(retval); } +void +do_nfsroot(char **cmd_cp, char *dp) +{ + char *cp, *rp, *ep; + + /* The boot argument (i.e /sys/mbxroot/zImage) is stored + * at offset 0x0078 in NVRAM. We use this path name to + * construct the root file system path. + */ + cp = *cmd_cp; + + /* build command string. + */ + rp = nfsroot_string; + while (*rp != 0) + *cp++ = *rp++; + + /* Add the server address to the path. + */ + while (*dp != ' ') + *cp++ = *dp++; + *cp++ = ':'; + + rp = (char *)0xfa000078; + ep = strrchr(rp, '/'); + + if (ep != 0) { + while (rp < ep) + *cp++ = *rp++; + } + else { + rp = defroot_string; + while (*rp != 0) + *cp++ = *rp++; + } + + *cmd_cp = cp; +} + +size_t strlen(const char * s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} + +int strncmp(const char * cs,const char * ct,size_t count) +{ + register signed char __res = 0; + + while (count) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} + +char * strrchr(const char * s, int c) +{ + const char *p = s + strlen(s); + do { + if (*p == (char)c) + return (char *)p; + } while (--p >= s); + return NULL; +} +#endif + void puthex(unsigned long val) { unsigned char buf[10]; diff --git a/arch/ppc/boot/mkprep.c b/arch/ppc/boot/mkprep.c index a65953f4e..7799c9acc 100644 --- a/arch/ppc/boot/mkprep.c +++ b/arch/ppc/boot/mkprep.c @@ -10,16 +10,18 @@ * 3) -asm - strips elf header and writes out as asm data * useful for generating data for a compressed image * -- Cort + * + * Modified for x86 hosted builds by Matt Porter <porter@neta.com> */ #ifdef linux #include <linux/types.h> -#include <asm/stat.h> +/*#include <asm/stat.h>*/ /*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */ #else #include <unistd.h> -#include <sys/stat.h> #endif +#include <sys/stat.h> #include <stdio.h> #include <errno.h> @@ -164,8 +166,13 @@ void write_prep_partition(int in, int out) bzero( block, sizeof block ); /* set entry point and boot image size skipping over elf header */ +#ifdef __i386__ + *entry = 0x400/*+65536*/; + *length = info.st_size+0x400; +#else *entry = cpu_to_le32(0x400/*+65536*/); *length = cpu_to_le32(info.st_size+0x400); +#endif /* __i386__ */ /* sets magic number for msdos partition (used by linux) */ block[510] = 0x55; @@ -202,9 +209,18 @@ void write_prep_partition(int in, int out) pe->beginning_sector = cpu_to_le32(1); #else /* This has to be 0 on the PowerStack? */ +#ifdef __i386__ + pe->beginning_sector = 0; +#else pe->beginning_sector = cpu_to_le32(0); +#endif /* __i386__ */ #endif + +#ifdef __i386__ + pe->number_of_sectors = 2*18*80-1; +#else pe->number_of_sectors = cpu_to_le32(2*18*80-1); +#endif /* __i386__ */ write( out, block, sizeof(block) ); write( out, entry, sizeof(*entry) ); diff --git a/arch/ppc/boot/offset b/arch/ppc/boot/offset index c9f39ed3f..52a1b5546 100644 --- a/arch/ppc/boot/offset +++ b/arch/ppc/boot/offset @@ -1,4 +1,4 @@ #!/bin/bash -OFFSET=`objdump -h $1 | grep $2 | grep -v zvmlinux| awk '{print $6}'` +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'` echo "0x"$OFFSET diff --git a/arch/ppc/boot/size b/arch/ppc/boot/size index c4b12cf94..6c48f8d14 100644 --- a/arch/ppc/boot/size +++ b/arch/ppc/boot/size @@ -1,4 +1,4 @@ #!/bin/bash -OFFSET=`objdump -h $1 | grep $2 | grep -v zvmlinux | awk '{print $3}'` +OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'` echo "0x"$OFFSET diff --git a/arch/ppc/chrp_defconfig b/arch/ppc/chrp_defconfig index fea81c513..dcaf4b2d5 100644 --- a/arch/ppc/chrp_defconfig +++ b/arch/ppc/chrp_defconfig @@ -41,10 +41,11 @@ CONFIG_FB_COMPAT_XPMAC=y CONFIG_MAC_KEYBOARD=y # CONFIG_MAC_FLOPPY is not set # CONFIG_MAC_SERIAL is not set -CONFIG_MACMOUSE=y +# CONFIG_ADBMOUSE is not set CONFIG_PROC_DEVICETREE=y # CONFIG_KGDB is not set # CONFIG_XMON is not set +# CONFIG_TOTALMP is not set # # Plug and Play support @@ -148,12 +149,11 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set CONFIG_SCSI_NCR53C8XX=y -# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set -# CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 CONFIG_SCSI_NCR53C8XX_SYNC=5 -# CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT is not set +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set @@ -199,9 +199,9 @@ CONFIG_DEC_ELCP=y # CONFIG_EEXPRESS_PRO100 is not set # CONFIG_LNE390 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set -# CONFIG_TLAN is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set @@ -228,50 +228,29 @@ CONFIG_DEC_ELCP=y # CONFIG_CD_NO_IDESCSI is not set # -# Filesystems -# -# CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -CONFIG_PROC_FS=y -CONFIG_NFS_FS=y -# CONFIG_NFSD is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set -# CONFIG_SMB_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -# CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_UFS_FS is not set -# CONFIG_ADFS_FS is not set -# CONFIG_DEVPTS_FS is not set -CONFIG_MAC_PARTITION=y -# CONFIG_NLS is not set - -# # Console drivers # +CONFIG_DUMMY_CONSOLE=y CONFIG_FB_OF=y -CONFIG_FB_S3TRIO=y +# CONFIG_FB_CONTROL is not set +# CONFIG_FB_PLATINUM is not set +# CONFIG_FB_VALKYRIE is not set CONFIG_FB_ATY=y +CONFIG_FB_IMSTT=y +# CONFIG_FB_CT65550 is not set +# CONFIG_FB_S3TRIO is not set CONFIG_FB_VGA=y # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y CONFIG_FBCON_CFB32=y CONFIG_FBCON_VGA=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y # # Character devices @@ -282,16 +261,15 @@ CONFIG_SERIAL=y # CONFIG_SERIAL_CONSOLE is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set # CONFIG_MOUSE is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set CONFIG_NVRAM=y # CONFIG_JOYSTICK is not set -# CONFIG_MISC_RADIO is not set # # Ftape, the floppy tape device driver @@ -299,7 +277,43 @@ CONFIG_NVRAM=y # CONFIG_FTAPE is not set # +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set +CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set +# CONFIG_SMB_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_HFS_FS=y +# CONFIG_ROMFS_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_ADFS_FS is not set +CONFIG_MAC_PARTITION=y +# CONFIG_NLS is not set + +# # Sound # CONFIG_SOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set # CONFIG_SOUND_OSS is not set diff --git a/arch/ppc/chrpboot/Makefile b/arch/ppc/chrpboot/Makefile index 4a194a5be..946845a5d 100644 --- a/arch/ppc/chrpboot/Makefile +++ b/arch/ppc/chrpboot/Makefile @@ -20,9 +20,13 @@ CFLAGS = -O -fno-builtin -DSTDC_HEADERS -I$(TOPDIR)/include LD_ARGS = -T ../vmlinux.lds -Ttext 0x00800000 OBJCOPY = $(CROSS_COMPILE)objcopy -OBJS = crt0.o start.o main.o misc.o string.o zlib.o image.o # initrd.o +OBJS = crt0.o start.o main.o misc.o ../coffboot/string.o ../coffboot/zlib.o image.o # initrd.o LIBS = $(TOPDIR)/lib/lib.a +ifeq ($(CONFIG_ALL_PPC),y) +# yes, we want to build chrp stuff +CONFIG_CHRP = y +endif all: $(TOPDIR)/zImage diff --git a/arch/ppc/chrpboot/main.c b/arch/ppc/chrpboot/main.c index 05a2f85d3..e89ae2720 100644 --- a/arch/ppc/chrpboot/main.c +++ b/arch/ppc/chrpboot/main.c @@ -6,8 +6,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include "nonstdio.h" -#include "zlib.h" +#include "../coffboot/nonstdio.h" +#include "../coffboot/zlib.h" extern void *finddevice(const char *); extern int getprop(void *, const char *, void *, int); diff --git a/arch/ppc/chrpboot/nonstdio.h b/arch/ppc/chrpboot/nonstdio.h deleted file mode 100644 index 664b8384a..000000000 --- a/arch/ppc/chrpboot/nonstdio.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -typedef int FILE; -extern FILE *stdin, *stdout; -#define NULL ((void *)0) -#define EOF (-1) -#define fopen(n, m) NULL -#define fflush(f) 0 -#define fclose(f) 0 -extern char *fgets(); - -#define perror(s) printf("%s: no files!\n", (s)) diff --git a/arch/ppc/chrpboot/zlib.c b/arch/ppc/chrpboot/zlib.c deleted file mode 100644 index 4f69fb3d8..000000000 --- a/arch/ppc/chrpboot/zlib.c +++ /dev/null @@ -1,2143 +0,0 @@ -/* - * This file is derived from various .h and .c files from the zlib-0.95 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. See zlib.h for conditions of - * distribution and use. - * - * Changes that have been made include: - * - changed functions not used outside this file to "local" - * - added minCompression parameter to deflateInit2 - * - added Z_PACKET_FLUSH (see zlib.h for details) - * - added inflateIncomp - * - * $Id: zlib.c,v 1.1 1997/09/19 07:03:44 paulus Exp $ - */ - -/*+++++*/ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */ - -#define _Z_UTIL_H - -#include "zlib.h" - -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - -#define FAR - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern char *z_errmsg[]; /* indexed by 1-zlib_error */ - -#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err) -/* To be used only when the state is known to be valid */ - -#ifndef NULL -#define NULL ((void *) 0) -#endif - - /* common constants */ - -#define DEFLATED 8 - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - - /* functions */ - -#include <string.h> -#define zmemcpy memcpy -#define zmemzero(dest, len) memset(dest, 0, len) - -/* Diagnostic functions */ -#ifdef DEBUG_ZLIB -# include <stdio.h> -# ifndef verbose -# define verbose 0 -# endif -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - - -typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len)); - -/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */ -/* void zcfree OF((voidpf opaque, voidpf ptr)); */ - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr, size) \ - (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size)) -#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);} - -/* deflate.h -- internal compression state - * Copyright (C) 1995 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/*+++++*/ -/* infblock.h -- header to use infblock.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; - -local inflate_blocks_statef * inflate_blocks_new OF(( - z_stream *z, - check_func c, /* check function */ - uInt w)); /* window size */ - -local int inflate_blocks OF(( - inflate_blocks_statef *, - z_stream *, - int)); /* initial return code */ - -local void inflate_blocks_reset OF(( - inflate_blocks_statef *, - z_stream *, - uLongf *)); /* check value on output */ - -local int inflate_blocks_free OF(( - inflate_blocks_statef *, - z_stream *, - uLongf *)); /* check value on output */ - -local int inflate_addhistory OF(( - inflate_blocks_statef *, - z_stream *)); - -local int inflate_packet_flush OF(( - inflate_blocks_statef *)); - -/*+++++*/ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). */ - -typedef struct inflate_huft_s FAR inflate_huft; - -struct inflate_huft_s { - union { - struct { - Byte Exop; /* number of extra bits or operation */ - Byte Bits; /* number of bits in this code or subcode */ - } what; - uInt Nalloc; /* number of these allocated here */ - Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ - } word; /* 16-bit, 8 bytes for 32-bit machines) */ - union { - uInt Base; /* literal, length base, or distance base */ - inflate_huft *Next; /* pointer to next level of table */ - } more; -}; - -#ifdef DEBUG_ZLIB - local uInt inflate_hufts; -#endif - -local int inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ - z_stream *)); /* for zalloc, zfree functions */ - -local int inflate_trees_dynamic OF(( - uInt, /* number of literal/length codes */ - uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_stream *)); /* for zalloc, zfree functions */ - -local int inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *)); /* distance tree result */ - -local int inflate_trees_free OF(( - inflate_huft *, /* tables to free */ - z_stream *)); /* for zfree function */ - - -/*+++++*/ -/* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; - -local inflate_codes_statef *inflate_codes_new OF(( - uInt, uInt, - inflate_huft *, inflate_huft *, - z_stream *)); - -local int inflate_codes OF(( - inflate_blocks_statef *, - z_stream *, - int)); - -local void inflate_codes_free OF(( - inflate_codes_statef *, - z_stream *)); - - -/*+++++*/ -/* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* inflate private state */ -struct internal_state { - - /* mode */ - enum { - METHOD, /* waiting for method byte */ - FLAG, /* waiting for flag byte */ - BLOCKS, /* decompressing blocks */ - CHECK4, /* four check bytes to go */ - CHECK3, /* three check bytes to go */ - CHECK2, /* two check bytes to go */ - CHECK1, /* one check byte to go */ - DONE, /* finished check, done */ - BAD} /* got an error--stay here */ - mode; /* current inflate mode */ - - /* mode dependent information */ - union { - uInt method; /* if FLAGS, method byte */ - struct { - uLong was; /* computed check value */ - uLong need; /* stream check value */ - } check; /* if CHECK, check values to compare */ - uInt marker; /* if BAD, inflateSync's marker bytes count */ - } sub; /* submode */ - - /* mode independent information */ - int nowrap; /* flag for no wrapper */ - uInt wbits; /* log2(window size) (8..15, defaults to 15) */ - inflate_blocks_statef - *blocks; /* current inflate_blocks state */ - -}; - - -int inflateReset(z) -z_stream *z; -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - z->total_in = z->total_out = 0; - z->msg = Z_NULL; - z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - inflate_blocks_reset(z->state->blocks, z, &c); - Trace((stderr, "inflate: reset\n")); - return Z_OK; -} - - -int inflateEnd(z) -z_stream *z; -{ - uLong c; - - if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) - inflate_blocks_free(z->state->blocks, z, &c); - ZFREE(z, z->state, sizeof(struct internal_state)); - z->state = Z_NULL; - Trace((stderr, "inflate: end\n")); - return Z_OK; -} - - -int inflateInit2(z, w) -z_stream *z; -int w; -{ - /* initialize state */ - if (z == Z_NULL) - return Z_STREAM_ERROR; -/* if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */ -/* if (z->zfree == Z_NULL) z->zfree = zcfree; */ - if ((z->state = (struct internal_state FAR *) - ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) - return Z_MEM_ERROR; - z->state->blocks = Z_NULL; - - /* handle undocumented nowrap option (no zlib header or check) */ - z->state->nowrap = 0; - if (w < 0) - { - w = - w; - z->state->nowrap = 1; - } - - /* set window size */ - if (w < 8 || w > 15) - { - inflateEnd(z); - return Z_STREAM_ERROR; - } - z->state->wbits = (uInt)w; - - /* create inflate_blocks state */ - if ((z->state->blocks = - inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w)) - == Z_NULL) - { - inflateEnd(z); - return Z_MEM_ERROR; - } - Trace((stderr, "inflate: allocated\n")); - - /* reset state */ - inflateReset(z); - return Z_OK; -} - - -int inflateInit(z) -z_stream *z; -{ - return inflateInit2(z, DEF_WBITS); -} - - -#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} -#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) - -int inflate(z, f) -z_stream *z; -int f; -{ - int r; - uInt b; - - if (z == Z_NULL || z->next_in == Z_NULL) - return Z_STREAM_ERROR; - r = Z_BUF_ERROR; - while (1) switch (z->state->mode) - { - case METHOD: - NEEDBYTE - if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED) - { - z->state->mode = BAD; - z->msg = "unknown compression method"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if ((z->state->sub.method >> 4) + 8 > z->state->wbits) - { - z->state->mode = BAD; - z->msg = "invalid window size"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - z->state->mode = FLAG; - case FLAG: - NEEDBYTE - if ((b = NEXTBYTE) & 0x20) - { - z->state->mode = BAD; - z->msg = "invalid reserved bit"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - if (((z->state->sub.method << 8) + b) % 31) - { - z->state->mode = BAD; - z->msg = "incorrect header check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib header ok\n")); - z->state->mode = BLOCKS; - case BLOCKS: - r = inflate_blocks(z->state->blocks, z, r); - if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) - r = inflate_packet_flush(z->state->blocks); - if (r == Z_DATA_ERROR) - { - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - break; - } - if (r != Z_STREAM_END) - return r; - r = Z_OK; - inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); - if (z->state->nowrap) - { - z->state->mode = DONE; - break; - } - z->state->mode = CHECK4; - case CHECK4: - NEEDBYTE - z->state->sub.check.need = (uLong)NEXTBYTE << 24; - z->state->mode = CHECK3; - case CHECK3: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 16; - z->state->mode = CHECK2; - case CHECK2: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE << 8; - z->state->mode = CHECK1; - case CHECK1: - NEEDBYTE - z->state->sub.check.need += (uLong)NEXTBYTE; - - if (z->state->sub.check.was != z->state->sub.check.need) - { - z->state->mode = BAD; - z->msg = "incorrect data check"; - z->state->sub.marker = 5; /* can't try inflateSync */ - break; - } - Trace((stderr, "inflate: zlib check ok\n")); - z->state->mode = DONE; - case DONE: - return Z_STREAM_END; - case BAD: - return Z_DATA_ERROR; - default: - return Z_STREAM_ERROR; - } - - empty: - if (f != Z_PACKET_FLUSH) - return r; - z->state->mode = BAD; - z->state->sub.marker = 0; /* can try inflateSync */ - return Z_DATA_ERROR; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ - -int inflateIncomp(z) -z_stream *z; -{ - if (z->state->mode != BLOCKS) - return Z_DATA_ERROR; - return inflate_addhistory(z->state->blocks, z); -} - - -int inflateSync(z) -z_stream *z; -{ - uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ - uInt m; /* number of marker bytes found in a row */ - uLong r, w; /* temporaries to save total_in and total_out */ - - /* set up */ - if (z == Z_NULL || z->state == Z_NULL) - return Z_STREAM_ERROR; - if (z->state->mode != BAD) - { - z->state->mode = BAD; - z->state->sub.marker = 0; - } - if ((n = z->avail_in) == 0) - return Z_BUF_ERROR; - p = z->next_in; - m = z->state->sub.marker; - - /* search */ - while (n && m < 4) - { - if (*p == (Byte)(m < 2 ? 0 : 0xff)) - m++; - else if (*p) - m = 0; - else - m = 4 - m; - p++, n--; - } - - /* restore */ - z->total_in += p - z->next_in; - z->next_in = p; - z->avail_in = n; - z->state->sub.marker = m; - - /* return no joy or set up to restart on a new block */ - if (m != 4) - return Z_DATA_ERROR; - r = z->total_in; w = z->total_out; - inflateReset(z); - z->total_in = r; z->total_out = w; - z->state->mode = BLOCKS; - return Z_OK; -} - -#undef NEEDBYTE -#undef NEXTBYTE - -/*+++++*/ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* inflate blocks semi-private state */ -struct inflate_blocks_state { - - /* mode */ - enum { - TYPE, /* get type bits (3, including end bit) */ - LENS, /* get lengths for stored */ - STORED, /* processing stored block */ - TABLE, /* get table lengths */ - BTREE, /* get bit lengths tree for a dynamic block */ - DTREE, /* get length, distance trees for a dynamic block */ - CODES, /* processing fixed or dynamic block */ - DRY, /* output remaining window bytes */ - DONEB, /* finished last block, done */ - BADB} /* got a data error--stuck here */ - mode; /* current inflate_block mode */ - - /* mode dependent information */ - union { - uInt left; /* if STORED, bytes left to copy */ - struct { - uInt table; /* table lengths (14 bits) */ - uInt index; /* index into blens (or border) */ - uIntf *blens; /* bit lengths of codes */ - uInt bb; /* bit length tree depth */ - inflate_huft *tb; /* bit length decoding tree */ - int nblens; /* # elements allocated at blens */ - } trees; /* if DTREE, decoding info for trees */ - struct { - inflate_huft *tl, *td; /* trees to free */ - inflate_codes_statef - *codes; - } decode; /* if CODES, current state */ - } sub; /* submode */ - uInt last; /* true if this block is the last block */ - - /* mode independent information */ - uInt bitk; /* bits in bit buffer */ - uLong bitb; /* bit buffer */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *write; /* window write pointer */ - check_func checkfn; /* check function */ - uLong check; /* check on output */ - -}; - - -/* defines for inflate input/output */ -/* update pointers and return */ -#define UPDBITS {s->bitb=b;s->bitk=k;} -#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} -#define UPDOUT {s->write=q;} -#define UPDATE {UPDBITS UPDIN UPDOUT} -#define LEAVE {UPDATE return inflate_flush(s,z,r);} -/* get bytes and bits */ -#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} -#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} -#define NEXTBYTE (n--,*p++) -#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}} -#define DUMPBITS(j) {b>>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (q<s->read?s->read-q-1:s->end-q) -#define LOADOUT {q=s->write;m=WAVAIL;} -#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}} -#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} -#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} -#define OUTBYTE(a) {*q++=(Byte)(a);m--;} -/* load local pointers */ -#define LOAD {LOADIN LOADOUT} - -/* And'ing with mask[n] masks the lower n bits */ -local uInt inflate_mask[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -/* copy as much as possible from the sliding window to the output area */ -local int inflate_flush OF(( - inflate_blocks_statef *, - z_stream *, - int)); - -/*+++++*/ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -local int inflate_fast OF(( - uInt, - uInt, - inflate_huft *, - inflate_huft *, - inflate_blocks_statef *, - z_stream *)); - - -/*+++++*/ -/* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* Table for deflate from PKZIP's appnote.txt. */ -local uInt border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - -/* - Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. - */ - - -local void inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_stream *z; -uLongf *c; -{ - if (s->checkfn != Z_NULL) - *c = s->check; - if (s->mode == BTREE || s->mode == DTREE) - ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); - if (s->mode == CODES) - { - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - } - s->mode = TYPE; - s->bitk = 0; - s->bitb = 0; - s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(0L, Z_NULL, 0); - Trace((stderr, "inflate: blocks reset\n")); -} - - -local inflate_blocks_statef *inflate_blocks_new(z, c, w) -z_stream *z; -check_func c; -uInt w; -{ - inflate_blocks_statef *s; - - if ((s = (inflate_blocks_statef *)ZALLOC - (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) - return s; - if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) - { - ZFREE(z, s, sizeof(struct inflate_blocks_state)); - return Z_NULL; - } - s->end = s->window + w; - s->checkfn = c; - s->mode = TYPE; - Trace((stderr, "inflate: blocks allocated\n")); - inflate_blocks_reset(s, z, &s->check); - return s; -} - - -local int inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; -{ - uInt t; /* temporary storage */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input based on current state */ - while (1) switch (s->mode) - { - case TYPE: - NEEDBITS(3) - t = (uInt)b & 7; - s->last = t & 1; - switch (t >> 1) - { - case 0: /* stored */ - Trace((stderr, "inflate: stored block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - t = k & 7; /* go to byte boundary */ - DUMPBITS(t) - s->mode = LENS; /* get length of stored block */ - break; - case 1: /* fixed */ - Trace((stderr, "inflate: fixed codes block%s\n", - s->last ? " (last)" : "")); - { - uInt bl, bd; - inflate_huft *tl, *td; - - inflate_trees_fixed(&bl, &bd, &tl, &td); - s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.decode.tl = Z_NULL; /* don't try to free these */ - s->sub.decode.td = Z_NULL; - } - DUMPBITS(3) - s->mode = CODES; - break; - case 2: /* dynamic */ - Trace((stderr, "inflate: dynamic codes block%s\n", - s->last ? " (last)" : "")); - DUMPBITS(3) - s->mode = TABLE; - break; - case 3: /* illegal */ - DUMPBITS(3) - s->mode = BADB; - z->msg = "invalid block type"; - r = Z_DATA_ERROR; - LEAVE - } - break; - case LENS: - NEEDBITS(32) - if (((~b) >> 16) != (b & 0xffff)) - { - s->mode = BADB; - z->msg = "invalid stored block lengths"; - r = Z_DATA_ERROR; - LEAVE - } - s->sub.left = (uInt)b & 0xffff; - b = k = 0; /* dump bits */ - Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); - s->mode = s->sub.left ? STORED : TYPE; - break; - case STORED: - if (n == 0) - LEAVE - NEEDOUT - t = s->sub.left; - if (t > n) t = n; - if (t > m) t = m; - zmemcpy(q, p, t); - p += t; n -= t; - q += t; m -= t; - if ((s->sub.left -= t) != 0) - break; - Tracev((stderr, "inflate: stored end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - s->mode = s->last ? DRY : TYPE; - break; - case TABLE: - NEEDBITS(14) - s->sub.trees.table = t = (uInt)b & 0x3fff; -#ifndef PKZIP_BUG_WORKAROUND - if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) - { - s->mode = BADB; - z->msg = "too many length or distance symbols"; - r = Z_DATA_ERROR; - LEAVE - } -#endif - t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); - if (t < 19) - t = 19; - if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) - { - r = Z_MEM_ERROR; - LEAVE - } - s->sub.trees.nblens = t; - DUMPBITS(14) - s->sub.trees.index = 0; - Tracev((stderr, "inflate: table sizes ok\n")); - s->mode = BTREE; - case BTREE: - while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) - { - NEEDBITS(3) - s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; - DUMPBITS(3) - } - while (s->sub.trees.index < 19) - s->sub.trees.blens[border[s->sub.trees.index++]] = 0; - s->sub.trees.bb = 7; - t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, - &s->sub.trees.tb, z); - if (t != Z_OK) - { - r = t; - if (r == Z_DATA_ERROR) - s->mode = BADB; - LEAVE - } - s->sub.trees.index = 0; - Tracev((stderr, "inflate: bits tree ok\n")); - s->mode = DTREE; - case DTREE: - while (t = s->sub.trees.table, - s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) - { - inflate_huft *h; - uInt i, j, c; - - t = s->sub.trees.bb; - NEEDBITS(t) - h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); - t = h->word.what.Bits; - c = h->more.Base; - if (c < 16) - { - DUMPBITS(t) - s->sub.trees.blens[s->sub.trees.index++] = c; - } - else /* c == 16..18 */ - { - i = c == 18 ? 7 : c - 14; - j = c == 18 ? 11 : 3; - NEEDBITS(t + i) - DUMPBITS(t) - j += (uInt)b & inflate_mask[i]; - DUMPBITS(i) - i = s->sub.trees.index; - t = s->sub.trees.table; - if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || - (c == 16 && i < 1)) - { - s->mode = BADB; - z->msg = "invalid bit length repeat"; - r = Z_DATA_ERROR; - LEAVE - } - c = c == 16 ? s->sub.trees.blens[i - 1] : 0; - do { - s->sub.trees.blens[i++] = c; - } while (--j); - s->sub.trees.index = i; - } - } - inflate_trees_free(s->sub.trees.tb, z); - s->sub.trees.tb = Z_NULL; - { - uInt bl, bd; - inflate_huft *tl, *td; - inflate_codes_statef *c; - - bl = 9; /* must be <= 9 for lookahead assumptions */ - bd = 6; /* must be <= 9 for lookahead assumptions */ - t = s->sub.trees.table; - t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), - s->sub.trees.blens, &bl, &bd, &tl, &td, z); - if (t != Z_OK) - { - if (t == (uInt)Z_DATA_ERROR) - s->mode = BADB; - r = t; - LEAVE - } - Tracev((stderr, "inflate: trees ok\n")); - if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) - { - inflate_trees_free(td, z); - inflate_trees_free(tl, z); - r = Z_MEM_ERROR; - LEAVE - } - ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); - s->sub.decode.codes = c; - s->sub.decode.tl = tl; - s->sub.decode.td = td; - } - s->mode = CODES; - case CODES: - UPDATE - if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) - return inflate_flush(s, z, r); - r = Z_OK; - inflate_codes_free(s->sub.decode.codes, z); - inflate_trees_free(s->sub.decode.td, z); - inflate_trees_free(s->sub.decode.tl, z); - LOAD - Tracev((stderr, "inflate: codes end, %lu total out\n", - z->total_out + (q >= s->read ? q - s->read : - (s->end - s->read) + (q - s->window)))); - if (!s->last) - { - s->mode = TYPE; - break; - } - if (k > 7) /* return unused byte, if any */ - { - Assert(k < 16, "inflate_codes grabbed too many bytes") - k -= 8; - n++; - p--; /* can always return one */ - } - s->mode = DRY; - case DRY: - FLUSH - if (s->read != s->write) - LEAVE - s->mode = DONEB; - case DONEB: - r = Z_STREAM_END; - LEAVE - case BADB: - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -local int inflate_blocks_free(s, z, c) -inflate_blocks_statef *s; -z_stream *z; -uLongf *c; -{ - inflate_blocks_reset(s, z, c); - ZFREE(z, s->window, s->end - s->window); - ZFREE(z, s, sizeof(struct inflate_blocks_state)); - Trace((stderr, "inflate: blocks freed\n")); - return Z_OK; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output (hence s->read equals s->write), and the state must - * be BLOCKS (i.e. we should be willing to see the start of a series of - * BLOCKS). On exit, the output will also be caught up, and the checksum - * will have been updated if need be. - */ -local int inflate_addhistory(s, z) -inflate_blocks_statef *s; -z_stream *z; -{ - uLong b; /* bit buffer */ /* NOT USED HERE */ - uInt k; /* bits in bit buffer */ /* NOT USED HERE */ - uInt t; /* temporary storage */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - - if (s->read != s->write) - return Z_STREAM_ERROR; - if (s->mode != TYPE) - return Z_DATA_ERROR; - - /* we're ready to rock */ - LOAD - /* while there is input ready, copy to output buffer, moving - * pointers as needed. - */ - while (n) { - t = n; /* how many to do */ - /* is there room until end of buffer? */ - if (t > m) t = m; - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, t); - zmemcpy(q, p, t); - q += t; - p += t; - n -= t; - z->total_out += t; - s->read = q; /* drag read pointer forward */ -/* WRAP */ /* expand WRAP macro by hand to handle s->read */ - if (q == s->end) { - s->read = q = s->window; - m = WAVAIL; - } - } - UPDATE - return Z_OK; -} - - -/* - * At the end of a Deflate-compressed PPP packet, we expect to have seen - * a `stored' block type value but not the (zero) length bytes. - */ -local int inflate_packet_flush(s) - inflate_blocks_statef *s; -{ - if (s->mode != LENS) - return Z_DATA_ERROR; - s->mode = TYPE; - return Z_OK; -} - - -/*+++++*/ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - - -local int huft_build OF(( - uIntf *, /* code lengths in bits */ - uInt, /* number of codes */ - uInt, /* number of "simple" codes */ - uIntf *, /* list of base values for non-simple codes */ - uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ - z_stream *)); /* for zalloc function */ - -local voidpf falloc OF(( - voidpf, /* opaque pointer (not used) */ - uInt, /* number of items */ - uInt)); /* size of item */ - -local void ffree OF(( - voidpf q, /* opaque pointer (not used) */ - voidpf p, /* what to free (not used) */ - uInt n)); /* number of bytes (not used) */ - -/* Tables for deflate from PKZIP's appnote.txt. */ -local uInt cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - /* actually lengths - 2; also see note #13 above about 258 */ -local uInt cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 192, 192}; /* 192==invalid */ -local uInt cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; -local uInt cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - -/* - Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. - */ - - -/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ -#define BMAX 15 /* maximum bit length of any code */ -#define N_MAX 288 /* maximum number of codes in any set */ - -#ifdef DEBUG_ZLIB - uInt inflate_hufts; -#endif - -local int huft_build(b, n, s, d, e, t, m, zs) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= N_MAX) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -uIntf *d; /* list of base values for non-simple codes */ -uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -z_stream *zs; /* for zalloc function */ -/* Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (all zero length codes or an - over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */ -{ - - uInt a; /* counter for codes of length k */ - uInt c[BMAX+1]; /* bit length count table */ - uInt f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register uInt i; /* counter, current code */ - register uInt j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register uIntf *p; /* pointer into c[], b[], or v[] */ - inflate_huft *q; /* points to current table */ - struct inflate_huft_s r; /* table entry for structure assignment */ - inflate_huft *u[BMAX]; /* table stack */ - uInt v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - uInt z; /* number of entries in current table */ - - - /* Generate counts for each bit length */ - p = c; -#define C0 *p++ = 0; -#define C2 C0 C0 C0 C0 -#define C4 C2 C2 C2 C2 - C4 /* clear c[]--assume BMAX+1 is 16 */ - p = b; i = n; - do { - c[*p++]++; /* assume all entries <= BMAX */ - } while (--i); - if (c[0] == n) /* null input--all zero length codes */ - { - *t = (inflate_huft *)Z_NULL; - *m = 0; - return Z_OK; - } - - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((uInt)l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((uInt)l > i) - l = i; - *m = l; - - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return Z_DATA_ERROR; - if ((y -= c[i]) < 0) - return Z_DATA_ERROR; - c[i] += y; - - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = c[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) - { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = (z = g - w) > (uInt)l ? l : z; /* table size upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - if (j < z) - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (inflate_huft *)ZALLOC - (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) - { - if (h) - inflate_trees_free(u[0], zs); - return Z_MEM_ERROR; /* not enough memory */ - } - q->word.Nalloc = z + 1; -#ifdef DEBUG_ZLIB - inflate_hufts += z + 1; -#endif - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->next)) = Z_NULL; - u[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) - { - x[h] = i; /* save pattern for backing up */ - r.bits = (Byte)l; /* bits to dump before this table */ - r.exop = (Byte)j; /* bits in this table */ - r.next = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h-1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.bits = (Byte)(k - w); - if (p >= v + n) - r.exop = 128 + 64; /* out of values--invalid code */ - else if (*p < s) - { - r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ - r.base = *p++; /* simple code is just the value */ - } - else - { - r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */ - r.base = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) - { - h--; /* don't need to update q */ - w -= l; - } - } - } - - - /* Return Z_BUF_ERROR if we were given an incomplete table */ - return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; -} - - -local int inflate_trees_bits(c, bb, tb, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -z_stream *z; /* for zfree function */ -{ - int r; - - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed dynamic bit lengths tree"; - else if (r == Z_BUF_ERROR) - { - inflate_trees_free(*tb, z); - z->msg = "incomplete dynamic bit lengths tree"; - r = Z_DATA_ERROR; - } - return r; -} - - -local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_stream *z; /* for zfree function */ -{ - int r; - - /* build literal/length tree */ - if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK) - { - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed literal/length tree"; - else if (r == Z_BUF_ERROR) - { - inflate_trees_free(*tl, z); - z->msg = "incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - return r; - } - - /* build distance tree */ - if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK) - { - if (r == Z_DATA_ERROR) - z->msg = "oversubscribed literal/length tree"; - else if (r == Z_BUF_ERROR) { -#ifdef PKZIP_BUG_WORKAROUND - r = Z_OK; - } -#else - inflate_trees_free(*td, z); - z->msg = "incomplete literal/length tree"; - r = Z_DATA_ERROR; - } - inflate_trees_free(*tl, z); - return r; -#endif - } - - /* done */ - return Z_OK; -} - - -/* build fixed tables only once--keep them here */ -local int fixed_lock = 0; -local int fixed_built = 0; -#define FIXEDH 530 /* number of hufts used by fixed tables */ -local uInt fixed_left = FIXEDH; -local inflate_huft fixed_mem[FIXEDH]; -local uInt fixed_bl; -local uInt fixed_bd; -local inflate_huft *fixed_tl; -local inflate_huft *fixed_td; - - -local voidpf falloc(q, n, s) -voidpf q; /* opaque pointer (not used) */ -uInt n; /* number of items */ -uInt s; /* size of item */ -{ - Assert(s == sizeof(inflate_huft) && n <= fixed_left, - "inflate_trees falloc overflow"); - if (q) s++; /* to make some compilers happy */ - fixed_left -= n; - return (voidpf)(fixed_mem + fixed_left); -} - - -local void ffree(q, p, n) -voidpf q; -voidpf p; -uInt n; -{ - Assert(0, "inflate_trees ffree called!"); - if (q) q = p; /* to make some compilers happy */ -} - - -local int inflate_trees_fixed(bl, bd, tl, td) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -{ - /* build fixed tables if not built already--lock out other instances */ - while (++fixed_lock > 1) - fixed_lock--; - if (!fixed_built) - { - int k; /* temporary variable */ - unsigned c[288]; /* length list for huft_build */ - z_stream z; /* for falloc function */ - - /* set up fake z_stream for memory routines */ - z.zalloc = falloc; - z.zfree = ffree; - z.opaque = Z_NULL; - - /* literal table */ - for (k = 0; k < 144; k++) - c[k] = 8; - for (; k < 256; k++) - c[k] = 9; - for (; k < 280; k++) - c[k] = 7; - for (; k < 288; k++) - c[k] = 8; - fixed_bl = 7; - huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); - - /* distance table */ - for (k = 0; k < 30; k++) - c[k] = 5; - fixed_bd = 5; - huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); - - /* done */ - fixed_built = 1; - } - fixed_lock--; - *bl = fixed_bl; - *bd = fixed_bd; - *tl = fixed_tl; - *td = fixed_td; - return Z_OK; -} - - -local int inflate_trees_free(t, z) -inflate_huft *t; /* table to free */ -z_stream *z; /* for zfree function */ -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ -{ - register inflate_huft *p, *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - p = t; - while (p != Z_NULL) - { - q = (--p)->next; - ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft)); - p = q; - } - return Z_OK; -} - -/*+++++*/ -/* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* inflate codes private state */ -struct inflate_codes_state { - - /* mode */ - enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - START, /* x: set up for LEN */ - LEN, /* i: get length/literal/eob next */ - LENEXT, /* i: getting length extra (have base) */ - DIST, /* i: get distance next */ - DISTEXT, /* i: getting distance extra */ - COPY, /* o: copying bytes in window, waiting for space */ - LIT, /* o: got literal, waiting for output space */ - WASH, /* o: got eob, possibly still output waiting */ - END, /* x: got eob and all data flushed */ - BADCODE} /* x: got error */ - mode; /* current inflate_codes mode */ - - /* mode dependent information */ - uInt len; - union { - struct { - inflate_huft *tree; /* pointer into tree */ - uInt need; /* bits needed */ - } code; /* if LEN or DIST, where in tree */ - uInt lit; /* if LIT, literal */ - struct { - uInt get; /* bits to get for extra */ - uInt dist; /* distance back to copy from */ - } copy; /* if EXT or COPY, where and how much */ - } sub; /* submode */ - - /* mode independent information */ - Byte lbits; /* ltree bits decoded per branch */ - Byte dbits; /* dtree bits decoder per branch */ - inflate_huft *ltree; /* literal/length/eob tree */ - inflate_huft *dtree; /* distance tree */ - -}; - - -local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl, *td; -z_stream *z; -{ - inflate_codes_statef *c; - - if ((c = (inflate_codes_statef *) - ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) - { - c->mode = START; - c->lbits = (Byte)bl; - c->dbits = (Byte)bd; - c->ltree = tl; - c->dtree = td; - Tracev((stderr, "inflate: codes new\n")); - } - return c; -} - - -local int inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; -{ - uInt j; /* temporary storage */ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ - inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ - - /* copy input/output information to locals (UPDATE macro restores) */ - LOAD - - /* process input and output based on current state */ - while (1) switch (c->mode) - { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ - case START: /* x: set up for LEN */ -#ifndef SLOW - if (m >= 258 && n >= 10) - { - UPDATE - r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); - LOAD - if (r != Z_OK) - { - c->mode = r == Z_STREAM_END ? WASH : BADCODE; - break; - } - } -#endif /* !SLOW */ - c->sub.code.need = c->lbits; - c->sub.code.tree = c->ltree; - c->mode = LEN; - case LEN: /* i: get length/literal/eob next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e == 0) /* literal */ - { - c->sub.lit = t->base; - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", t->base)); - c->mode = LIT; - break; - } - if (e & 16) /* length */ - { - c->sub.copy.get = e & 15; - c->len = t->base; - c->mode = LENEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - if (e & 32) /* end of block */ - { - Tracevv((stderr, "inflate: end of block\n")); - c->mode = WASH; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = "invalid literal/length code"; - r = Z_DATA_ERROR; - LEAVE - case LENEXT: /* i: getting length extra (have base) */ - j = c->sub.copy.get; - NEEDBITS(j) - c->len += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - c->sub.code.need = c->dbits; - c->sub.code.tree = c->dtree; - Tracevv((stderr, "inflate: length %u\n", c->len)); - c->mode = DIST; - case DIST: /* i: get distance next */ - j = c->sub.code.need; - NEEDBITS(j) - t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); - DUMPBITS(t->bits) - e = (uInt)(t->exop); - if (e & 16) /* distance */ - { - c->sub.copy.get = e & 15; - c->sub.copy.dist = t->base; - c->mode = DISTEXT; - break; - } - if ((e & 64) == 0) /* next table */ - { - c->sub.code.need = e; - c->sub.code.tree = t->next; - break; - } - c->mode = BADCODE; /* invalid code */ - z->msg = "invalid distance code"; - r = Z_DATA_ERROR; - LEAVE - case DISTEXT: /* i: getting distance extra */ - j = c->sub.copy.get; - NEEDBITS(j) - c->sub.copy.dist += (uInt)b & inflate_mask[j]; - DUMPBITS(j) - Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); - c->mode = COPY; - case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else - f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (q - s->window)); -#endif - while (c->len) - { - NEEDOUT - OUTBYTE(*f++) - if (f == s->end) - f = s->window; - c->len--; - } - c->mode = START; - break; - case LIT: /* o: got literal, waiting for output space */ - NEEDOUT - OUTBYTE(c->sub.lit) - c->mode = START; - break; - case WASH: /* o: got eob, possibly more output */ - FLUSH - if (s->read != s->write) - LEAVE - c->mode = END; - case END: - r = Z_STREAM_END; - LEAVE - case BADCODE: /* x: got error */ - r = Z_DATA_ERROR; - LEAVE - default: - r = Z_STREAM_ERROR; - LEAVE - } -} - - -local void inflate_codes_free(c, z) -inflate_codes_statef *c; -z_stream *z; -{ - ZFREE(z, c, sizeof(struct inflate_codes_state)); - Tracev((stderr, "inflate: codes free\n")); -} - -/*+++++*/ -/* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* copy as much as possible from the sliding window to the output area */ -local int inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; -{ - uInt n; - Bytef *p, *q; - - /* local copies of source and destination pointers */ - p = z->next_out; - q = s->read; - - /* compute number of bytes to copy as far as end of window */ - n = (uInt)((q <= s->write ? s->write : s->end) - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, n); - - /* copy as far as end of window */ - zmemcpy(p, q, n); - p += n; - q += n; - - /* see if more to copy at beginning of window */ - if (q == s->end) - { - /* wrap pointers */ - q = s->window; - if (s->write == s->end) - s->write = s->window; - - /* compute bytes to copy */ - n = (uInt)(s->write - q); - if (n > z->avail_out) n = z->avail_out; - if (n && r == Z_BUF_ERROR) r = Z_OK; - - /* update counters */ - z->avail_out -= n; - z->total_out += n; - - /* update check information */ - if (s->checkfn != Z_NULL) - s->check = (*s->checkfn)(s->check, q, n); - - /* copy */ - zmemcpy(p, q, n); - p += n; - q += n; - } - - /* update pointers */ - z->next_out = p; - s->read = q; - - /* done */ - return r; -} - - -/*+++++*/ -/* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* simplify the use of the inflate_huft type with some defines */ -#define base more.Base -#define next more.Next -#define exop word.what.Exop -#define bits word.what.Bits - -/* macros for bit input with no checking and for returning unused bytes */ -#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}} -#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;} - -/* Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. */ - -local int inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl, *td; -inflate_blocks_statef *s; -z_stream *z; -{ - inflate_huft *t; /* temporary pointer */ - uInt e; /* extra bits or operation */ - uLong b; /* bit buffer */ - uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ - uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ - uInt m; /* bytes to end of window or read pointer */ - uInt ml; /* mask for literal/length tree */ - uInt md; /* mask for distance tree */ - uInt c; /* bytes to copy */ - uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ - - /* load input, output, bit values */ - LOAD - - /* initialize masks */ - ml = inflate_mask[bl]; - md = inflate_mask[bd]; - - /* do until not enough input or output space for fast loop */ - do { /* assume called with m >= 258 && n >= 10 */ - /* get literal/length code */ - GRABBITS(20) /* max bits for literal/length code */ - if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - continue; - } - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits for length */ - e &= 15; - c = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * length %u\n", c)); - - /* decode distance base of block to copy */ - GRABBITS(15); /* max bits for distance code */ - e = (t = td + ((uInt)b & md))->exop; - do { - DUMPBITS(t->bits) - if (e & 16) - { - /* get extra bits to add to distance base */ - e &= 15; - GRABBITS(e) /* get extra bits (up to 13) */ - d = t->base + ((uInt)b & inflate_mask[e]); - DUMPBITS(e) - Tracevv((stderr, "inflate: * distance %u\n", d)); - - /* do the copy */ - m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ - { - e = d - (q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ - { - c -= e; /* copy to end of window */ - do { - *q++ = *r++; - } while (--e); - r = s->window; /* copy rest from start of window */ - } - } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); - break; - } - else if ((e & 64) == 0) - e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; - else - { - z->msg = "invalid distance code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - break; - } - if ((e & 64) == 0) - { - if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) - { - DUMPBITS(t->bits) - Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? - "inflate: * literal '%c'\n" : - "inflate: * literal 0x%02x\n", t->base)); - *q++ = (Byte)t->base; - m--; - break; - } - } - else if (e & 32) - { - Tracevv((stderr, "inflate: * end of block\n")); - UNGRAB - UPDATE - return Z_STREAM_END; - } - else - { - z->msg = "invalid literal/length code"; - UNGRAB - UPDATE - return Z_DATA_ERROR; - } - } while (1); - } while (m >= 258 && n >= 10); - - /* not enough input or output--restore pointers and return */ - UNGRAB - UPDATE - return Z_OK; -} - - -/*+++++*/ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */ - -char *zlib_version = ZLIB_VERSION; - -char *z_errmsg[] = { -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -""}; - - -/*+++++*/ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf) {s1 += *buf++; s2 += s1;} -#define DO2(buf) DO1(buf); DO1(buf); -#define DO4(buf) DO2(buf); DO2(buf); -#define DO8(buf) DO4(buf); DO4(buf); -#define DO16(buf) DO8(buf); DO8(buf); - -/* ========================================================================= */ -uLong adler32(adler, buf, len) - uLong adler; - Bytef *buf; - uInt len; -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == Z_NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - k -= 16; - } - if (k != 0) do { - DO1(buf); - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} diff --git a/arch/ppc/chrpboot/zlib.h b/arch/ppc/chrpboot/zlib.h deleted file mode 100644 index fe45c2c64..000000000 --- a/arch/ppc/chrpboot/zlib.h +++ /dev/null @@ -1,432 +0,0 @@ -/* $Id: zlib.h,v 1.1 1997/09/19 07:03:47 paulus Exp $ */ - -/* - * This file is derived from zlib.h and zconf.h from the zlib-0.95 - * distribution by Jean-loup Gailly and Mark Adler, with some additions - * by Paul Mackerras to aid in implementing Deflate compression and - * decompression for PPP packets. - */ - -/* - * ==FILEVERSION 960122== - * - * This marker is used by the Linux installation script to determine - * whether an up-to-date version of this file is already installed. - */ - -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 0.95, Aug 16th, 1995. - - Copyright (C) 1995 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - gzip@prep.ai.mit.edu madler@alumni.caltech.edu - */ - -#ifndef _ZLIB_H -#define _ZLIB_H - -/* #include "zconf.h" */ /* included directly here */ - -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */ - -/* - The library does not install any signal handler. It is recommended to - add at least a handler for SIGSEGV when decompressing; the library checks - the consistency of the input data whenever possible but may go nuts - for some forms of corrupted input. - */ - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints - * at addresses which are not a multiple of their size. - * Under DOS, -DFAR=far or -DFAR=__far may be needed. - */ - -#ifndef STDC -# if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus) -# define STDC -# endif -#endif - -#ifdef __MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */ -# include <unix.h> -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -#ifndef FAR -# define FAR -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - 1 << (windowBits+2) + 1 << (memLevel+9) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -typedef Byte FAR Bytef; -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -/* end of original zconf.h */ - -#define ZLIB_VERSION "0.95P" - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms may be added later and will have the same - stream interface. - - For compression the application must provide the output buffer and - may optionally provide the input buffer for optimization. For decompression, - the application must provide the input buffer and may optionally provide - the output buffer for optimization. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address, uInt nbytes)); - -struct internal_state; - -typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Bytef *next_out; /* next output byte should be put there */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidp opaque; /* private data object passed to zalloc and zfree */ - - Byte data_type; /* best guess about the data type: ascii or binary */ - -} z_stream; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_FULL_FLUSH 2 -#define Z_SYNC_FLUSH 3 /* experimental: partial_flush + byte align */ -#define Z_FINISH 4 -#define Z_PACKET_FLUSH 5 -/* See deflate() below for the usage of these constants */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -/* error codes for the compression/decompression functions */ - -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Used to set the data_type field */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -extern char *zlib_version; -/* The application can compare zlib_version and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - */ - - /* basic functions */ - -extern int inflateInit OF((z_stream *strm)); -/* - Initializes the internal stream state for decompression. The fields - zalloc and zfree must be initialized before by the caller. If zalloc and - zfree are set to Z_NULL, inflateInit updates them to use default allocation - functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory. msg is set to null if there is no error message. - inflateInit does not perform any decompression: this will be done by - inflate(). -*/ - - -extern int inflate OF((z_stream *strm, int flush)); -/* - Performs one or both of the following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() always provides as much output as possible - (until there is no more input data or no more space in the output buffer). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). - - If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH, - inflate flushes as much output as possible to the output buffer. The - flushing behavior of inflate is not specified for values of the flush - parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the - current implementation actually flushes as much output as possible - anyway. For Z_PACKET_FLUSH, inflate checks that once all the input data - has been consumed, it is expecting to see the length field of a stored - block; if not, it returns Z_DATA_ERROR. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine - may be used for the single inflate() call. - - inflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if the end of the - compressed data has been reached and all uncompressed output has been - produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if - the stream structure was inconsistent (for example if next_in or next_out - was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no - progress is possible or if there was not enough room in the output buffer - when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then - call inflateSync to look for a good compression block. */ - - -extern int inflateEnd OF((z_stream *strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* advanced functions */ - -extern int inflateInit2 OF((z_stream *strm, - int windowBits)); -/* - This is another version of inflateInit with more compression options. The - fields next_out, zalloc and zfree must be initialized before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library (the value 16 will be allowed soon). The - default value is 15 if inflateInit is used instead. If a compressed stream - with a larger window size is given as input, inflate() will return with - the error code Z_DATA_ERROR instead of trying to allocate a larger window. - - If next_out is not null, the library will use this buffer for the history - buffer; the buffer must either be large enough to hold the entire output - data, or have at least 1<<windowBits bytes. If next_out is null, the - library will allocate its own buffer (and leave next_out null). next_in - need not be provided here but must be provided by the application for the - next call of inflate(). - - If the history buffer is provided by the application, next_out must - never be changed by the application since the decompressor maintains - history information inside this buffer from call to call; the application - can only reset next_out to the beginning of the history buffer when - avail_out is zero and all output has been consumed. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was - not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as - windowBits < 8). msg is set to null if there is no error message. - inflateInit2 does not perform any decompression: this will be done by - inflate(). -*/ - -extern int inflateSync OF((z_stream *strm)); -/* - Skips invalid compressed data until the special marker (see deflate() - above) can be found, or until all available input is skipped. No output - is provided. - - inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no marker has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -*/ - -extern int inflateReset OF((z_stream *strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -extern int inflateIncomp OF((z_stream *strm)); -/* - This function adds the data at next_in (avail_in bytes) to the output - history without performing any output. There must be no pending output, - and the decompressor must be expecting to see the start of a block. - Calling this function is equivalent to decompressing a stored block - containing the data at next_in (except that the data is not output). -*/ - - /* checksum functions */ - -/* - This function is not related to compression but is exported - anyway because it might be useful in applications using the - compression library. -*/ - -extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len)); - -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -#ifndef _Z_UTIL_H - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -#endif /* _ZLIB_H */ diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile index 3f5ef4a09..72a6df455 100644 --- a/arch/ppc/coffboot/Makefile +++ b/arch/ppc/coffboot/Makefile @@ -9,6 +9,12 @@ CROSS_COMPILE =powerpc-eabi- endif +# PowerPC (cross) tools +ifneq ($(shell uname -m),ppc) +#CROSS_COMPILE =powerpc-eabi- +CROSS_COMPILE =ppc-linux-elf- +endif + HOSTCC = gcc HOSTCFLAGS = -O -I$(TOPDIR)/include @@ -24,6 +30,11 @@ GZ = gzip -9 OBJS = crt0.o start.o main.o misc.o string.o zlib.o LIBS = $(TOPDIR)/lib/lib.a +ifeq ($(CONFIG_ALL_PPC),y) +# yes, we want to build pmac stuff +CONFIG_PMAC = y +endif + ifeq ($(CONFIG_PMAC),y) hack-coff: hack-coff.c $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c @@ -73,8 +84,6 @@ vmlinux.coff.initrd: vmlinux.gz floppy: vmlinux.gz - - endif vmlinux.gz: $(TOPDIR)/vmlinux diff --git a/arch/ppc/coffboot/misc.S b/arch/ppc/coffboot/misc.S index 1a9f07129..df542a522 100644 --- a/arch/ppc/coffboot/misc.S +++ b/arch/ppc/coffboot/misc.S @@ -21,13 +21,16 @@ setup_bats: bne 4f ori 4,4,4 /* set up BAT registers for 601 */ li 5,0x7f - b 5f -4: ori 4,4,0xff /* set up BAT registers for 604 */ + mtibatu 3,4 + mtibatl 3,5 + isync + blr +4: ori 4,4,0xfe /* set up BAT registers for 604 */ li 5,2 - mtdbatu 3,4 mtdbatl 3,5 -5: mtibatu 3,4 + mtdbatu 3,4 mtibatl 3,5 + mtibatu 3,4 isync blr diff --git a/arch/ppc/coffboot/zlib.c b/arch/ppc/coffboot/zlib.c index 12d07df41..1a839043c 100644 --- a/arch/ppc/coffboot/zlib.c +++ b/arch/ppc/coffboot/zlib.c @@ -11,7 +11,7 @@ * - added Z_PACKET_FLUSH (see zlib.h for details) * - added inflateIncomp * - * $Id: zlib.c,v 1.1 1997/08/30 04:51:48 ralf Exp $ + * $Id: zlib.c,v 1.2 1998/09/03 17:40:53 cort Exp $ */ /*+++++*/ @@ -80,7 +80,7 @@ extern char *z_errmsg[]; /* indexed by 1-zlib_error */ /* functions */ -#include <string.h> +#include <linux/string.h> #define zmemcpy memcpy #define zmemzero(dest, len) memset(dest, 0, len) diff --git a/arch/ppc/common_defconfig b/arch/ppc/common_defconfig index 4fe557754..916af99f1 100644 --- a/arch/ppc/common_defconfig +++ b/arch/ppc/common_defconfig @@ -21,7 +21,7 @@ CONFIG_ALL_PPC=y CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y -# CONFIG_KMOD is not set +CONFIG_KMOD=y CONFIG_PCI=y # CONFIG_PCI_QUIRKS is not set CONFIG_PCI_OLD_PROC=y @@ -34,16 +34,20 @@ CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set +# CONFIG_VGA_CONSOLE is not set CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y -# CONFIG_PMAC_PBOOK is not set +CONFIG_PMAC_PBOOK=y CONFIG_MAC_KEYBOARD=y -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set -# CONFIG_MACMOUSE is not set +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +CONFIG_ADBMOUSE=y +CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_PROC_DEVICETREE=y # CONFIG_KGDB is not set -# CONFIG_XMON is not set +CONFIG_XMON=y +# CONFIG_TOTALMP is not set +# CONFIG_BOOTX_TEXT is not set # # Plug and Play support @@ -53,7 +57,7 @@ CONFIG_PROC_DEVICETREE=y # # Block devices # -CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y @@ -66,7 +70,7 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDEPCI is not set CONFIG_BLK_DEV_SL82C105=y # CONFIG_IDE_CHIPSETS is not set -CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP=m # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y @@ -94,7 +98,7 @@ CONFIG_INET=y # CONFIG_NET_IPGRE is not set # CONFIG_IP_ALIAS is not set CONFIG_SYN_COOKIES=y -CONFIG_INET_RARP=y +# CONFIG_INET_RARP is not set # CONFIG_IP_NOSR is not set CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set @@ -116,7 +120,7 @@ CONFIG_SKB_LARGE=y # CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y +CONFIG_CHR_DEV_ST=m CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set @@ -146,11 +150,11 @@ CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set CONFIG_SCSI_NCR53C8XX=y -# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set -CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y -CONFIG_SCSI_NCR53C8XX_IOMAPPED=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4 CONFIG_SCSI_NCR53C8XX_SYNC=5 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +CONFIG_SCSI_NCR53C8XX_IOMAPPED=y # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set @@ -166,7 +170,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=5 # CONFIG_SCSI_DEBUG is not set CONFIG_SCSI_MESH=y CONFIG_SCSI_MESH_SYNC_RATE=5 -CONFIG_SCSI_MAC53C94=y +CONFIG_SCSI_MAC53C94=m # # Network device support @@ -176,17 +180,17 @@ CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set # CONFIG_EQUALIZER is not set CONFIG_NET_ETHERNET=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set +CONFIG_MACE=y +CONFIG_BMAC=y # CONFIG_NET_VENDOR_3COM is not set -CONFIG_LANCE=y +# CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set # CONFIG_RTL8139 is not set # CONFIG_YELLOWFIN is not set # CONFIG_NET_ISA is not set CONFIG_NET_EISA=y -CONFIG_PCNET32=y +CONFIG_PCNET32=m # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set @@ -195,19 +199,26 @@ CONFIG_DE4X5=y # CONFIG_DGRS is not set # CONFIG_EEXPRESS_PRO100 is not set # CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set -# CONFIG_TLAN is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set +# CONFIG_HIPPI is not set # CONFIG_DLCI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set +CONFIG_PPP=y +CONFIG_SLIP=m +# CONFIG_SLIP_COMPRESSED is not set +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 is not set # CONFIG_NET_RADIO is not set # CONFIG_TR is not set # CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set # # Amateur Radio support @@ -225,59 +236,27 @@ CONFIG_DE4X5=y # CONFIG_CD_NO_IDESCSI is not set # -# Filesystems -# -# CONFIG_QUOTA is not set -# CONFIG_MINIX_FS is not set -CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set -CONFIG_PROC_FS=y -CONFIG_NFS_FS=y -# CONFIG_NFSD is not set -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set -# CONFIG_SMB_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_NTFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y -# CONFIG_ROMFS_FS is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_UFS_FS is not set -# CONFIG_ADFS_FS is not set -# CONFIG_DEVPTS_FS is not set -CONFIG_MAC_PARTITION=y -# CONFIG_NLS is not set - -# # Console drivers # CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_OF=y -# CONFIG_FB_S3TRIO is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_CT65550 is not set -CONFIG_FB_VGA=y +# CONFIG_FB_OF is not set +# CONFIG_FB_MATROX is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_VGA=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y # # Character devices # CONFIG_VT=y CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set +CONFIG_SERIAL=m # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set CONFIG_MOUSE=y # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_BUSMOUSE is not set @@ -285,15 +264,12 @@ CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set # CONFIG_PC110_PAD is not set -# CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set # CONFIG_NVRAM is not set # CONFIG_JOYSTICK is not set -# CONFIG_MISC_RADIO is not set # # Ftape, the floppy tape device driver @@ -301,6 +277,104 @@ CONFIG_PSMOUSE=y # CONFIG_FTAPE is not set # +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set +CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +CONFIG_NFSD=y +# CONFIG_NFSD_SUN is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set +# CONFIG_SMB_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_HFS_FS=y +# CONFIG_ROMFS_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_ADFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_MAC_PARTITION=y +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set + +# # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +CONFIG_DMASOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_OSS=y +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_UART6850 is not set + +# +# Additional low level sound drivers +# +# CONFIG_LOWLEVEL_SOUND is not set diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 31c3ed423..59223a45c 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -1,41 +1,33 @@ -# $Id: config.in,v 1.65 1998/07/20 18:42:27 geert Exp $ +# $Id: config.in,v 1.80 1998/11/11 03:54:56 paulus Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # mainmenu_name "Linux/PowerPC Kernel Configuration" - - mainmenu_option next_comment comment 'Platform support' define_bool CONFIG_PPC y -#if [ "`uname`" != "Linux" -o "`uname -m`" != "ppc" ]; then -# define_bool CONFIG_CROSSCOMPILE y -#else -# define_bool CONFIG_NATIVE y -#fi - choice 'Processor type' \ "6xx/7xx CONFIG_6xx \ 860/821 CONFIG_8xx" 6xx/7xx choice 'Machine Type' \ "PowerMac CONFIG_PMAC \ - PReP CONFIG_PREP \ + PReP/MTX CONFIG_PREP \ CHRP CONFIG_CHRP \ PowerMac/PReP/CHRP CONFIG_ALL_PPC \ APUS CONFIG_APUS \ - MBX CONFIG_MBX" PReP + MBX CONFIG_MBX" PowerMac + +if [ "$CONFIG_ALL_PPC" != "y" ];then + define_bool CONFIG_MACH_SPECIFIC y +fi endmenu if [ "$CONFIG_MBX" = "y" ];then define_bool CONFIG_SERIAL_CONSOLE y fi -if [ "$CONFIG_ALL_PPC" != "y" ]; then - define_bool CONFIG_MACH_SPECIFIC y -fi - mainmenu_option next_comment comment 'General setup' @@ -77,24 +69,23 @@ if [ "$CONFIG_PARPORT" != "n" ]; then fi fi +bool 'Support for VGA Console' CONFIG_VGA_CONSOLE bool 'Support for frame buffer devices' CONFIG_FB if [ "$CONFIG_FB" = "y" ]; then bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC fi -if [ "$CONFIG_FB" != "y" ]; then - bool 'Support for VGA Console' CONFIG_VGA_CONSOLE -fi bool 'Power management support for PowerBook 3400/2400' CONFIG_PMAC_PBOOK bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY bool 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Support for PowerMac mouse (EXPERIMENTAL)' CONFIG_MACMOUSE -fi +bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE +bool 'Support for PowerMac IDE devices (must also enable IDE)' CONFIG_BLK_DEV_IDE_PMAC bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Include kgdb kernel debugger' CONFIG_KGDB bool 'Include xmon kernel debugger' CONFIG_XMON +bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP +bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT if [ "$CONFIG_APUS" = "y" ]; then define_bool CONFIG_FB_CONSOLE y @@ -103,9 +94,8 @@ if [ "$CONFIG_APUS" = "y" ]; then define_bool CONFIG_AMIGAMOUSE y define_bool CONFIG_ABSTRACT_CONSOLE y define_bool CONFIG_FB y - tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY - bool 'Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL + tristate 'Parallel printer support' CONFIG_M68K_PRINTER tristate 'GVP IO-Extender support' CONFIG_GVPIOEXT dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT @@ -114,7 +104,8 @@ if [ "$CONFIG_APUS" = "y" ]; then "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE fi -bool '/proc/hardware support' CONFIG_PROC_HARDWARE + bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT + bool '/proc/hardware support' CONFIG_PROC_HARDWARE fi endmenu @@ -129,9 +120,7 @@ fi mainmenu_option next_comment comment 'SCSI support' - tristate 'SCSI support' CONFIG_SCSI - if [ "$CONFIG_SCSI" != "n" ]; then source drivers/scsi/Config.in fi @@ -174,22 +163,15 @@ source drivers/video/Config.in endmenu source drivers/char/Config.in - source fs/Config.in - source fs/nls/Config.in mainmenu_option next_comment comment 'Sound' - tristate 'Sound card support' CONFIG_SOUND if [ "$CONFIG_SOUND" != "n" ]; then - if [ "$CONFIG_APUS" = "y" -o "$CONFIG_PMAC" = "y" ]; then - tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND - fi - if [ "$CONFIG_PREP" = "y" -o "$CONFIG_CHRP" = "y" ]; then - source drivers/sound/Config.in - fi + tristate 'Amiga or PowerMac DMA sound support' CONFIG_DMASOUND + source drivers/sound/Config.in fi endmenu diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig index 495b786b3..ae1303bb4 100644 --- a/arch/ppc/defconfig +++ b/arch/ppc/defconfig @@ -35,16 +35,20 @@ CONFIG_KERNEL_ELF=y CONFIG_BINFMT_MISC=m # CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set -# CONFIG_FB is not set # CONFIG_VGA_CONSOLE is not set -# CONFIG_PMAC_PBOOK is not set +CONFIG_FB=y +CONFIG_FB_COMPAT_XPMAC=y +CONFIG_PMAC_PBOOK=y CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -CONFIG_MACMOUSE=y +CONFIG_ADBMOUSE=y +CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_PROC_DEVICETREE=y # CONFIG_KGDB is not set # CONFIG_XMON is not set +# CONFIG_TOTALMP is not set +CONFIG_BOOTX_TEXT=y # # Plug and Play support @@ -64,12 +68,16 @@ CONFIG_BLK_DEV_IDE=y CONFIG_BLK_DEV_IDEDISK=y CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_IDEPCI is not set # CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_PMAC_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set # @@ -159,7 +167,7 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -CONFIG_SCSI_AIC7XXX=m +CONFIG_SCSI_AIC7XXX=y # CONFIG_OVERRIDE_CMDS is not set CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=15 @@ -216,23 +224,26 @@ CONFIG_NET_EISA=y # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set -CONFIG_DE4X5=m +CONFIG_DE4X5=y CONFIG_DEC_ELCP=m # CONFIG_DGRS is not set # CONFIG_EEXPRESS_PRO100 is not set # CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set # CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set +# CONFIG_HIPPI is not set # CONFIG_DLCI is not set # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set -CONFIG_PPP=m +CONFIG_PPP=y # # CCP compressors for PPP are only built as modules. @@ -241,6 +252,7 @@ CONFIG_PPP=m # CONFIG_NET_RADIO is not set # CONFIG_TR is not set # CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set # # Amateur Radio support @@ -260,21 +272,44 @@ CONFIG_PPP=m # # Console drivers # +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_ATY=y +CONFIG_FB_IMSTT=y +CONFIG_FB_CT65550=y +# CONFIG_FB_S3TRIO is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_SUN8x16=y +CONFIG_FONT_SUN12x22=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set # # Character devices # CONFIG_VT=y CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set +CONFIG_SERIAL=m # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTY_COUNT=256 # CONFIG_MOUSE is not set -# CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set @@ -301,6 +336,7 @@ CONFIG_VFAT_FS=m CONFIG_PROC_FS=y CONFIG_NFS_FS=y CONFIG_NFSD=y +# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_CODA_FS is not set @@ -309,12 +345,16 @@ CONFIG_LOCKD=y # CONFIG_NTFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=m +CONFIG_HFS_FS=y # CONFIG_ROMFS_FS is not set CONFIG_AUTOFS_FS=y # CONFIG_UFS_FS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set CONFIG_DEVPTS_FS=y # CONFIG_ADFS_FS is not set +# CONFIG_QNX4FS_FS is not set CONFIG_MAC_PARTITION=y CONFIG_NLS=y @@ -351,4 +391,11 @@ CONFIG_NLS_CODEPAGE_437=y # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +CONFIG_DMASOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 6f1060560..4846d5ebb 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -11,11 +11,11 @@ $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o O_TARGET := kernel.o -OX_OBJS := ppc_ksyms.o +OX_OBJS := ppc_ksyms.o setup.o O_OBJS := traps.o irq.o idle.o time.o process.o signal.o syscalls.o misc.o \ - bitops.o setup.o ptrace.o align.o ppc_htab.o + bitops.o ptrace.o align.o ppc_htab.o feature.o ifdef CONFIG_PCI O_OBJS += pci.o @@ -23,6 +23,9 @@ endif ifdef CONFIG_KGDB O_OBJS += ppc-stub.o endif +ifdef CONFIG_TOTALMP +O_OBJS += totalmp.o +endif ifeq ($(CONFIG_MBX),y) O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o @@ -31,10 +34,10 @@ ifeq ($(CONFIG_APUS),y) O_OBJS += apus_setup.o prom.o openpic.o else O_OBJS += prep_time.o pmac_time.o chrp_time.o \ - pmac_setup.o pmac_support.o chrp_setup.o \ + pmac_setup.o pmac_support.o \ prep_pci.o pmac_pci.o chrp_pci.o \ residual.o prom.o openpic.o -OX_OBJS += prep_setup.o +OX_OBJS += chrp_setup.o prep_setup.o endif endif diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index 70284674b..83ee7756d 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -265,7 +265,7 @@ fix_alignment(struct pt_regs *regs) #else giveup_fpu(); #endif - cvt_fd(&data.f, ¤t->tss.fpr[reg]); + cvt_fd(&data.f, ¤t->tss.fpr[reg], ¤t->tss.fpscr); /* current->tss.fpr[reg] = data.f; */ break; case ST+F+S: @@ -275,7 +275,7 @@ fix_alignment(struct pt_regs *regs) #else giveup_fpu(); #endif - cvt_df(¤t->tss.fpr[reg], &data.f); + cvt_df(¤t->tss.fpr[reg], &data.f, ¤t->tss.fpscr); /* data.f = current->tss.fpr[reg]; */ break; default: diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index ea2bc5690..93c2fe2d1 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -19,6 +19,7 @@ #include <asm/amigahw.h> #include <asm/amigappc.h> #include <asm/pgtable.h> +#include <asm/io.h> unsigned long m68k_machtype; char debug_device[6] = ""; @@ -60,6 +61,8 @@ extern struct mem_info memory[NUM_MEMINFO];/* memory description */ extern void amiga_floppy_setup(char *, int *); extern void config_amiga(void); +static int __60nsram = 0; + /*********************************************************** SETUP */ /* From arch/m68k/kernel/setup.c. */ __initfunc(void apus_setup_arch(unsigned long * memory_start_p, @@ -75,10 +78,17 @@ __initfunc(void apus_setup_arch(unsigned long * memory_start_p, for( p = cmd_line; p && *p; ) { i = 0; if (!strncmp( p, "debug=", 6 )) { - strncpy( debug_device, p+6, sizeof(debug_device)-1 ); - debug_device[sizeof(debug_device)-1] = 0; - if ((q = strchr( debug_device, ' ' ))) *q = 0; - i = 1; + strncpy( debug_device, p+6, sizeof(debug_device)-1 ); + debug_device[sizeof(debug_device)-1] = 0; + if ((q = strchr( debug_device, ' ' ))) *q = 0; + i = 1; + } else if (!strncmp( p, "60nsram", 7 )) { + APUS_WRITE (APUS_REG_WAITSTATE, + REGWAITSTATE_SETRESET + |REGWAITSTATE_PPCR + |REGWAITSTATE_PPCW); + __60nsram = 1; + i = 1; } if (i) { @@ -95,63 +105,85 @@ __initfunc(void apus_setup_arch(unsigned long * memory_start_p, config_amiga(); } + +void get_current_tb(unsigned long long *time) +{ + __asm __volatile ("1:mftbu 4 \n\t" + " mftb 5 \n\t" + " mftbu 6 \n\t" + " cmpw 4,6 \n\t" + " bne 1b \n\t" + " stw 4,0(%0)\n\t" + " stw 5,4(%0)\n\t" + : + : "r" (time) + : "r4", "r5", "r6"); +} + + void apus_calibrate_decr(void) { int freq, divisor; - unsigned char c = *(unsigned char*)ZTWO_VADDR(0xf00011); - switch (c) + /* This algorithm for determining the bus speed was + contributed by Ralph Schmidt. */ + unsigned long long start, stop; + int bus_speed; + { - case 'A': - case 'B': - if (amiga_model == AMI_1200 || amiga_model == AMI_2000){ - freq = 1; - } else { - freq = 0; - } - break; - case 'C': - if (amiga_model == AMI_1200 || amiga_model == AMI_2000){ - freq = 0; - } else { - freq = 1; + unsigned long loop = amiga_eclock / 10; + + get_current_tb (&start); + while (loop--) { + unsigned char tmp; + + tmp = ciaa.pra; } - break; - case 'D': - freq = 1; - break; - default: - freq = 0; - printk (" *Unknown CPU speed ID ('%c')* ", c); - break; + get_current_tb (&stop); + } + + bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000; + if (AMI_1200 == amiga_model) + bus_speed /= 2; + + if ((bus_speed >= 47) && (bus_speed < 53)) { + bus_speed = 50; + freq = 12500000; + } else if ((bus_speed >= 57) && (bus_speed < 63)) { + bus_speed = 60; + freq = 15000000; + } else if ((bus_speed >= 63) && (bus_speed < 69)) { + bus_speed = 66; + freq = 16500000; + } else { + printk ("APUS: Unable to determine bus speed (%d). " + "Defaulting to 50MHz", bus_speed); + bus_speed = 50; + freq = 12500000; } + /* Ease diagnostics... */ { - int speed; - switch (freq) - { - case 0: - freq = 15000000; - speed = 60; - - /* Use status of left mouse button to select - RAM speed. */ - if (!(ciaa.pra & 0x40)) - { - APUS_WRITE (APUS_REG_WAITSTATE, - REGWAITSTATE_SETRESET - |REGWAITSTATE_PPCR - |REGWAITSTATE_PPCW); - printk (" [RAM R/W waitstate removed. " - "(expecting 60ns RAM).] "); + extern int __map_without_bats; + + printk ("APUS: BATs=%d, BUS=%dMHz, RAM=%dns\n", + (__map_without_bats) ? 0 : 1, + bus_speed, + (__60nsram) ? 60 : 70); + + /* print a bit more if asked politely... */ + if (!(ciaa.pra & 0x40)){ + extern unsigned int bat_addrs[4][3]; + int b; + for (b = 0; b < 4; ++b) { + printk ("APUS: BAT%d ", b); + printk ("%08x-%08x -> %08x\n", + bat_addrs[b][0], + bat_addrs[b][1], + bat_addrs[b][2]); } - break; - case 1: - freq = 16500000; - speed = 66; - break; } - printk ("PowerUp Bus Speed: %dMHz\n", speed); + } freq *= 60; /* try to make freq/1e6 an integer */ @@ -222,7 +254,72 @@ unsigned long kernel_map (unsigned long phys_addr, unsigned long size, } return v_ret; } - + +/* From pgtable.h */ +extern __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va) +{ + pgd_t *dir = 0; + pmd_t *pmd = 0; + pte_t *pte = 0; + + va &= PAGE_MASK; + + dir = pgd_offset( mm, va ); + if (dir) + { + pmd = pmd_offset(dir, va & PAGE_MASK); + if (pmd && pmd_present(*pmd)) + { + pte = pte_offset(pmd, va); + } + } + return pte; +} + + +/* Again simulating an m68k/mm/kmap.c function. */ +void kernel_set_cachemode( unsigned long address, unsigned long size, + unsigned int cmode ) +{ + int mask, flags; + + switch (cmode) + { + case KERNELMAP_FULL_CACHING: + mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED); + flags = 0; + break; + case KERNELMAP_NOCACHE_SER: + mask = ~0; + flags = (_PAGE_NO_CACHE | _PAGE_GUARDED); + break; + default: + panic ("kernel_set_cachemode() doesn't support mode %d\n", + cmode); + break; + } + + size /= PAGE_SIZE; + address &= PAGE_MASK; + while (size--) + { + pte_t *pte; + + pte = my_find_pte(init_task.mm, address); + if ( !pte ) + { + printk("pte NULL in kernel_set_cachemode()\n"); + return; + } + + pte_val (*pte) &= mask; + pte_val (*pte) |= flags; + flush_tlb_page(find_vma(init_task.mm,address),address); + + address += PAGE_SIZE; + } +} + unsigned long mm_ptov (unsigned long paddr) { unsigned long ret; diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 748a78e00..5b373c876 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -11,6 +11,7 @@ */ #include <linux/config.h> +#include <linux/module.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -29,6 +30,7 @@ #include <linux/blk.h> #include <linux/ioport.h> #include <linux/console.h> +#include <linux/pci.h> #include <asm/mmu.h> #include <asm/processor.h> @@ -37,6 +39,7 @@ #include <asm/ide.h> #include <asm/prom.h> #include <asm/gg2.h> +#include <asm/pci-bridge.h> extern void hydra_init(void); extern void w83c553f_init(void); @@ -189,7 +192,15 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) aux_device_present = 0xaa; - ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ +#ifdef CONFIG_BLK_DEV_INITRD + /* this is fine for chrp */ + initrd_below_start_ok = 1; + + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ printk("Boot arguments: %s\n", cmd_line); @@ -203,7 +214,6 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) /* PCI bridge config space access area - * appears to be not in devtree on longtrail. */ ioremap(GG2_PCI_CONFIG_BASE, 0x80000); - /* * Temporary fixes for PCI devices. * -- Geert @@ -215,8 +225,54 @@ chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) * Fix the Super I/O configuration */ sio_init(); - #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + /* my starmax 6000 needs this but the longtrail shouldn't do it -- Cort */ + if ( !strncmp("MOT", get_property(find_path_device("/"), + "model", NULL),3) ) + *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); +} + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) + +unsigned int chrp_ide_irq = 0; +int chrp_ide_ports_known = 0; +ide_ioreg_t chrp_ide_regbase[MAX_HWIFS]; +ide_ioreg_t chrp_idedma_regbase; + +void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) +{ + ide_ioreg_t port = base; + int i = 8; + + while (i--) + *p++ = port++; + *p++ = port; + if (irq != NULL) + *irq = chrp_ide_irq; } + +void chrp_ide_probe(void) { + + struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL); + + chrp_ide_ports_known = 1; + + if(pdev) { + chrp_ide_regbase[0]=pdev->base_address[0] & + PCI_BASE_ADDRESS_IO_MASK; + chrp_ide_regbase[1]=pdev->base_address[2] & + PCI_BASE_ADDRESS_IO_MASK; + chrp_idedma_regbase=pdev->base_address[4] & + PCI_BASE_ADDRESS_IO_MASK; + chrp_ide_irq=pdev->irq; + } +} + +EXPORT_SYMBOL(chrp_ide_irq); +EXPORT_SYMBOL(chrp_ide_ports_known); +EXPORT_SYMBOL(chrp_ide_regbase); +EXPORT_SYMBOL(chrp_ide_probe); + +#endif diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c new file mode 100644 index 000000000..48d8bcb39 --- /dev/null +++ b/arch/ppc/kernel/feature.c @@ -0,0 +1,249 @@ +/* + * arch/ppc/kernel/feature.c + * + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <asm/errno.h> +#include <asm/ohare.h> +#include <asm/io.h> +#include <asm/prom.h> +#include <asm/feature.h> + +#define MAX_FEATURE_REGS 2 +#undef DEBUG_FEATURE + +static u32 feature_bits_pbook[] = { + 0, /* FEATURE_null */ + OH_SCC_RESET, /* FEATURE_Serial_reset */ + OH_SCC_ENABLE, /* FEATURE_Serial_enable */ + OH_SCCA_IO, /* FEATURE_Serial_IO_A */ + OH_SCCB_IO, /* FEATURE_Serial_IO_B */ + OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */ + OH_MESH_ENABLE, /* FEATURE_MESH_enable */ + OH_IDE_ENABLE, /* FEATURE_IDE_enable */ + OH_VIA_ENABLE, /* FEATURE_VIA_enable */ + OH_IDECD_POWER, /* FEATURE_CD_power */ + OH_BAY_RESET, /* FEATURE_Mediabay_reset */ + OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */ + OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */ + OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */ + OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ + 0, /* FEATURE_BMac_reset */ + 0, /* FEATURE_BMac_IO_enable */ + 0, /* FEATURE_Modem_PowerOn -> guess...*/ + 0 /* FEATURE_Modem_Reset -> guess...*/ +}; + +/* assume these are the same as the ohare until proven otherwise */ +static u32 feature_bits_heathrow[] = { + 0, /* FEATURE_null */ + OH_SCC_RESET, /* FEATURE_Serial_reset */ + OH_SCC_ENABLE, /* FEATURE_Serial_enable */ + OH_SCCA_IO, /* FEATURE_Serial_IO_A */ + OH_SCCB_IO, /* FEATURE_Serial_IO_B */ + OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */ + OH_MESH_ENABLE, /* FEATURE_MESH_enable */ + OH_IDE_ENABLE, /* FEATURE_IDE_enable */ + OH_VIA_ENABLE, /* FEATURE_VIA_enable */ + OH_IDECD_POWER, /* FEATURE_CD_power */ + OH_BAY_RESET, /* FEATURE_Mediabay_reset */ + OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */ + OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */ + OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */ + OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */ + 0x80000000, /* FEATURE_BMac_reset */ + 0x60000000, /* FEATURE_BMac_IO_enable */ + 0x02000000, /* FEATURE_Modem_PowerOn -> guess...*/ + 0x07000000 /* FEATURE_Modem_Reset -> guess...*/ +}; + +/* definition of a feature controller object */ +struct feature_controller +{ + u32* bits; + volatile u32* reg; + struct device_node* device; +}; + +/* static functions */ +static void +feature_add_controller(struct device_node *controller_device, u32* bits); + +static int +feature_lookup_controller(struct device_node *device); + +/* static varialbles */ +static struct feature_controller controllers[MAX_FEATURE_REGS]; +static int controller_count = 0; + + +void +feature_init(void) +{ + struct device_node *np; + + np = find_devices("mac-io"); + while (np != NULL) + { + feature_add_controller(np, feature_bits_heathrow); + np = np->next; + } + if (controller_count == 0) + { + np = find_devices("ohare"); + if (np) + { + if (find_devices("via-pmu") != NULL) + feature_add_controller(np, feature_bits_pbook); + else + /* else not sure; maybe this is a Starmax? */ + feature_add_controller(np, NULL); + } + } + + if (controller_count) + printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); +} + +static void +feature_add_controller(struct device_node *controller_device, u32* bits) +{ + struct feature_controller* controller; + + if (controller_count >= MAX_FEATURE_REGS) + { + printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n", + controller_device->full_name, MAX_FEATURE_REGS); + return; + } + controller = &controllers[controller_count]; + + controller->bits = bits; + controller->device = controller_device; + if (controller_device->n_addrs == 0) { + printk(KERN_ERR "No addresses for %s\n", + controller_device->full_name); + return; + } + + controller->reg = (volatile u32 *)ioremap( + controller_device->addrs[0].address + OHARE_FEATURE_REG, 4); + + if (bits == NULL) { + printk(KERN_INFO "Twiddling the magic ohare bits\n"); + out_le32(controller->reg, STARMAX_FEATURES); + return; + } + + controller_count++; +} + +static int +feature_lookup_controller(struct device_node *device) +{ + int i; + + if (device == NULL) + return -EINVAL; + + while(device) + { + for (i=0; i<controller_count; i++) + if (device == controllers[i].device) + return i; + device = device->parent; + } + +#ifdef DEBUG_FEATURE + printk("feature: <%s> not found on any controller\n", + device->name); +#endif + + return -ENODEV; +} + +int +feature_set(struct device_node* device, enum system_feature f) +{ + int controller; + unsigned long flags; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + +#ifdef DEBUG_FEATURE + printk("feature: <%s> setting feature %d in controller @0x%x\n", + device->name, (int)f, (unsigned int)controllers[controller].reg); +#endif + + save_flags(flags); + cli(); + st_le32( controllers[controller].reg, + ld_le32(controllers[controller].reg) | + controllers[controller].bits[f]); + restore_flags(flags); + udelay(10); + + return 0; +} + +int +feature_clear(struct device_node* device, enum system_feature f) +{ + int controller; + unsigned long flags; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + +#ifdef DEBUG_FEATURE + printk("feature: <%s> clearing feature %d in controller @0x%x\n", + device->name, (int)f, (unsigned int)controllers[controller].reg); +#endif + + save_flags(flags); + cli(); + st_le32( controllers[controller].reg, + ld_le32(controllers[controller].reg) & + ~(controllers[controller].bits[f])); + restore_flags(flags); + udelay(10); + + return 0; +} + +int +feature_test(struct device_node* device, enum system_feature f) +{ + int controller; + + if (f >= FEATURE_last) + return -EINVAL; + + controller = feature_lookup_controller(device); + if (controller < 0) + return controller; + + return (ld_le32(controllers[controller].reg) & + controllers[controller].bits[f]) != 0; +} + diff --git a/arch/ppc/kernel/find_name.c b/arch/ppc/kernel/find_name.c index d5d88bff7..3c0fa8e0c 100644 --- a/arch/ppc/kernel/find_name.c +++ b/arch/ppc/kernel/find_name.c @@ -16,7 +16,7 @@ int main(int argc, char **argv) if ( argc < 2 ) { fprintf(stderr, "Usage: %s <address>\n", argv[0]); - exit(-1); + return -1; } for ( i = 1 ; argv[i] ; i++ ) @@ -41,7 +41,7 @@ int main(int argc, char **argv) strcpy( last, s); } - printf( "%s", last); + printf( "%s%s", last, s ); } fclose(f); return 0; diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index a257e7762..4c528beb8 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -1,7 +1,7 @@ /* * arch/ppc/kernel/head.S * - * $Id: head.S,v 1.98 1998/07/26 21:28:48 geert Exp $ + * $Id: head.S,v 1.111 1998/11/10 01:10:32 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -93,15 +93,18 @@ LG_CACHE_LINE_SIZE = 5 bdnz 0b #endif +/* 601 only have IBAT cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, offset, reg, RA, RB) \ lwz RA,offset+0(reg); \ lwz RB,offset+4(reg); \ mtspr IBAT##n##U,RA; \ mtspr IBAT##n##L,RB; \ + beq 1f; \ lwz RA,offset+8(reg); \ lwz RB,offset+12(reg); \ mtspr DBAT##n##U,RA; \ - mtspr DBAT##n##L,RB + mtspr DBAT##n##L,RB; \ +1: #ifndef CONFIG_APUS #define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h @@ -139,6 +142,12 @@ _start: * pointer (r1) points to just below the end of the half-meg region * from 0x380000 - 0x400000, which is mapped in already. * + * If we are booted from MacOS via BootX, we enter with the kernel + * image loaded somewhere, and the following values in registers: + * r3: 'BooX' (0x426f6f58) + * r4: virtual address of boot_infos_t + * r5: 0 + * * PREP * This is jumped to on prep systems right after the kernel is relocated * to its proper place in memory by the boot loader. The expected layout @@ -201,7 +210,8 @@ __start: mr r27,r7 #ifndef CONFIG_8xx bl prom_init - + .globl __secondary_start +__secondary_start: /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely @@ -213,33 +223,45 @@ __start: lis r11,KERNELBASE@h bne 4f ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f + li r8,0x7f /* valid, block length = 8MB */ oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ + mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */ + mtspr IBAT0L,r8 /* lower BAT register */ mtspr IBAT1U,r9 mtspr IBAT1L,r10 b 5f 4: #ifndef CONFIG_APUS - ori r11,r11,0x1ff /* set up BAT registers for 604 */ - li r8,2 + ori r11,r11,0x1fe /* set up BAT registers for 604 */ + li r8,2 /* R/W access */ #else - ori r11,r11,0xff /* set up an 8MB mapping */ + ori r11,r11,0xfe /* set up an 8MB mapping */ lis r8,CYBERBASEp@h lwz r8,0(r8) addis r8,r8,KERNELBASE@h addi r8,r8,2 #endif -5: mtspr DBAT0U,r11 - mtspr DBAT0L,r8 - mtspr IBAT0U,r11 + mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT0U,r11 /* bit in upper BAT register */ mtspr IBAT0L,r8 - isync + mtspr IBAT0U,r11 +5: isync #ifdef CONFIG_APUS /* Unfortunately the APUS specific instructions bloat the * code so it cannot fit in the 0x100 bytes available. We have * to do it the crude way. */ + + /* Map 0xfff00000 so we can access VTOP/PTOV constant when + MMU is enabled. */ + lis r8,0xfff0 + ori r11,r8,0x2 /* r/w */ + ori r8,r8,0x2 /* 128KB, supervisor */ + mtspr DBAT3U,r8 + mtspr DBAT3L,r11 + + /* Copy exception code to exception vector base. */ lis r3,KERNELBASE@h tophys(r4,r3,r5) lis r3,0xfff0 /* Copy to 0xfff00000 on APUS */ @@ -263,23 +285,10 @@ __start: li r3,0 mfmsr r0 andi. r0,r0,MSR_DR /* MMU enabled? */ - beq 7f + beq relocate_kernel lis r3,KERNELBASE@h /* if so, are we */ cmpw 0,r4,r3 /* already running at KERNELBASE? */ - beq 2f - rlwinm r4,r4,0,8,31 /* translate source address */ - add r4,r4,r3 /* to region mapped with BATs */ -7: addis r9,r26,klimit@ha /* fetch klimit */ - lwz r25,klimit@l(r9) - addis r25,r25,-KERNELBASE@h - li r6,0 /* Destination */ - li r5,0x4000 /* # bytes of memory to copy */ - bl copy_and_flush /* copy the first 0x4000 bytes */ - addi r0,r3,4f@l /* jump to the address of 4f */ - mtctr r0 /* in copy and do the rest. */ - bctr /* jump to the copy */ -4: mr r5,r25 - bl copy_and_flush /* copy the rest */ + bne relocate_kernel 2: #endif /* CONFIG_APUS */ /* @@ -356,6 +365,7 @@ __start: */ #endif /* CONFIG_8xx */ +turn_on_mmu: mfmsr r0 ori r0,r0,MSR_DR|MSR_IR mtspr SRR1,r0 @@ -364,7 +374,7 @@ __start: mtspr SRR0,r0 SYNC rfi /* enables MMU */ - + /* * GCC sometimes accesses words at negative offsets from the stack * pointer, although the SysV ABI says it shouldn't. To cope with @@ -506,7 +516,7 @@ HardwareInterrupt: li r20,(IPLEMU_SETRESET|IPLEMU_DISABLEINT) stb r20,APUS_IPL_EMU@l(r3) - sync + eieio lbz r3,APUS_IPL_EMU@l(r3) @@ -1386,15 +1396,13 @@ hash_page_out: next_slot: .long 0 -/* - * FPU stuff for the 6xx/7xx follows - * -- Cort - */ load_up_fpu: /* * Disable FP for the task which had the FPU previously, * and save its floating-point registers in its thread_struct. * Enables the FPU for use in the kernel on return. + * On SMP we know the fpu is free, since we give it up every + * switch. -- Cort */ #ifndef CONFIG_APUS lis r6,-KERNELBASE@h @@ -1402,28 +1410,23 @@ load_up_fpu: lis r6,CYBERBASEp@h lwz r6,0(r6) #endif + addis r3,r6,last_task_used_math@ha lwz r4,last_task_used_math@l(r3) mfmsr r5 ori r5,r5,MSR_FP SYNC mtmsr r5 /* enable use of fpu now */ -#ifndef __SMP__ - SYNC - cmpi 0,r4,0 - beq 1f -#else /* * All the saving of last_task_used_math is handled * by a switch_to() call to smp_giveup_fpu() in SMP so * last_task_used_math is not used. - * - * We should never be herre on SMP anyway, sinc ethe fpu should - * always be on. * -- Cort */ - b 1f -#endif +#ifndef __SMP__ + SYNC + cmpi 0,r4,0 + beq 1f add r4,r4,r6 addi r4,r4,TSS /* want TSS of last_task_used_math */ SAVE_32FPRS(0, r4) @@ -1432,22 +1435,20 @@ load_up_fpu: lwz r5,PT_REGS(r4) add r5,r5,r6 lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) - li r20,MSR_FP + li r20,MSR_FP|MSR_FE0|MSR_FE1 andc r4,r4,r20 /* disable FP for previous task */ stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) - -1: ori r23,r23,MSR_FP /* enable use of FP after return */ +#endif /* __SMP__ */ +1: ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 /* enable use of FP after return */ mfspr r5,SPRG3 /* current task's TSS (phys) */ lfd fr0,TSS_FPSCR-4(r5) mtfsf 0xff,fr0 REST_32FPRS(0, r5) -/* - * on SMP we don't really use last_task_used_math but set it - * here anyway to avoid the ifdef's -- Cort - */ subi r4,r5,TSS sub r4,r4,r6 +#ifndef __SMP__ stw r4,last_task_used_math@l(r3) +#endif /* __SMP__ */ /* restore registers and return */ lwz r3,_CCR(r21) lwz r4,_LINK(r21) @@ -1507,14 +1508,16 @@ giveup_fpu: cmpi 0,r4,0 beqlr- /* if no previous owner, done */ addi r4,r4,TSS /* want TSS of last_task_used_math */ +#ifndef __SMP__ li r5,0 stw r5,last_task_used_math@l(r3) +#endif /* __SMP__ */ SAVE_32FPRS(0, r4) mffs fr0 stfd fr0,TSS_FPSCR-4(r4) lwz r5,PT_REGS(r4) lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5) - li r4,MSR_FP + li r4,MSR_FP|MSR_FE0|MSR_FE1 andc r3,r3,r4 /* disable FP for previous task */ stw r3,_MSR-STACK_FRAME_OVERHEAD(r5) #else /* CONFIG_8xx */ @@ -1522,7 +1525,31 @@ giveup_fpu: giveup_fpu: #endif /* CONFIG_8xx */ blr - + +/* + * This code is jumped to from the startup code to copy + * the kernel image to physical address 0. + */ +relocate_kernel: + lis r9,0x426f /* if booted from BootX, don't */ + addi r9,r9,0x6f58 /* translate source addr */ + cmpw r31,r9 /* (we have to on chrp) */ + beq 7f + rlwinm r4,r4,0,8,31 /* translate source address */ + add r4,r4,r3 /* to region mapped with BATs */ +7: addis r9,r26,klimit@ha /* fetch klimit */ + lwz r25,klimit@l(r9) + addis r25,r25,-KERNELBASE@h + li r6,0 /* Destination offset */ + li r5,0x4000 /* # bytes of memory to copy */ + bl copy_and_flush /* copy the first 0x4000 bytes */ + addi r0,r3,4f@l /* jump to the address of 4f */ + mtctr r0 /* in copy and do the rest. */ + bctr /* jump to the copy */ +4: mr r5,r25 + bl copy_and_flush /* copy the rest */ + b turn_on_mmu + /* * Copy routine used to copy the kernel to start at physical address 0 * and flush and invalidate the caches as needed. @@ -1577,11 +1604,6 @@ start_here: bne 3f /* don't invalidate the D-cache */ ori r8,r8,HID0_DCI /* unless it wasn't enabled */ 3: - /* turn on dpm for 603 */ - cmpi 0,r9,3 - bne 10f - oris r11,r11,HID0_DPM@h -10: sync mtspr HID0,r8 /* enable and invalidate caches */ sync @@ -1600,14 +1622,27 @@ start_here: 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ 4: #endif /* CONFIG_8xx */ +#ifdef __SMP__ + /* if we're the second cpu stack and r2 are different + * and we want to not clear the bss -- Cort */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + lwz r5,0(r5) + cmpi 0,r5,0 + beq 99f + + /* get current */ + lis r2,current_set@h + ori r2,r2,current_set@l + addi r2,r2,4 + lwz r2,0(r2) + + b 10f +99: +#endif /* __SMP__ */ /* ptr to current */ lis r2,init_task_union@h ori r2,r2,init_task_union@l - /* stack */ - addi r1,r2,TASK_UNION_SIZE - li r0,0 - stwu r0,-STACK_FRAME_OVERHEAD(r1) - /* Clear out the BSS */ lis r11,_end@ha addi r11,r11,_end@l @@ -1623,6 +1658,15 @@ start_here: 3: stwu r0,4(r8) bdnz 3b 2: +#ifdef __SMP__ +10: +#endif /* __SMP__ */ + + /* stack */ + addi r1,r2,TASK_UNION_SIZE + li r0,0 + stwu r0,-STACK_FRAME_OVERHEAD(r1) + /* * Decide what sort of machine this is and initialize the MMU. */ @@ -1633,6 +1677,7 @@ start_here: mr r7,r27 bl identify_machine bl MMU_init + /* * Go back to running unmapped so we can load up new values * for SDR1 (hash table pointer) and the segment registers @@ -1674,9 +1719,11 @@ start_here: addi r3,r3,1 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b - /* Load the BAT registers with the values set up by MMU_init. MMU_init takes care of whether we're on a 601 or not. */ + mfpvr r3 + srwi r3,r3,16 + cmpwi r3,1 lis r3,BATS@ha addi r3,r3,BATS@l tophys(r3,r3,r4) @@ -1696,6 +1743,20 @@ start_here: li r4,MSR_KERNEL lis r3,start_kernel@h ori r3,r3,start_kernel@l +#ifdef __SMP__ + /* the second time through here we go to + * start_secondary(). -- Cort + */ + lis r5,first_cpu_booted@h + ori r5,r5,first_cpu_booted@l + tophys(r5,r5,r3) + lwz r5,0(r5) + cmpi 0,r5,0 + beq 10f + lis r3,start_secondary@h + ori r3,r3,start_secondary@l +10: +#endif /* __SMP__ */ mtspr SRR0,r3 mtspr SRR1,r4 rfi /* enable MMU and jump to start_kernel */ @@ -1954,6 +2015,8 @@ int_return: beq+ 1f addi r3,r1,STACK_FRAME_OVERHEAD bl do_IRQ + .globl lost_irq_ret +lost_irq_ret: b 3b 1: lis r4,bh_mask@ha lwz r4,bh_mask@l(r4) @@ -1962,6 +2025,8 @@ int_return: and. r4,r4,r5 beq+ 2f bl do_bottom_half + .globl do_bottom_half_ret +do_bottom_half_ret: SYNC mtmsr r30 /* disable interrupts again */ SYNC @@ -1979,6 +2044,8 @@ int_return: li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD bl do_signal + .globl do_signal_ret +do_signal_ret: b 0b 8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */ stw r4,TSS+KSP(r2) /* save kernel stack pointer */ @@ -2221,173 +2288,6 @@ _GLOBAL(flush_hash_page) _GLOBAL(__main) blr -#ifdef __SMP__ -/* - * Secondary processor begins executing here. - */ - .globl secondary_entry -secondary_entry: - /* just like __start() with a few changes -- Cort */ - mfspr r9,PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 - lis r11,KERNELBASE@h - bne 4f - ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f - oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ - oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ - mtspr IBAT1U,r9 - mtspr IBAT1L,r10 - b 5f -4: ori r11,r11,0x1ff /* set up BAT registers for 604 */ - li r8,2 - mtspr DBAT0U,r11 - mtspr DBAT0L,r8 -5: mtspr IBAT0U,r11 - mtspr IBAT0L,r8 - isync -/* - * we now have the 1st 16M of ram mapped with the bats. - * prep needs the mmu to be turned on here, but pmac already has it on. - * this shouldn't bother the pmac since it just gets turned on again - * as we jump to our code at KERNELBASE. -- Cort - */ - mfmsr r0 - ori r0,r0,MSR_DR|MSR_IR - mtspr SRR1,r0 - lis r0,100f@h - ori r0,r0,100f@l - mtspr SRR0,r0 - SYNC - rfi /* enables MMU */ -100: - /* - * Enable caches and 604-specific features if necessary. - */ - mfspr r9,PVR - rlwinm r9,r9,16,16,31 - cmpi 0,r9,1 - beq 4f /* not needed for 601 */ - mfspr r11,HID0 - andi. r0,r11,HID0_DCE - ori r11,r11,HID0_ICE|HID0_DCE - ori r8,r11,HID0_ICFI - bne 3f /* don't invalidate the D-cache */ - ori r8,r8,HID0_DCI /* unless it wasn't enabled */ -3: - /* turn on dpm for 603 */ - cmpi 0,r9,3 - bne 10f - oris r11,r11,HID0_DPM@h -10: - sync - mtspr HID0,r8 /* enable and invalidate caches */ - sync - mtspr HID0,r11 /* enable caches */ - sync - isync - cmpi 0,r9,4 /* check for 604 */ - cmpi 1,r9,9 /* or 604e */ - cmpi 2,r9,10 /* or mach5 */ - cror 2,2,6 - cror 2,2,10 - bne 4f - ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */ - bne 2,5f - ori r11,r11,HID0_BTCD -5: mtspr HID0,r11 /* superscalar exec & br history tbl */ -4: -/* - * init_MMU on the first processor has setup the variables - * for us - all we need to do is load them -- Cort - */ - -/* - * Go back to running unmapped so we can load up new values - * for SDR1 (hash table pointer) and the segment registers - * and change to using our exception vectors. - */ - lis r6,_SDR1@ha - lwz r6,_SDR1@l(r6) - lis r4,2f@h - ori r4,r4,2f@l - tophys(r4,r4,r3) - li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) - mtspr SRR0,r4 - mtspr SRR1,r3 - rfi -/* Load up the kernel context */ -2: - /* get ptr to current */ - lis r2,current_set@h - ori r2,r2,current_set@l - /* assume we're second processor for now */ - tophys(r2,r2,r10) - lwz r2,4(r2) - /* stack */ - addi r1,r2,TASK_UNION_SIZE - li r0,0 - tophys(r3,r1,r10) - stwu r0,-STACK_FRAME_OVERHEAD(r3) - - SYNC /* Force all PTE updates to finish */ - tlbia /* Clear all TLB entries */ - mtspr SDR1,r6 - li r0,16 /* load up segment register values */ - mtctr r0 /* for context 0 */ - lis r3,0x2000 /* Ku = 1, VSID = 0 */ - li r4,0 -3: mtsrin r3,r4 - addi r3,r3,1 /* increment VSID */ - addis r4,r4,0x1000 /* address of next segment */ - bdnz 3b - -/* Load the BAT registers with the values set up by MMU_init. - MMU_init takes care of whether we're on a 601 or not. */ - lis r3,BATS@ha - addi r3,r3,BATS@l - tophys(r3,r3,r4) - LOAD_BAT(0,0,r3,r4,r5) - LOAD_BAT(1,16,r3,r4,r5) - LOAD_BAT(2,32,r3,r4,r5) - LOAD_BAT(3,48,r3,r4,r5) - -/* Set up for using our exception vectors */ - /* ptr to phys current tss */ - tophys(r4,r2,r4) - addi r4,r4,TSS /* init task's TSS */ - mtspr SPRG3,r4 - li r3,0 - mtspr SPRG2,r3 /* 0 => r1 has kernel sp */ - - /* need to flush/invalidate caches too */ - li r3,0x4000/CACHE_LINE_SIZE - li r4,0 - mtctr r3 -73: dcbst 0,r4 - addi r4,r4,CACHE_LINE_SIZE - bdnz 73b - sync - li r4,0 - mtctr r3 -72: icbi 0,r4 - addi r4,r4,CACHE_LINE_SIZE - bdnz 72b - sync - isync -77: -/* Now turn on the MMU for real! */ - li r4,MSR_KERNEL - lis r3,start_secondary@h - ori r3,r3,start_secondary@l - mtspr SRR0,r3 - mtspr SRR1,r4 - rfi /* enable MMU and jump to start_kernel */ -/* should never return */ - .long 0 -#endif /* __SMP__ */ - /* * PROM code for specific machines follows. Put it * here so it's easy to add arch-specific sections later. diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index bd7980678..b6c338946 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -1,5 +1,5 @@ /* - * $Id: idle.c,v 1.48 1998/07/30 11:29:22 davem Exp $ + * $Id: idle.c,v 1.56 1998/10/13 19:14:36 paulus Exp $ * * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. @@ -11,8 +11,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#define __KERNEL_SYSCALLS__ - #include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> @@ -32,9 +30,6 @@ #include <asm/processor.h> #include <asm/mmu.h> #include <asm/cache.h> -#ifdef CONFIG_PMAC -#include <asm/mediabay.h> -#endif void zero_paged(void); void power_save(void); @@ -53,22 +48,15 @@ int idled(void *unused) __sti(); /* endless loop with no priority at all */ - current->priority = -100; - current->counter = -100; + current->priority = 0; + current->counter = 0; check_pgt_cache(); if ( !current->need_resched && zero_paged_on ) zero_paged(); if ( !current->need_resched && htab_reclaim_on ) htab_reclaim(); - - /* - * Only processor 1 may sleep now since processor 2 would - * never wake up. Need to add timer code for processor 2 - * then it can sleep. -- Cort - */ -#ifndef __SMP__ if ( !current->need_resched ) power_save(); -#endif /* __SMP__ */ + run_task_queue(&tq_scheduler); schedule(); } ret = 0; @@ -92,15 +80,9 @@ int cpu_idle(void *unused) */ asmlinkage int sys_idle(void) { - extern int media_bay_task(void *); if(current->pid != 0) return -EPERM; -#ifdef CONFIG_PMAC - if (media_bay_present) - kernel_thread(media_bay_task, NULL, 0); -#endif - idled(NULL); return 0; /* should never execute this but it makes gcc happy -- Cort */ } diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index cb4d0872e..a180e5f0a 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -9,7 +9,7 @@ * Adapted for Power Macintosh by Paul Mackerras * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). - * + * * This file contains the code used by various IRQ handling routines: * asking for different IRQ's should be done through these routines * instead of just grabbing them. Thus setups with different IRQ numbers @@ -50,55 +50,29 @@ #include <asm/gg2.h> #include <asm/cache.h> #include <asm/prom.h> +#include <asm/amigaints.h> +#include <asm/amigahw.h> +#include <asm/amigappc.h> #ifdef CONFIG_8xx #include <asm/8xx_immap.h> #include <asm/mbx.h> #endif -#include <asm/amigaints.h> -#include <asm/amigahw.h> -#include <asm/amigappc.h> -#define VEC_SPUR (24) extern void process_int(unsigned long vec, struct pt_regs *fp); extern void apus_init_IRQ(void); extern void amiga_disable_irq(unsigned int irq); extern void amiga_enable_irq(unsigned int irq); +static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } +static volatile unsigned char *chrp_int_ack_special; +extern volatile unsigned long ipi_count; +static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base); + #ifdef CONFIG_APUS /* Rename a few functions. Requires the CONFIG_APUS protection. */ #define request_irq nop_ppc_request_irq #define free_irq nop_ppc_free_irq #define get_irq_list nop_get_irq_list #endif - -#undef SHOW_IRQ - -#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) - -int max_irqs; -unsigned int local_irq_count[NR_CPUS]; -static struct irqaction *irq_action[NR_IRQS]; -static int spurious_interrupts = 0; -static unsigned int cached_irq_mask[NR_MASK_WORDS]; -unsigned int lost_interrupts[NR_MASK_WORDS]; -atomic_t n_lost_interrupts; - -static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } - -/*spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;*/ -#ifdef __SMP__ -atomic_t __ppc_bh_counter = ATOMIC_INIT(0); -#else -int __ppc_bh_counter = 0; -#endif -static volatile unsigned char *gg2_int_ack_special; -extern volatile unsigned long ipi_count; - -#define cached_21 (((char *)(cached_irq_mask))[3]) -#define cached_A1 (((char *)(cached_irq_mask))[2]) - -/* - * These are set to the appropriate functions by init_IRQ() - */ #ifndef CONFIG_8xx void (*mask_and_ack_irq)(int irq_nr); void (*mask_irq)(unsigned int irq_nr); @@ -113,10 +87,24 @@ void (*unmask_irq)(unsigned int irq_nr); #define unmask_irq(irq) mbx_unmask_irq(irq) #endif /* CONFIG_8xx */ - -/* prep */ +#define VEC_SPUR (24) +#undef SHOW_IRQ +#undef SHOW_GATWICK_IRQS +#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) +#define cached_21 (((char *)(cached_irq_mask))[3]) +#define cached_A1 (((char *)(cached_irq_mask))[2]) #define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21 +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +int max_irqs; +int max_real_irqs; +static struct irqaction *irq_action[NR_IRQS]; +static int spurious_interrupts = 0; +static unsigned int cached_irq_mask[NR_MASK_WORDS]; +unsigned int lost_interrupts[NR_MASK_WORDS]; +atomic_t n_lost_interrupts; + /* pmac */ struct pmac_irq_hw { unsigned int flag; @@ -126,13 +114,32 @@ struct pmac_irq_hw { }; /* XXX these addresses should be obtained from the device tree */ -volatile struct pmac_irq_hw *pmac_irq_hw[2] = { +volatile struct pmac_irq_hw *pmac_irq_hw[4] = { (struct pmac_irq_hw *) 0xf3000020, (struct pmac_irq_hw *) 0xf3000010, + (struct pmac_irq_hw *) 0xf4000020, + (struct pmac_irq_hw *) 0xf4000010, }; -#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */ +/* This is the interrupt used on the main controller for the secondary + controller. Happens on PowerBooks G3 Series (a second mac-io) + -- BenH + */ +static int second_irq = -999; + +/* Returns the number of 0's to the left of the most significant 1 bit */ +static inline int cntlzw(int bits) +{ + int lz; + + asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits)); + return lz; +} +static inline void sync(void) +{ + asm volatile ("sync"); +} /* nasty hack for shared irq's since we need to do kmalloc calls but * can't very very early in the boot when we need to do a request irq. @@ -190,12 +197,12 @@ void i8259_mask_and_ack_irq(int irq_nr) /* spin_unlock(&irq_controller_lock);*/ } -void pmac_mask_and_ack_irq(int irq_nr) +void __pmac pmac_mask_and_ack_irq(int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; - if (irq_nr >= max_irqs) + if ((unsigned)irq_nr >= max_irqs) return; /*spin_lock(&irq_controller_lock);*/ @@ -205,13 +212,15 @@ void pmac_mask_and_ack_irq(int irq_nr) out_le32(&pmac_irq_hw[i]->ack, bit); out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]); out_le32(&pmac_irq_hw[i]->ack, bit); + /* make sure ack gets to controller before we enable interrupts */ + sync(); /*spin_unlock(&irq_controller_lock);*/ /*if ( irq_controller_lock.lock ) panic("irq controller lock still held in mask and ack\n");*/ } -void chrp_mask_and_ack_irq(int irq_nr) +void __openfirmware chrp_mask_and_ack_irq(int irq_nr) { /* spinlocks are done by i8259_mask_and_ack() - Cort */ if (is_8259_irq(irq_nr)) @@ -228,12 +237,12 @@ static void i8259_set_irq_mask(int irq_nr) } } -static void pmac_set_irq_mask(int irq_nr) +static void __pmac pmac_set_irq_mask(int irq_nr) { unsigned long bit = 1UL << (irq_nr & 0x1f); int i = irq_nr >> 5; - if (irq_nr >= max_irqs) + if ((unsigned)irq_nr >= max_irqs) return; /* enable unmasked interrupts */ @@ -268,19 +277,20 @@ static void i8259_unmask_irq(unsigned int irq_nr) i8259_set_irq_mask(irq_nr); } -static void pmac_mask_irq(unsigned int irq_nr) +static void __pmac pmac_mask_irq(unsigned int irq_nr) { clear_bit(irq_nr, cached_irq_mask); pmac_set_irq_mask(irq_nr); + sync(); } -static void pmac_unmask_irq(unsigned int irq_nr) +static void __pmac pmac_unmask_irq(unsigned int irq_nr) { set_bit(irq_nr, cached_irq_mask); pmac_set_irq_mask(irq_nr); } -static void chrp_mask_irq(unsigned int irq_nr) +static void __openfirmware chrp_mask_irq(unsigned int irq_nr) { if (is_8259_irq(irq_nr)) i8259_mask_irq(irq_nr); @@ -288,7 +298,7 @@ static void chrp_mask_irq(unsigned int irq_nr) openpic_disable_irq(irq_to_openpic(irq_nr)); } -static void chrp_unmask_irq(unsigned int irq_nr) +static void __openfirmware chrp_unmask_irq(unsigned int irq_nr) { if (is_8259_irq(irq_nr)) i8259_unmask_irq(irq_nr); @@ -342,7 +352,7 @@ int get_irq_list(char *buf) for (i = 0 ; i < NR_IRQS ; i++) { action = irq_action[i]; - if (!action || !action->handler) + if ((!action || !action->handler) && (i != second_irq)) continue; len += sprintf(buf+len, "%3d: ", i); #ifdef __SMP__ @@ -358,7 +368,10 @@ int get_irq_list(char *buf) len += sprintf(buf+len, " 82c59 "); break; case _MACH_Pmac: - len += sprintf(buf+len, " PMAC-PIC "); + if (i < 64) + len += sprintf(buf+len, " PMAC-PIC "); + else + len += sprintf(buf+len, " GATWICK "); break; case _MACH_chrp: if ( is_8259_irq(i) ) @@ -371,83 +384,132 @@ int get_irq_list(char *buf) break; } - len += sprintf(buf+len, " %s",action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s", action->name); - } - len += sprintf(buf+len, "\n"); + if (i != second_irq) { + len += sprintf(buf+len, " %s",action->name); + for (action=action->next; action; action = action->next) { + len += sprintf(buf+len, ", %s", action->name); + } + len += sprintf(buf+len, "\n"); + } else + len += sprintf(buf+len, " Gatwick secondary IRQ controller\n"); } #ifdef __SMP__ /* should this be per processor send/receive? */ - len += sprintf(buf+len, "IPI: %10lu\n", ipi_count); + len += sprintf(buf+len, "IPI: %10lu", ipi_count); for ( i = 0 ; i <= smp_num_cpus-1; i++ ) len += sprintf(buf+len," "); - len += sprintf(buf+len, " interprocessor messages received\n"); + len += sprintf(buf+len, " interprocessor messages received\n"); #endif len += sprintf(buf+len, "BAD: %10u",spurious_interrupts); for ( i = 0 ; i <= smp_num_cpus-1; i++ ) len += sprintf(buf+len," "); - len += sprintf(buf+len, " spurious or short\n"); + len += sprintf(buf+len, " spurious or short\n"); return len; } +/* + * Global interrupt locks for SMP. Allow interrupts to come in on any + * CPU, yet make cli/sti act globally to protect critical regions.. + */ #ifdef __SMP__ -/* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; +unsigned volatile int global_irq_lock; +atomic_t global_irq_count; -/* This protects IRQ's. */ -spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; -unsigned long previous_irqholder; +atomic_t global_bh_count; +atomic_t global_bh_lock; -/* This protects BH software state (masks, things like that). */ -spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; +static void show(char * str) +{ + int i; + unsigned long *stack; + int cpu = smp_processor_id(); -/* Global IRQ locking depth. */ -atomic_t global_irq_count = ATOMIC_INIT(0); + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [%d %d]\n", + atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); + printk("bh: %d [%d %d]\n", + atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]); + stack = (unsigned long *) &str; + for (i = 40; i ; i--) { + unsigned long x = *++stack; + if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) { + printk("<[%08lx]> ", x); + } + } +} -#undef INIT_STUCK -#define INIT_STUCK 100000000 +#define MAXCOUNT 100000000 +static inline void wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if (!--count) { + show("wait_on_bh"); + count = ~0; + } + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 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; } -void wait_on_irq(int cpu, unsigned long where) +#define MAXCOUNT 100000000 +static inline void wait_on_irq(int cpu) { - int stuck = INIT_STUCK; - int local_count = local_irq_count[cpu]; + int count = MAXCOUNT; - /* Are we the only one in an interrupt context? */ - while (local_count != atomic_read(&global_irq_count)) { - /* - * No such luck. Now we need to release the lock, - * _and_ release our interrupt context, because - * otherwise we'd have dead-locks and live-locks - * and other fun things. - */ - atomic_sub(local_count, &global_irq_count); - spin_unlock(&global_irq_lock); + for (;;) { /* - * Wait for everybody else to go away and release - * their things before trying to get the lock again. + * 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)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + clear_bit(0,&global_irq_lock); + for (;;) { - STUCK; + if (!--count) { + show("wait_on_irq"); + count = ~0; + } + __sti(); + /* don't worry about the lock race Linus found + * on intel here. -- Cort + */ + __cli(); if (atomic_read(&global_irq_count)) continue; - if (*((unsigned char *)&global_irq_lock)) + if (global_irq_lock) continue; - if (spin_trylock(&global_irq_lock)) + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + continue; + if (!test_and_set_bit(0,&global_irq_lock)) break; } - atomic_add(local_count, &global_irq_count); } } -#define irq_active(cpu) \ - (global_irq_count != local_irq_count[cpu]) +/* + * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void synchronize_bh(void) +{ + if (atomic_read(&global_bh_count) && !in_interrupt()) + wait_on_bh(); +} + /* * This is called when we want to synchronize with @@ -455,97 +517,125 @@ void wait_on_irq(int cpu, unsigned long where) * stop sending interrupts: but to make sure there * are no interrupts that are executing on another * CPU we need to call this function. - * - * On UP this is a no-op. */ void synchronize_irq(void) { - int cpu = smp_processor_id(); - int local_count = local_irq_count[cpu]; - - /* Do we need to wait? */ - if (local_count != atomic_read(&global_irq_count)) { - /* The stupid way to do this */ + if (atomic_read(&global_irq_count)) { + /* Stupid approach */ cli(); sti(); } } -#undef INIT_STUCK -#define INIT_STUCK 10000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {\ -ll_printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} - -void get_irqlock(int cpu, unsigned long where) +static inline void get_irqlock(int cpu) { - int stuck = INIT_STUCK; - if (!spin_trylock(&global_irq_lock)) { + if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ if ((unsigned char) cpu == global_irq_holder) return; /* Uhhuh.. Somebody else got it. Wait.. */ do { do { - STUCK; - barrier(); - } while (*((unsigned char *)&global_irq_lock)); - } while (!spin_trylock(&global_irq_lock)); + + } while (test_bit(0,&global_irq_lock)); + } while (test_and_set_bit(0,&global_irq_lock)); } - - /* - * Ok, we got the lock bit. - * But that's actually just the easy part.. Now - * we need to make sure that nobody else is running + /* + * We also to make sure that nobody else is running * in an interrupt context. */ - wait_on_irq(cpu, where); + wait_on_irq(cpu); + /* - * Finally. + * Ok, finally.. */ global_irq_holder = cpu; - previous_irqholder = where; } +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + * + * If we already have local interrupts disabled, + * this will not turn a local disable into a + * global one (problems with spinlocks: this makes + * save_flags+cli+sti usable inside a spinlock). + */ void __global_cli(void) { - int cpu = smp_processor_id(); - unsigned long where; - __asm__("mr %0,31" : "=r" (where)); /* get lr */ - __cli(); - get_irqlock(cpu, where); + unsigned int flags; + + __save_flags(flags); + if (flags & (1 << 15)) { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count[cpu]) + get_irqlock(cpu); + } } void __global_sti(void) { - release_irqlock(smp_processor_id()); + int cpu = smp_processor_id(); + + if (!local_irq_count[cpu]) + release_irqlock(cpu); __sti(); } +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ unsigned long __global_save_flags(void) { - return global_irq_holder == (unsigned char) smp_processor_id(); + int retval; + int local_enabled; + unsigned long flags; + + __save_flags(flags); + local_enabled = (flags >> 15) & 1; + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count[smp_processor_id()]) { + if (local_enabled) + retval = 1; + if (global_irq_holder == (unsigned char) smp_processor_id()) + retval = 0; + } + return retval; } void __global_restore_flags(unsigned long flags) { switch (flags) { case 0: - release_irqlock(smp_processor_id()); - __sti(); + __global_cli(); break; case 1: - __global_cli(); + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); break; default: printk("global_restore_flags: %08lx (%08lx)\n", flags, (&flags)[-1]); } } -#endif /* __SMP__ */ +#endif /* __SMP__ */ asmlinkage void do_IRQ(struct pt_regs *regs) { @@ -569,9 +659,6 @@ asmlinkage void do_IRQ(struct pt_regs *regs) if (!atomic_read(&n_lost_interrupts)) { extern void smp_message_recv(void); - goto out; - - ipi_count++; smp_message_recv(); goto out; } @@ -584,20 +671,48 @@ asmlinkage void do_IRQ(struct pt_regs *regs) switch ( _machine ) { case _MACH_Pmac: - for (irq = max_irqs - 1; irq > 0; irq -= 32) { - int i = irq >> 5, lz; + for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { + int i = irq >> 5; bits = ld_le32(&pmac_irq_hw[i]->flag) | lost_interrupts[i]; if (bits == 0) continue; - /* lz = number of 0 bits to left of most sig. 1 */ - asm ("cntlzw %0,%1" : "=r" (lz) : "r" (bits)); - irq -= lz; + irq -= cntlzw(bits); break; } + + /* Here, we handle interrupts coming from Gatwick, + * normal interrupt code will take care of acking and + * masking the irq on Gatwick itself but we ack&mask + * the Gatwick main interrupt on Heathrow now. It's + * unmasked later, after interrupt handling. -- BenH + */ + if (irq == second_irq) { + mask_and_ack_irq(second_irq); + for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) { + int i = irq >> 5; + bits = ld_le32(&pmac_irq_hw[i]->flag) + | lost_interrupts[i]; + if (bits == 0) + continue; + irq -= cntlzw(bits); + break; + } + /* If not found, on exit, irq is 63 (128-1-32-32). + * We set it to -1 and revalidate second controller + */ + if (irq < max_real_irqs) { + irq = -1; + unmask_irq(second_irq); + } +#ifdef SHOW_GATWICK_IRQS + printk("Gatwick irq %d (i:%d, bits:0x%08lx\n", irq, i, bits); +#endif + } + break; case _MACH_chrp: - irq = openpic_irq(0); + irq = openpic_irq(0); if (irq == IRQ_8259_CASCADE) { /* @@ -605,7 +720,7 @@ asmlinkage void do_IRQ(struct pt_regs *regs) * * This should go in the above mask/ack code soon. -- Cort */ - irq = *gg2_int_ack_special; + irq = *chrp_int_ack_special; /* * Acknowledge as soon as possible to allow i8259 * interrupt nesting @@ -682,11 +797,13 @@ apus_out: } #endif } - + if (irq < 0) { - printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n", regs->nip); + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + spurious_interrupts++; goto out; - } + } #else /* CONFIG_8xx */ /* For MPC8xx, read the SIVEC register and shift the bits down @@ -695,9 +812,7 @@ apus_out: bits = ((immap_t *)MBX_IMAP_ADDR)->im_siu_conf.sc_sivec; irq = bits >> 26; #endif /* CONFIG_8xx */ - mask_and_ack_irq(irq); - status = 0; action = irq_action[irq]; kstat.irqs[cpu][irq]++; @@ -707,14 +822,10 @@ apus_out: do { status |= action->flags; action->handler(irq, action->dev_id, regs); - /*if (status & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq);*/ action = action->next; } while ( action ); __cli(); - /* spin_lock(&irq_controller_lock);*/ unmask_irq(irq); - /* spin_unlock(&irq_controller_lock);*/ } else { #ifndef CONFIG_8xx if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */ @@ -723,8 +834,13 @@ apus_out: disable_irq( irq ); } + /* This was a gatwick sub-interrupt, we re-enable them on Heathrow + now */ + if (_machine == _MACH_Pmac && irq >= max_real_irqs) + unmask_irq(second_irq); + /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */ -#ifndef CONFIG_8xx +#ifndef CONFIG_8xx if ( is_prep && (irq > 7) ) goto retry_cascade; /* do_bottom_half is called if necessary from int_return in head.S */ @@ -750,12 +866,16 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) #ifdef SHOW_IRQ printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n", - irq,handler,devname,dev_id); + irq,(int)handler,devname,(int)dev_id); #endif /* SHOW_IRQ */ if (irq >= NR_IRQS) return -EINVAL; + /* Cannot allocate second controller IRQ */ + if (irq == second_irq) + return -EBUSY; + if (!handler) { /* Free */ @@ -780,7 +900,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) cli(); action->handler = handler; - action->flags = irqflags; + action->flags = irqflags; action->mask = 0; action->name = devname; action->dev_id = dev_id; @@ -851,6 +971,9 @@ __initfunc(void init_IRQ(void)) { extern void xmon_irq(int, void *, struct pt_regs *); int i; + struct device_node *irqctrler; + unsigned long addr; + struct device_node *np; #ifndef CONFIG_8xx switch (_machine) @@ -860,23 +983,77 @@ __initfunc(void init_IRQ(void)) mask_irq = pmac_mask_irq; unmask_irq = pmac_unmask_irq; - /* G3 powermacs have 64 interrupts, others have 32 */ - max_irqs = (find_devices("mac-io") ? 64 : 32); - printk("System has %d possible interrupts\n", max_irqs); + /* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, + others have 32 */ + max_irqs = max_real_irqs = 32; + irqctrler = find_devices("mac-io"); + if (irqctrler) + { + max_real_irqs = 64; + if (irqctrler->next) + max_irqs = 128; + else + max_irqs = 64; + } + + /* get addresses of first controller */ + if (irqctrler) { + if (irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 0; i < 2; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (2 - i) * 0x10); + } + + /* get addresses of second controller */ + irqctrler = (irqctrler->next) ? irqctrler->next : NULL; + if (irqctrler && irqctrler->n_addrs > 0) { + addr = (unsigned long) + ioremap(irqctrler->addrs[0].address, 0x40); + for (i = 2; i < 4; ++i) + pmac_irq_hw[i] = (volatile struct pmac_irq_hw*) + (addr + (4 - i) * 0x10); + } + } + /* disable all interrupts in all controllers */ for (i = 0; i * 32 < max_irqs; ++i) out_le32(&pmac_irq_hw[i]->enable, 0); + + + /* get interrupt line of secondary interrupt controller */ + if (irqctrler) { + second_irq = irqctrler->intrs[0].line; + printk(KERN_INFO "irq: secondary controller on irq %d\n", + (int)second_irq); + if (device_is_compatible(irqctrler, "gatwick")) + pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs); + enable_irq(second_irq); + } + printk("System has %d possible interrupts\n", max_irqs); + if (max_irqs != max_real_irqs) + printk(KERN_DEBUG "%d interrupts on main controller\n", + max_real_irqs); + #ifdef CONFIG_XMON - request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0); + request_irq(20, xmon_irq, 0, "NMI", 0); #endif /* CONFIG_XMON */ break; case _MACH_chrp: mask_and_ack_irq = chrp_mask_and_ack_irq; mask_irq = chrp_mask_irq; unmask_irq = chrp_unmask_irq; - gg2_int_ack_special = (volatile unsigned char *) - ioremap(GG2_INT_ACK_SPECIAL, 1); - openpic_init(); + + if ( !(np = find_devices("pci") ) ) + printk("Cannot find pci to get ack address\n"); + else + { + chrp_int_ack_special = (volatile unsigned char *) + (*(unsigned long *)get_property(np, + "8259-interrupt-acknowledge", NULL)); + } + openpic_init(1); i8259_init(); cached_irq_mask[0] = cached_irq_mask[1] = ~0UL; #ifdef CONFIG_XMON @@ -935,3 +1112,61 @@ __initfunc(void init_IRQ(void)) } #endif /* CONFIG_8xx */ } + +/* This routine will fix some missing interrupt values in the device tree + * on the gatwick mac-io controller used by some PowerBooks + */ +__pmac +static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base) +{ + struct device_node *node; + static struct interrupt_info int_pool[4]; + + memset(int_pool, 0, sizeof(int_pool)); + node = gw->child; + while(node) + { + /* Fix SCC */ + if (strcasecmp(node->name, "escc") == 0) + if (node->child && node->child->n_intrs == 0) + { + node->child->n_intrs = 1; + node->child->intrs = &int_pool[0]; + int_pool[0].line = 15+irq_base; + printk(KERN_INFO "irq: fixed SCC on second controller (%d)\n", + int_pool[0].line); + } + /* Fix media-bay & left SWIM */ + if (strcasecmp(node->name, "media-bay") == 0) + { + struct device_node* ya_node; + + if (node->n_intrs == 0) + { + node->n_intrs = 1; + node->intrs = &int_pool[1]; + int_pool[1].line = 29+irq_base; + printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n", + int_pool[1].line); + } + ya_node = node->child; + while(ya_node) + { + if ((strcasecmp(ya_node->name, "floppy") == 0) && + ya_node->n_intrs == 0) + { + ya_node->n_intrs = 2; + ya_node->intrs = &int_pool[2]; + int_pool[2].line = 19+irq_base; + int_pool[3].line = 1+irq_base; + printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n", + int_pool[2].line, int_pool[3].line); + } + ya_node = ya_node->sibling; + } + } + node = node->sibling; + } + +} + diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index de55ceaa3..f13508d96 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -363,22 +363,62 @@ _GLOBAL(_get_THRM1) mfspr r3,THRM1 blr +_GLOBAL(_get_THRM2) + mfspr r3,THRM2 + blr + +_GLOBAL(_get_THRM3) + mfspr r3,THRM3 + blr + _GLOBAL(_set_THRM1) mtspr THRM1,r3 blr + +_GLOBAL(_set_THRM2) + mtspr THRM2,r3 + blr + +_GLOBAL(_set_THRM3) + mtspr THRM3,r3 + blr _GLOBAL(_get_L2CR) mfspr r3,L2CR blr - + +_GLOBAL(_set_L2CR) + mtspr L2CR,r3 + blr + _GLOBAL(_get_PVR) mfspr r3,PVR blr +/* + * These are used in the alignment trap handler when emulating + * single-precision loads and stores. + * We restore and save the fpscr so the task gets the same result + * and exceptions as if the cpu had performed the load or store. + */ _GLOBAL(cvt_fd) cvt_fd: + lfd 0,-4(r5) /* load up fpscr value */ + mtfsf 0xff,0 lfs 0,0(r3) stfd 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,-4(r5) + blr + +_GLOBAL(cvt_df) +cvt_df: + lfd 0,-4(r5) /* load up fpscr value */ + mtfsf 0xff,0 + lfd 0,0(r3) + stfs 0,0(r4) + mffs 0 /* save new fpscr value */ + stfd 0,-4(r5) blr /* @@ -390,12 +430,6 @@ _GLOBAL(get_SR) mr r3,r4 blr -_GLOBAL(cvt_df) -cvt_df: - lfd 0,0(r3) - stfs 0,0(r4) - blr - /* * Create a kernel thread * __kernel_thread(flags, fn, arg) @@ -435,7 +469,6 @@ _GLOBAL(name) \ #define __NR__exit __NR_exit SYSCALL(idle) -SYSCALL(setup) SYSCALL(sync) SYSCALL(setsid) SYSCALL(write) @@ -455,7 +488,7 @@ SYSCALL(read) .align 4 .globl sys_call_table sys_call_table: - .long sys_setup /* 0 */ + .long sys_ni_syscall /* 0 - old "setup()" system call */ .long sys_exit .long sys_fork .long sys_read @@ -472,12 +505,12 @@ sys_call_table: .long sys_mknod .long sys_chmod /* 15 */ .long sys_lchown - .long sys_ni_syscall + .long sys_ni_syscall /* old break syscall holder */ .long sys_stat .long sys_lseek .long sys_getpid /* 20 */ .long sys_mount - .long sys_umount + .long sys_oldumount .long sys_setuid .long sys_getuid .long sys_stime /* 25 */ @@ -486,11 +519,11 @@ sys_call_table: .long sys_fstat .long sys_pause .long sys_utime /* 30 */ - .long /*sys_stty*/ sys_ni_syscall - .long /*sys_gtty*/ sys_ni_syscall + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ .long sys_access .long sys_nice - .long /*sys_ftime*/ sys_ni_syscall /* 35 */ + .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ .long sys_sync .long sys_kill .long sys_rename @@ -499,7 +532,7 @@ sys_call_table: .long sys_dup .long sys_pipe .long sys_times - .long /*sys_prof*/ sys_ni_syscall + .long sys_ni_syscall /* old prof syscall holder */ .long sys_brk /* 45 */ .long sys_setgid .long sys_getgid @@ -507,13 +540,13 @@ sys_call_table: .long sys_geteuid .long sys_getegid /* 50 */ .long sys_acct - .long /*sys_phys*/ sys_ni_syscall - .long /*sys_lock*/ sys_ni_syscall + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ .long sys_ioctl .long sys_fcntl /* 55 */ - .long /*sys_mpx*/ sys_ni_syscall + .long sys_ni_syscall /* old mpx syscall holder */ .long sys_setpgid - .long /*sys_ulimit*/ sys_ni_syscall + .long sys_ni_syscall /* old ulimit syscall holder */ .long sys_olduname .long sys_umask /* 60 */ .long sys_chroot @@ -544,7 +577,7 @@ sys_call_table: .long sys_uselib .long sys_swapon .long sys_reboot - .long old_readdir /* was sys_readdir */ + .long old_readdir .long sys_mmap /* 90 */ .long sys_munmap .long sys_truncate @@ -553,7 +586,7 @@ sys_call_table: .long sys_fchown /* 95 */ .long sys_getpriority .long sys_setpriority - .long /*sys_profil*/ sys_ni_syscall + .long sys_ni_syscall /* old profil syscall holder */ .long sys_statfs .long sys_fstatfs /* 100 */ .long sys_ioperm @@ -592,7 +625,7 @@ sys_call_table: .long sys_bdflush .long sys_sysfs /* 135 */ .long sys_personality - .long 0 /* for afs_syscall */ + .long sys_ni_syscall /* for afs_syscall */ .long sys_setfsuid .long sys_setfsgid .long sys_llseek /* 140 */ @@ -620,22 +653,28 @@ sys_call_table: .long sys_nanosleep .long sys_mremap .long sys_setresuid - .long sys_getresuid /* 165 */ + .long sys_getresuid /* 165 */ .long sys_query_module .long sys_poll .long sys_nfsservctl - .long sys_setresgid - .long sys_getresgid /* 170 */ + .long sys_setresgid + .long sys_getresgid /* 170 */ .long sys_prctl .long sys_rt_sigreturn .long sys_rt_sigaction .long sys_rt_sigprocmask - .long sys_rt_sigpending /* 175 */ + .long sys_rt_sigpending /* 175 */ .long sys_rt_sigtimedwait .long sys_rt_sigqueueinfo .long sys_rt_sigsuspend .long sys_pread - .long sys_pwrite /* 180 */ + .long sys_pwrite /* 180 */ .long sys_chown .long sys_getcwd + .long sys_capget + .long sys_capset + .long sys_sigaltstack /* 185 */ + .long sys_sendfile + .long sys_ni_syscall /* streams1 */ + .long sys_ni_syscall /* streams2 */ .space (NR_syscalls-183)*4 diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c index fd104ae9f..ec60ca5a6 100644 --- a/arch/ppc/kernel/openpic.c +++ b/arch/ppc/kernel/openpic.c @@ -133,7 +133,7 @@ static inline u_int openpic_readfield(volatile u_int *addr, u_int mask) return val & mask; } -static inline void openpic_writefield(volatile u_int *addr, u_int mask, +inline void openpic_writefield(volatile u_int *addr, u_int mask, u_int field) { u_int val = openpic_read(addr); @@ -173,7 +173,7 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask, * Initialize the OpenPIC */ -__initfunc(void openpic_init(void)) +__initfunc(void openpic_init(int main_pic)) { u_int t, i; u_int vendorid, devid, stepping, timerfreq; @@ -233,41 +233,44 @@ __initfunc(void openpic_init(void)) else printk("not set\n"); - /* Initialize timer interrupts */ - for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { - /* Disabled, Priority 0 */ - openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); - /* No processor */ - openpic_maptimer(i, 0); + if ( main_pic ) + { + /* Initialize timer interrupts */ + for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { + /* Disabled, Priority 0 */ + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); + /* No processor */ + openpic_maptimer(i, 0); + } + + /* Initialize IPI interrupts */ + for (i = 0; i < OPENPIC_NUM_IPI; i++) { + /* Disabled, Priority 0 */ + openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); + } + + /* Initialize external interrupts */ + /* SIOint (8259 cascade) is special */ + openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1); + /* Processor 0 */ + openpic_mapirq(0, 1<<0); + for (i = 1; i < NumSources; i++) { + /* Enabled, Priority 8 */ + openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0, + i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); + /* Processor 0 */ + openpic_mapirq(i, 1<<0); + } + + /* Initialize the spurious interrupt */ + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); + + if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, + "82c59 cascade", NULL)) + printk("Unable to get OpenPIC IRQ 0 for cascade\n"); + openpic_set_priority(0, 0); + openpic_disable_8259_pass_through(); } - - /* Initialize IPI interrupts */ - for (i = 0; i < OPENPIC_NUM_IPI; i++) { - /* Disabled, Priority 0 */ - openpic_initipi(i, 0, OPENPIC_VEC_IPI+i); - } - - /* Initialize external interrupts */ - /* SIOint (8259 cascade) is special */ - openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1); - /* Processor 0 */ - openpic_mapirq(0, 1<<0); - for (i = 1; i < NumSources; i++) { - /* Enabled, Priority 8 */ - openpic_initirq(i, 8, OPENPIC_VEC_SOURCE+i, 0, - i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1); - /* Processor 0 */ - openpic_mapirq(i, 1<<0); - } - - /* Initialize the spurious interrupt */ - openpic_set_spurious(OPENPIC_VEC_SPURIOUS); - - if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT, - "82c59 cascade", NULL)) - printk("Unable to get OpenPIC IRQ 0 for cascade\n"); - openpic_set_priority(0, 0); - openpic_disable_8259_pass_through(); } @@ -529,5 +532,3 @@ void openpic_set_sense(u_int irq, int sense) OPENPIC_SENSE_LEVEL, (sense ? OPENPIC_SENSE_LEVEL : 0)); } - - diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 235365f5e..359446f4f 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1,5 +1,5 @@ /* - * $Id: pci.c,v 1.36 1998/08/02 23:22:11 paulus Exp $ + * $Id: pci.c,v 1.39 1998/10/13 20:59:04 cort Exp $ * Common pmac/prep/chrp pci routines. -- Cort */ @@ -164,7 +164,7 @@ __initfunc(void get_property(find_path_device("/"), "model", NULL),3) ) { isa_io_base = 0xfe000000; - set_config_access_method(raven); + set_config_access_method(grackle); } else { @@ -201,8 +201,22 @@ __initfunc(void pcibios_fixup(void)) route_pci_interrupts(); for(dev=pci_devices; dev; dev=dev->next) { + /* + * Use our old hard-coded kludge to figure out what + * irq this device uses. This is necessary on things + * without residual data. -- Cort + */ unsigned char d = PCI_SLOT(dev->devfn); dev->irq = Motherboard_routes[Motherboard_map[d]]; +#if 0 + /* + * If we have residual data and if it knows about this + * device ask it what the irq is. + * -- Cort + */ + ppcd = residual_find_device_id( ~0L, dev->device, + -1,-1,-1, 0); +#endif } break; case _MACH_chrp: diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c index 481f69e2c..7763059f7 100644 --- a/arch/ppc/kernel/pmac_pci.c +++ b/arch/ppc/kernel/pmac_pci.c @@ -40,7 +40,6 @@ static void add_bridges(struct device_node *dev, unsigned long *mem_ptr); #define BANDIT_COHERENT 0x40 __pmac - void *pci_io_base(unsigned int bus) { struct bridge_data *bp; @@ -50,6 +49,7 @@ void *pci_io_base(unsigned int bus) return bp->io_base; } +__pmac int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, unsigned char *devfn_ptr) { @@ -68,6 +68,7 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, return 0; } +__pmac int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char *val) { @@ -90,6 +91,7 @@ int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val) { @@ -114,6 +116,7 @@ int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int *val) { @@ -138,6 +141,7 @@ int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned char val) { @@ -159,6 +163,7 @@ int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val) { @@ -182,6 +187,7 @@ int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, return PCIBIOS_SUCCESSFUL; } +__pmac int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned int val) { @@ -406,7 +412,7 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p ioremap(0xfec00000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); - bp->io_base = (void *) ioremap(0xfe000000, 0x10000); + bp->io_base = (void *) ioremap(0xfe000000, 0x20000); } if (isa_io_base == 0) isa_io_base = (unsigned long) bp->io_base; diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 7e44b404c..499e8b6a5 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -38,6 +38,7 @@ #include <linux/delay.h> #include <linux/ioport.h> #include <linux/major.h> +#include <linux/blk.h> #include <linux/vt_kern.h> #include <linux/console.h> #include <asm/prom.h> @@ -48,28 +49,89 @@ #include <asm/adb.h> #include <asm/cuda.h> #include <asm/pmu.h> -#include <asm/mediabay.h> #include <asm/ohare.h> #include <asm/mediabay.h> +#include <asm/feature.h> #include "time.h" -extern int root_mountflags; - unsigned char drive_info; +extern char saved_command_line[]; + #define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */ extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); __pmac - int pmac_get_cpuinfo(char *buffer) { int len; - /* should find motherboard type here as well */ - len = sprintf(buffer,"machine\t\t: PowerMac\n"); + struct device_node *np; + char *pp; + int plen; + + /* find motherboard type */ + len = sprintf(buffer, "machine\t\t: "); + np = find_devices("device-tree"); + if (np != NULL) { + pp = (char *) get_property(np, "model", NULL); + if (pp != NULL) + len += sprintf(buffer+len, "%s\n", pp); + else + len += sprintf(buffer+len, "PowerMac\n"); + pp = (char *) get_property(np, "compatible", &plen); + if (pp != NULL) { + len += sprintf(buffer+len, "motherboard\t:"); + while (plen > 0) { + int l = strlen(pp) + 1; + len += sprintf(buffer+len, " %s", pp); + plen -= l; + pp += l; + } + buffer[len++] = '\n'; + } + } else + len += sprintf(buffer+len, "PowerMac\n"); + + /* find l2 cache info */ + np = find_devices("l2-cache"); + if (np == 0) + np = find_type_devices("cache"); + if (np != 0) { + unsigned int *ic = (unsigned int *) + get_property(np, "i-cache-size", NULL); + unsigned int *dc = (unsigned int *) + get_property(np, "d-cache-size", NULL); + len += sprintf(buffer+len, "L2 cache\t:"); + if (get_property(np, "cache-unified", NULL) != 0 && dc) { + len += sprintf(buffer+len, " %dK unified", *dc / 1024); + } else { + if (ic) + len += sprintf(buffer+len, " %dK instruction", + *ic / 1024); + if (dc) + len += sprintf(buffer+len, "%s %dK data", + (ic? " +": ""), *dc / 1024); + } + pp = get_property(np, "ram-type", NULL); + if (pp) + len += sprintf(buffer+len, " %s", pp); + buffer[len++] = '\n'; + } + + /* find ram info */ + np = find_devices("memory"); + if (np != 0) { + struct reg_property *reg = (struct reg_property *) + get_property(np, "reg", NULL); + if (reg != 0) { + len += sprintf(buffer+len, "memory\t\t: %dMB\n", + reg->size >> 20); + } + } + return len; } @@ -82,6 +144,13 @@ pmac_get_cpuinfo(char *buffer) #include "../../../drivers/scsi/sd.h" #include "../../../drivers/scsi/hosts.h" +#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) +#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) +#define SD_MINOR_NUMBER(i) ((i) & 255) +#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), SD_MINOR_NUMBER(i)) +#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) + +__init kdev_t sd_find_target(void *host, int tgt) { Scsi_Disk *dp; @@ -90,7 +159,7 @@ kdev_t sd_find_target(void *host, int tgt) for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) if (dp->device != NULL && dp->device->host == host && dp->device->id == tgt) - return MKDEV(SCSI_DISK_MAJOR, i << 4); + return MKDEV_SD(i); return 0; } #endif @@ -99,13 +168,13 @@ kdev_t sd_find_target(void *host, int tgt) * Dummy mksound function that does nothing. * The real one is in the dmasound driver. */ +__pmac static void pmac_mksound(unsigned int hz, unsigned int ticks) { } static volatile u32 *sysctrl_regs; -static volatile u32 *feature_addr; __initfunc(void pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) @@ -137,10 +206,11 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) and some registers used by smp boards */ sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); __ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY)); + ohare_init(); *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); - ohare_init(); + feature_init(); #ifdef CONFIG_KGDB zs_kgdb_hook(0); @@ -154,43 +224,30 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) #endif kd_mksound = pmac_mksound; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE); } __initfunc(static void ohare_init(void)) { - struct device_node *np; - - np = find_devices("ohare"); - if (np == 0) - return; - if (np->next != 0) - printk(KERN_WARNING "only using the first ohare\n"); - if (np->n_addrs == 0) { - printk(KERN_ERR "No addresses for %s\n", np->full_name); - return; - } - feature_addr = (volatile u32 *) - ioremap(np->addrs[0].address + OHARE_FEATURE_REG, 4); - - if (find_devices("via-pmu") == 0) { - printk(KERN_INFO "Twiddling the magic ohare bits\n"); - out_le32(feature_addr, STARMAX_FEATURES); - } else { - out_le32(feature_addr, in_le32(feature_addr) | PBOOK_FEATURES); - printk(KERN_DEBUG "feature reg = %x\n", in_le32(feature_addr)); - } - /* * Turn on the L2 cache. * We assume that we have a PSX memory controller iff * we have an ohare I/O controller. */ - if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { - if (sysctrl_regs[4] & 0x10) - sysctrl_regs[4] |= 0x04000020; - else - sysctrl_regs[4] |= 0x04000000; - printk(KERN_INFO "Level 2 cache enabled\n"); + if (find_devices("ohare") != NULL) { + if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { + if (sysctrl_regs[4] & 0x10) + sysctrl_regs[4] |= 0x04000020; + else + sysctrl_regs[4] |= 0x04000000; + printk(KERN_INFO "Level 2 cache enabled\n"); + } } } @@ -201,8 +258,10 @@ int boot_target; int boot_part; kdev_t boot_dev; -__initfunc(void powermac_init(void)) +void __init powermac_init(void) { + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return; adb_init(); pmac_nvram_init(); if (_machine == _MACH_Pmac) { @@ -210,6 +269,7 @@ __initfunc(void powermac_init(void)) } } +#ifdef CONFIG_SCSI __initfunc(void note_scsi_host(struct device_node *node, void *host)) { @@ -238,28 +298,67 @@ note_scsi_host(struct device_node *node, void *host)) } } } +#endif -__initfunc(void find_boot_device(void)) +#ifdef CONFIG_BLK_DEV_IDE_PMAC +extern int pmac_ide_count; +extern struct device_node *pmac_ide_node[]; +static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; + +__initfunc(kdev_t find_ide_boot(void)) { - kdev_t dev; + char *p; + int i, n; - if (kdev_t_to_nr(ROOT_DEV) != 0) - return; - ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE); - if (boot_host == NULL) - return; + if (bootdevice == NULL) + return 0; + p = strrchr(bootdevice, '/'); + if (p == NULL) + return 0; + n = p - bootdevice; + + /* + * Look through the list of IDE interfaces for this one. + */ + for (i = 0; i < pmac_ide_count; ++i) { + char *name = pmac_ide_node[i]->full_name; + if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) { + /* XXX should cope with the 2nd drive as well... */ + return MKDEV(ide_majors[i], 0); + } + } + + return 0; +} +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ + +__initfunc(void find_boot_device(void)) +{ #ifdef CONFIG_SCSI - dev = sd_find_target(boot_host, boot_target); - if (dev == 0) - return; - boot_dev = MKDEV(MAJOR(dev), MINOR(dev) + boot_part); + if (boot_host != NULL) { + boot_dev = sd_find_target(boot_host, boot_target); + if (boot_dev != 0) + return; + } +#endif +#ifdef CONFIG_BLK_DEV_IDE_PMAC + boot_dev = find_ide_boot(); #endif - /* XXX should cope with booting from IDE also */ } -__initfunc(void note_bootable_part(kdev_t dev, int part)) +/* can't be initfunc - can be called whenever a disk is first accessed */ +__pmac +void note_bootable_part(kdev_t dev, int part) { static int found_boot = 0; + char *p; + + /* Do nothing if the root has been set already. */ + if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)) + return; + p = strstr(saved_command_line, "root="); + if (p != NULL && (p == saved_command_line || p[-1] == ' ')) + return; if (!found_boot) { find_boot_device(); diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c index c88c8bae9..0196c5eb6 100644 --- a/arch/ppc/kernel/pmac_support.c +++ b/arch/ppc/kernel/pmac_support.c @@ -25,8 +25,7 @@ static int nvram_mult; #define NVRAM_SIZE 0x2000 /* 8kB of non-volatile RAM */ -__pmac - +__init void pmac_nvram_init(void) { struct device_node *dp; diff --git a/arch/ppc/kernel/ppc_defs.h b/arch/ppc/kernel/ppc_defs.h new file mode 100644 index 000000000..83315a2ae --- /dev/null +++ b/arch/ppc/kernel/ppc_defs.h @@ -0,0 +1,69 @@ +/* + * WARNING! This file is automatically generated - DO NOT EDIT! + */ +#define KERNELBASE -1073741824 +#define STATE 0 +#define NEXT_TASK 48 +#define COUNTER 24 +#define PROCESSOR 36 +#define SIGPENDING 8 +#define TSS 568 +#define MM 872 +#define TASK_STRUCT_SIZE 912 +#define KSP 0 +#define PG_TABLES 4 +#define PGD 8 +#define LAST_SYSCALL 20 +#define PT_REGS 12 +#define PF_TRACESYS 32 +#define TASK_FLAGS 4 +#define NEED_RESCHED 20 +#define TSS_FPR0 24 +#define TSS_FPSCR 284 +#define TSS_SMP_FORK_RET 288 +#define TASK_UNION_SIZE 8192 +#define STACK_FRAME_OVERHEAD 16 +#define INT_FRAME_SIZE 192 +#define GPR0 16 +#define GPR1 20 +#define GPR2 24 +#define GPR3 28 +#define GPR4 32 +#define GPR5 36 +#define GPR6 40 +#define GPR7 44 +#define GPR8 48 +#define GPR9 52 +#define GPR10 56 +#define GPR11 60 +#define GPR12 64 +#define GPR13 68 +#define GPR14 72 +#define GPR15 76 +#define GPR16 80 +#define GPR17 84 +#define GPR18 88 +#define GPR19 92 +#define GPR20 96 +#define GPR21 100 +#define GPR22 104 +#define GPR23 108 +#define GPR24 112 +#define GPR25 116 +#define GPR26 120 +#define GPR27 124 +#define GPR28 128 +#define GPR29 132 +#define GPR30 136 +#define GPR31 140 +#define _NIP 144 +#define _MSR 148 +#define _CTR 156 +#define _LINK 160 +#define _CCR 168 +#define _XER 164 +#define _DAR 180 +#define _DSISR 184 +#define ORIG_GPR3 152 +#define RESULT 188 +#define TRAP 176 diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index c1445d393..3aa0534ea 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -1,5 +1,5 @@ /* - * $Id: ppc_htab.c,v 1.21 1998/05/13 22:34:55 cort Exp $ + * $Id: ppc_htab.c,v 1.25 1998/08/26 10:28:26 davem Exp $ * * PowerPC hash table management proc entry. Will show information * about the current hash table and will allow changes to it. @@ -17,6 +17,8 @@ #include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/stat.h> +#include <linux/sysctl.h> +#include <linux/ctype.h> #include <asm/uaccess.h> #include <asm/bitops.h> @@ -31,6 +33,8 @@ static ssize_t ppc_htab_read(struct file * file, char * buf, static ssize_t ppc_htab_write(struct file * file, const char * buffer, size_t count, loff_t *ppos); static long long ppc_htab_lseek(struct file * file, loff_t offset, int orig); +int proc_dol2crvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp); extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; @@ -519,3 +523,147 @@ ppc_htab_lseek(struct file * file, loff_t offset, int orig) return(-EINVAL); } } + +int proc_dol2crvec(ctl_table *table, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int vleft, first=1, len, left, val; + #define TMPBUFLEN 256 + char buf[TMPBUFLEN], *p; + + if ( (_get_PVR() >> 16) != 8) return -EFAULT; + + if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + vleft = table->maxlen / sizeof(int); + left = *lenp; + + for (; left /*&& vleft--*/; first=0) { + if (write) { + while (left) { + char c; + if(get_user(c,(char *) buffer)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + ((char *) buffer)++; + } + if (!left) + break; + len = left; + if (len > TMPBUFLEN-1) + len = TMPBUFLEN-1; + if(copy_from_user(buf, buffer, len)) + return -EFAULT; + buf[len] = 0; + p = buf; + if (*p < '0' || *p > '9') + break; + val = simple_strtoul(p, &p, 0); + len = p-buf; + if ((len < left) && *p && !isspace(*p)) + break; + buffer += len; + left -= len; + _set_L2CR(val); + while ( _get_L2CR() & 0x1 ) + /* wait for invalidate to finish */; + + } else { + p = buf; + if (!first) + *p++ = '\t'; + val = _get_L2CR(); + p += sprintf(p, "%08x: ", val); + p += sprintf(p, " %s", + (val&0x80000000)?"enabled":"disabled"); + p += sprintf(p,",%sparity",(val&0x40000000)?"":"no "); + + switch( (val >> 28) & 0x3 ) + { + case 1: p += sprintf(p,",256Kb"); + break; + case 2: p += sprintf(p,",512Kb"); + break; + case 3: p += sprintf(p,",1M"); + break; + default: p += sprintf(p,",unknown size"); + break; + } + + + switch( (val >> 25) & 0x7 ) + { + case 0: p += sprintf(p,",clock disabled"); + break; + case 1: p += sprintf(p,",+1 clock"); + break; + case 2: p += sprintf(p,",+1.5 clock"); + break; + case 7: + case 3: p += sprintf(p,",reserved clock"); + break; + case 4: p += sprintf(p,",+2 clock"); + break; + case 5: p += sprintf(p,",+2.5 clock"); + break; + case 6: p += sprintf(p,",+3 clock"); + break; + } + + switch( (val >> 23) & 0x2 ) + { + case 0: p += sprintf(p,",flow-through burst SRAM"); + break; + case 1: p += sprintf(p,",reserved SRAM"); + break; + case 2: p += sprintf(p,",pipelined burst SRAM"); + break; + case 3: p += sprintf(p,",pipelined late-write SRAM"); + break; + } + + p += sprintf(p,"%s",(val>>22)?"":",data only"); + p += sprintf(p,"%s",(val>>20)?",ZZ enabled":""); + p += sprintf(p,",%s",(val>>19)?"write-through":"copy-back"); + p += sprintf(p,",%sns hold",(val>>16)?"1.0":"0.5"); + + p += sprintf(p,"\n"); + + len = strlen(buf); + if (len > left) + len = left; + if(copy_to_user(buffer, buf, len)) + return -EFAULT; + left -= len; + buffer += len; + break; + } + } + + if (!write && !first && left) { + if(put_user('\n', (char *) buffer)) + return -EFAULT; + left--, buffer++; + } + if (write) { + p = (char *) buffer; + while (left) { + char c; + if(get_user(c, p++)) + return -EFAULT; + if (!isspace(c)) + break; + left--; + } + } + if (write && first) + return -EINVAL; + *lenp -= left; + filp->f_pos += *lenp; + return 0; +} diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index e869a31dd..ea5f6db0d 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -11,6 +11,7 @@ #include <asm/semaphore.h> #include <asm/processor.h> #include <asm/uaccess.h> +#include <asm/ide.h> #include <asm/io.h> #include <asm/atomic.h> #include <asm/bitops.h> @@ -23,6 +24,7 @@ #include <asm/system.h> #include <asm/pci-bridge.h> #include <asm/irq.h> +#include <asm/feature.h> #define __KERNEL_SYSCALLS__ #include <linux/unistd.h> @@ -56,10 +58,10 @@ EXPORT_SYMBOL(SingleStepException); EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(n_lost_interrupts); EXPORT_SYMBOL(do_lost_interrupts); -EXPORT_SYMBOL(__ppc_bh_counter); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(isa_io_base); EXPORT_SYMBOL(isa_mem_base); @@ -138,11 +140,12 @@ EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(ide_insw); +EXPORT_SYMBOL(ide_outsw); + EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(__kernel_thread); -EXPORT_SYMBOL(__down_interruptible); - EXPORT_SYMBOL(__cli); EXPORT_SYMBOL(__sti); /*EXPORT_SYMBOL(__restore_flags);*/ @@ -154,6 +157,10 @@ EXPORT_SYMBOL(giveup_fpu); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); +#ifndef CONFIG_MACH_SPECIFIC +EXPORT_SYMBOL(_machine); +#endif + EXPORT_SYMBOL(adb_request); EXPORT_SYMBOL(adb_autopoll); EXPORT_SYMBOL(adb_register); @@ -169,10 +176,15 @@ EXPORT_SYMBOL(sleep_notifier_list); EXPORT_SYMBOL(abort); EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); +EXPORT_SYMBOL(find_compatible_devices); EXPORT_SYMBOL(find_path_device); +EXPORT_SYMBOL(find_phandle); EXPORT_SYMBOL(get_property); EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); +EXPORT_SYMBOL(feature_set); +EXPORT_SYMBOL(feature_clear); +EXPORT_SYMBOL(feature_test); EXPORT_SYMBOL(note_scsi_host); EXPORT_SYMBOL(kd_mksound); #ifdef CONFIG_PMAC diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c index 7f45756cb..b7d94d208 100644 --- a/arch/ppc/kernel/prep_pci.c +++ b/arch/ppc/kernel/prep_pci.c @@ -1,5 +1,5 @@ /* - * $Id: prep_pci.c,v 1.20 1998/06/19 16:48:45 cort Exp $ + * $Id: prep_pci.c,v 1.23 1998/10/21 10:52:24 cort Exp $ * PReP pci functions. * Originally by Gary Thomas * rewritten and updated by Cort Dougan (cort@cs.nmt.edu) @@ -234,6 +234,44 @@ static char ibm8xx_pci_IRQ_routes[] __prepdata = { 15, /* Line 4 */ }; +/* + * a 6015 ibm board + * -- Cort + */ +static char ibm6015_pci_IRQ_map[23] __prepdata = { + 0, /* Slot 0 - unused */ + 0, /* Slot 1 - unused */ + 0, /* Slot 2 - unused */ + 0, /* Slot 3 - unused */ + 0, /* Slot 4 - unused */ + 0, /* Slot 5 - unused */ + 0, /* Slot 6 - unused */ + 0, /* Slot 7 - unused */ + 0, /* Slot 8 - unused */ + 0, /* Slot 9 - unused */ + 0, /* Slot 10 - unused */ + 0, /* Slot 11 - */ + 1, /* Slot 12 - SCSI */ + 2, /* Slot 13 - */ + 2, /* Slot 14 - */ + 1, /* Slot 15 - */ + 1, /* Slot 16 - */ + 0, /* Slot 17 - */ + 2, /* Slot 18 - */ + 0, /* Slot 19 - */ + 0, /* Slot 20 - */ + 0, /* Slot 21 - */ + 2, /* Slot 22 - */ +}; +static char ibm6015_pci_IRQ_routes[] __prepdata = { + 0, /* Line 0 - unused */ + 13, /* Line 1 */ + 10, /* Line 2 */ + 15, /* Line 3 */ + 15, /* Line 4 */ +}; + + /* IBM Nobis and 850 */ static char Nobis_pci_IRQ_map[23] __prepdata ={ 0, /* Slot 0 - unused */ @@ -424,6 +462,11 @@ __initfunc(unsigned long route_pci_interrupts(void)) Motherboard_map = Utah_pci_IRQ_map; Motherboard_routes = Utah_pci_IRQ_routes; break; + case 0xE0: /* MTX -- close enough?? to Genesis, so reuse it */ + Motherboard_map_name = "Motorola MTX"; + Motherboard_map = Genesis_pci_IRQ_map; + Motherboard_routes = Genesis_pci_IRQ_routes; + break; case 0x40: /* PowerStack */ default: /* Can't hurt, can it? */ Motherboard_map_name = "Blackhawk (Powerstack)"; @@ -434,16 +477,31 @@ __initfunc(unsigned long route_pci_interrupts(void)) } else if ( _prep_type == _PREP_IBM ) { unsigned char pl_id; - - if (inb(0x0852) == 0xFF) { + /* + * my carolina is 0xf0 + * 6015 has 0xfc + * -- Cort + */ + printk("IBM ID: %08x\n", inb(0x0852)); + switch(inb(0x0852)) + { + case 0xff: Motherboard_map_name = "IBM 850/860 Portable\n"; Motherboard_map = Nobis_pci_IRQ_map; Motherboard_routes = Nobis_pci_IRQ_routes; - } else { + break; + case 0xfc: + Motherboard_map_name = "IBM 6015"; + Motherboard_map = ibm6015_pci_IRQ_map; + Motherboard_routes = ibm6015_pci_IRQ_routes; + break; + default: Motherboard_map_name = "IBM 8xx (Carolina)"; Motherboard_map = ibm8xx_pci_IRQ_map; Motherboard_routes = ibm8xx_pci_IRQ_routes; + break; } + /*printk("Changing IRQ mode\n");*/ pl_id=inb(0x04d0); /*printk("Low mask is %#0x\n", pl_id);*/ diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index 406c18281..e596f9ea5 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -76,26 +76,70 @@ prep_get_cpuinfo(char *buffer) #endif len = sprintf(buffer,"machine\t\t: PReP %s\n",Motherboard_map_name); + - len += sprintf(buffer+len,"L2\t\t: "); - switch(*((unsigned char *)CACHECRBA) & L2CACHE_MASK) + switch ( _prep_type ) { - case L2CACHE_512KB: - len += sprintf(buffer+len,"512Kb\n"); - break; - case L2CACHE_256KB: - len += sprintf(buffer+len,"256Kb\n"); - break; - case L2CACHE_1MB: - len += sprintf(buffer+len,"1MB\n"); + case _PREP_IBM: + if ((*(unsigned char *)0x8000080c) & (1<<6)) + len += sprintf(buffer+len,"Upgrade CPU\n"); + len += sprintf(buffer+len,"L2\t\t: "); + if ((*(unsigned char *)0x8000080c) & (1<<7)) + { + len += sprintf(buffer+len,"not present\n"); + goto no_l2; + } + len += sprintf(buffer+len,"%sKb,", + (((*(unsigned char *)0x8000080d)>>2)&1)?"512":"256"); + len += sprintf(buffer+len,"%sync\n", + ((*(unsigned char *)0x8000080d)>>7) ? "":"a"); break; - case L2CACHE_NONE: - len += sprintf(buffer+len,"none\n"); + case _PREP_Motorola: + len += sprintf(buffer+len,"L2\t\t: "); + switch(*((unsigned char *)CACHECRBA) & L2CACHE_MASK) + { + case L2CACHE_512KB: + len += sprintf(buffer+len,"512Kb"); + break; + case L2CACHE_256KB: + len += sprintf(buffer+len,"256Kb"); + break; + case L2CACHE_1MB: + len += sprintf(buffer+len,"1MB"); + break; + case L2CACHE_NONE: + len += sprintf(buffer+len,"none\n"); + goto no_l2; + break; + default: + len += sprintf(buffer+len, "%x\n", + *((unsigned char *)CACHECRBA)); + } + + len += sprintf(buffer+len,",parity %s", + (*((unsigned char *)CACHECRBA) & L2CACHE_PARITY) ? + "enabled" : "disabled"); + + len += sprintf(buffer+len, " SRAM:"); + + switch ( ((*((unsigned char *)CACHECRBA) & 0xf0) >> 4) & ~(0x3) ) + { + case 1: len += sprintf(buffer+len, + "synchronous,parity,flow-through\n"); + break; + case 2: len += sprintf(buffer+len,"asynchronous,no parity\n"); + break; + case 3: len += sprintf(buffer+len,"asynchronous,parity\n"); + break; + default:len += sprintf(buffer+len, + "synchronous,pipelined,no parity\n"); + break; + } break; - default: - len += sprintf(buffer+len,"%x\n", *((unsigned char *)CACHECRBA)); } - + + +no_l2: if ( res->ResidualLength == 0 ) return len; @@ -111,20 +155,6 @@ prep_get_cpuinfo(char *buffer) } len += sprintf(buffer+len,"\n"); -#if 0 - /* L2 */ - if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */ - { - len += sprintf(buffer+len,"l2\t\t: %dkB %s\n", - ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256, - (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled"); - } - else - { - len += sprintf(buffer+len,"l2\t\t: not present\n"); - } -#endif - return len; } @@ -155,6 +185,9 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) ROOT_DEV = to_kdev_t(0x0801); /* sda1 */ break; } + + /* Enable L2. Assume we don't need to flush -- Cort*/ + *(unsigned char *)(0x8000081c) = *(unsigned char *)(0x8000081c)|3; /* make the serial port the console */ /* strcat(cmd_line,"console=ttyS0,9600n8"); */ @@ -163,7 +196,7 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) sprintf(cmd_line,"%s console=tty0 console=ttyS0,9600n8", cmd_line); printk("Boot arguments: %s\n", cmd_line); -#ifdef CONFIG_CS4232 +#ifdef CONFIG_SOUND_CS4232 /* * setup proper values for the cs4232 driver so we don't have * to recompile for the motorola or ibm workstations sound systems. @@ -200,8 +233,7 @@ prep_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p)) } } } -#endif /* CONFIG_CS4232 */ - +#endif /* CONFIG_SOUND_CS4232 */ /*print_residual_device_info();*/ request_region(0x20,0x20,"pic1"); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 9cf88c8a4..5ea55cee9 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -163,14 +163,19 @@ switch_to(struct task_struct *prev, struct task_struct *new) #endif #ifdef SHOW_TASK_SWITCHES - printk("%s/%d -> %s/%d NIP %08lx cpu %d sfr %d lock %x\n", + printk("%s/%d -> %s/%d NIP %08lx cpu %d lock %x root %x/%x\n", prev->comm,prev->pid, new->comm,new->pid,new->tss.regs->nip,new->processor, - new->tss.smp_fork_ret,scheduler_lock.lock); + scheduler_lock.lock,new->fs->root,prev->fs->root); #endif #ifdef __SMP__ /* avoid complexity of lazy save/restore of fpu - * by just saving it every time we switch out -- Cort + * by just saving it every time we switch out if + * this task used the fpu during the last quantum. + * + * If it tries to use the fpu again, it'll trap and + * reload its fp regs. + * -- Cort */ if ( prev->tss.regs->msr & MSR_FP ) smp_giveup_fpu(prev); @@ -349,6 +354,9 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp) regs->gpr[1] = sp; regs->msr = MSR_USER; shove_aux_table(sp); + if (last_task_used_math == current) + last_task_used_math = 0; + current->tss.fpscr = 0; } asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, @@ -380,6 +388,7 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, { int res; + lock_kernel(); res = do_fork(SIGCHLD, regs->gpr[1], regs); /* only parent returns here */ @@ -401,18 +410,23 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, { int error; char * filename; - lock_kernel(); filename = getname((char *) a0); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; +#ifdef __SMP__ + if ( regs->msr & MSR_FP ) + smp_giveup_fpu(current); +#else if ( last_task_used_math == current ) - last_task_used_math = NULL; + giveup_fpu(); +#endif error = do_execve(filename, (char **) a1, (char **) a2, regs); putname(filename); out: unlock_kernel(); + return error; } @@ -446,7 +460,7 @@ __initfunc(int ll_printk(const char *fmt, ...)) int i; va_start(args, fmt); - i=sprintf(buf,fmt,args); + i=vsprintf(buf,fmt,args); ll_puts(buf); va_end(args); return i; @@ -455,6 +469,19 @@ __initfunc(int ll_printk(const char *fmt, ...)) int lines = 24, cols = 80; int orig_x = 0, orig_y = 0; +void puthex(unsigned long val) +{ + unsigned char buf[10]; + int i; + for (i = 7; i >= 0; i--) + { + buf[i] = "0123456789ABCDEF"[val & 0x0F]; + val >>= 4; + } + buf[8] = '\0'; + prom_print(buf); +} + __initfunc(void ll_puts(const char *s)) { int x,y; diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 047d590ed..da9d7a04c 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -1,5 +1,5 @@ /* - * $Id: prom.c,v 1.32 1998/07/28 20:28:46 geert Exp $ + * $Id: prom.c,v 1.46 1998/11/11 03:55:09 paulus Exp $ * * Procedures for interfacing to the Open Firmware PROM on * Power Macintosh computers. @@ -15,11 +15,14 @@ #include <linux/kernel.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/version.h> #include <asm/prom.h> #include <asm/page.h> #include <asm/processor.h> #include <asm/irq.h> #include <asm/io.h> +#include <asm/smp.h> +#include <asm/bootx.h> /* * Properties whose value is longer than this get excluded from our @@ -60,6 +63,13 @@ struct isa_reg_property { unsigned size; }; +struct pci_intr_map { + struct pci_address addr; + unsigned dunno; + phandle int_ctrler; + unsigned intr; +}; + typedef unsigned long interpret_func(struct device_node *, unsigned long); static interpret_func interpret_pci_props; static interpret_func interpret_dbdma_props; @@ -67,8 +77,12 @@ static interpret_func interpret_isa_props; static interpret_func interpret_macio_props; static interpret_func interpret_root_props; +#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ +#define FB_MAX 8 +#endif char *prom_display_paths[FB_MAX] __initdata = { 0, }; unsigned int prom_num_displays = 0; +char *of_stdout_device = 0; prom_entry prom = 0; ihandle prom_chosen = 0, prom_stdout = 0; @@ -84,20 +98,49 @@ unsigned int old_rtas = 0; static struct device_node *allnodes = 0; +static void clearscreen(void); + +#ifdef CONFIG_BOOTX_TEXT + +static void drawchar(char c); +static void drawstring(const char *c); +static void scrollscreen(void); + +static void draw_byte(unsigned char c, long locX, long locY); +static void draw_byte_32(unsigned char *bits, unsigned long *base); +static void draw_byte_16(unsigned char *bits, unsigned long *base); +static void draw_byte_8(unsigned char *bits, unsigned long *base); + +static long g_loc_X; +static long g_loc_Y; +static long g_max_loc_X; +static long g_max_loc_Y; + +#define cmapsz (16*256) + +static unsigned char vga_font[cmapsz]; + +#endif + + static void *call_prom(const char *service, int nargs, int nret, ...); - void prom_print(const char *msg); static void prom_exit(void); static unsigned long copy_device_tree(unsigned long, unsigned long); static unsigned long inspect_node(phandle, struct device_node *, unsigned long, unsigned long, struct device_node ***); static unsigned long finish_node(struct device_node *, unsigned long, interpret_func *); +static void relocate_nodes(void); static unsigned long check_display(unsigned long); static int prom_next_node(phandle *); +static void *early_get_property(unsigned long, unsigned long, char *); extern void enter_rtas(void *); extern unsigned long reloc_offset(void); +extern char cmd_line[512]; /* XXX */ +boot_infos_t *boot_infos = 0; /* init it so it's in data segment not bss */ + /* * prom_init() is called very early on, before the kernel text * and data have been mapped to KERNELBASE. At this point the code @@ -124,7 +167,7 @@ extern unsigned long reloc_offset(void); #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) -__openfirmware +__init static void prom_exit() { @@ -139,7 +182,7 @@ prom_exit() ; } -__openfirmware +__init void prom_enter(void) { @@ -152,7 +195,7 @@ prom_enter(void) RELOC(prom)(&args); } -__openfirmware +__init static void * call_prom(const char *service, int nargs, int nret, ...) { @@ -174,13 +217,23 @@ call_prom(const char *service, int nargs, int nret, ...) return prom_args.args[nargs]; } -__openfirmware +__init void prom_print(const char *msg) { const char *p, *q; unsigned long offset = reloc_offset(); + if (RELOC(prom_stdout) == 0) + { +#ifdef CONFIG_BOOTX_TEXT + if (RELOC(boot_infos) != 0) + drawstring(msg); +#endif + return; + } + + for (p = msg; *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n'; ++q) ; @@ -199,7 +252,7 @@ prom_print(const char *msg) * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. */ -__openfirmware +__init void prom_init(int r3, int r4, prom_entry pp) { @@ -208,13 +261,59 @@ prom_init(int r3, int r4, prom_entry pp) unsigned long offset = reloc_offset(); int l; char *p, *d; + + /* check if we're apus, return if we are */ + if ( r3 == 0x61707573 ) + return; + + /* If we came here from BootX, clear the screen, + * set up some pointers and return. */ + if (r3 == 0x426f6f58 && pp == NULL) { + boot_infos_t *bi = (boot_infos_t *) r4; + unsigned long space; + unsigned long ptr, x; + char *model; + + RELOC(boot_infos) = PTRUNRELOC(bi); + + clearscreen(); + +#ifdef CONFIG_BOOTX_TEXT + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y) = 0; + RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8; + RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16; + prom_print(RELOC("Welcome to Linux, kernel " UTS_RELEASE " booting...\n")); +#endif + + /* + * XXX If this is an iMac, turn off the USB controller. + */ + model = (char *) early_get_property + (r4 + bi->deviceTreeOffset, 4, RELOC("model")); + if (model && strcmp(model, RELOC("iMac,1")) == 0) { + out_le32((unsigned *)0x80880008, 1); /* XXX */ + } + + space = bi->deviceTreeOffset + bi->deviceTreeSize; + if (bi->ramDisk) + space = bi->ramDisk + bi->ramDiskSize; + RELOC(klimit) = PTRUNRELOC((char *) bi + space); + + /* + * Touch each page to make sure the PTEs for them + * are in the hash table - the aim is to try to avoid + * getting DSI exceptions while copying the kernel image. + */ + for (ptr = (KERNELBASE + offset) & PAGE_MASK; + ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) + x = *(volatile unsigned long *)ptr; - /* check if we're prep, return if we are */ - if ( *(unsigned long *)(0) == 0xdeadc0de ) return; + } - /* check if we're apus, return if we are */ - if ( r3 == 0x61707573 ) + /* check if we're prep, return if we are */ + if ( *(unsigned long *)(0) == 0xdeadc0de ) return; /* First get a handle for the stdout device */ @@ -228,9 +327,16 @@ prom_init(int r3, int r4, prom_entry pp) sizeof(prom_stdout)) <= 0) prom_exit(); - /* Get the boot device and translate it to a full OF pathname. */ + /* Get the full OF pathname of the stdout device */ mem = (unsigned long) RELOC(klimit) + offset; p = (char *) mem; + memset(p, 0, 256); + call_prom(RELOC("instance-to-path"), 3, 1, RELOC(prom_stdout), p, 255); + RELOC(of_stdout_device) = PTRUNRELOC(p); + mem += strlen(p) + 1; + + /* Get the boot device and translate it to a full OF pathname. */ + p = (char *) mem; l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen), RELOC("bootpath"), p, 1<<20); if (l > 0) { @@ -297,14 +403,15 @@ prom_init(int r3, int r4, prom_entry pp) * So we check whether we will need to open the display, * and if so, open it now. */ -__openfirmware +__init static unsigned long check_display(unsigned long mem) { phandle node; ihandle ih; + int i; unsigned long offset = reloc_offset(); - char type[16], name[16], *path; + char type[16], *path; for (node = 0; prom_next_node(&node); ) { type[0] = 0; @@ -323,27 +430,30 @@ check_display(unsigned long mem) ih = call_prom(RELOC("open"), 1, 1, path); if (ih == 0 || ih == (ihandle) -1) { prom_print(RELOC("... failed\n")); - /* platinum kludge. platinum is a valid display, - * but not handled by OF. Make sure prom_num_display - * is incremented anyway - */ - call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"), - name, sizeof(name)); - if (strncmp(name, RELOC("platinum"), 8)) - continue; - } else { - prom_print(RELOC("... ok\n")); + continue; } + prom_print(RELOC("... ok\n")); + + /* + * If this display is the device that OF is using for stdout, + * move it to the front of the list. + */ mem += strlen(path) + 1; - RELOC(prom_display_paths[RELOC(prom_num_displays)++]) - = PTRUNRELOC(path); + i = RELOC(prom_num_displays)++; + if (RELOC(of_stdout_device) != 0 && i > 0 + && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) { + for (; i > 0; --i) + RELOC(prom_display_paths[i]) + = RELOC(prom_display_paths[i-1]); + } + RELOC(prom_display_paths[i]) = PTRUNRELOC(path); if (RELOC(prom_num_displays) >= FB_MAX) break; } return ALIGN(mem); } -__openfirmware +__init static int prom_next_node(phandle *nodep) { @@ -366,7 +476,7 @@ prom_next_node(phandle *nodep) /* * Make a copy of the device tree from the PROM. */ -__openfirmware +__init static unsigned long copy_device_tree(unsigned long mem_start, unsigned long mem_end) { @@ -387,7 +497,7 @@ copy_device_tree(unsigned long mem_start, unsigned long mem_end) return new_start; } -__openfirmware +__init static unsigned long inspect_node(phandle node, struct device_node *dad, unsigned long mem_start, unsigned long mem_end, @@ -472,19 +582,41 @@ inspect_node(phandle node, struct device_node *dad, * It traverses the device tree and fills in the name, type, * {n_}addrs and {n_}intrs fields of each node. */ -__openfirmware +__init void finish_device_tree(void) { unsigned long mem = (unsigned long) klimit; + if (boot_infos) + relocate_nodes(); mem = finish_node(allnodes, mem, NULL); printk(KERN_INFO "device tree used %lu bytes\n", mem - (unsigned long) allnodes); klimit = (char *) mem; } -__openfirmware +/* + * early_get_property is used to access the device tree image prepared + * by BootX very early on, before the pointers in it have been relocated. + */ +__init void * +early_get_property(unsigned long base, unsigned long node, char *prop) +{ + struct device_node *np = (struct device_node *)(base + node); + struct property *pp; + + for (pp = np->properties; pp != 0; pp = pp->next) { + pp = (struct property *) (base + (unsigned long)pp); + if (strcmp((char *)((unsigned long)pp->name + base), + prop) == 0) { + return (void *)((unsigned long)pp->value + base); + } + } + return 0; +} + +__init static unsigned long finish_node(struct device_node *np, unsigned long mem_start, interpret_func *ifunc) @@ -505,31 +637,79 @@ finish_node(struct device_node *np, unsigned long mem_start, ifunc = NULL; else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) ifunc = interpret_pci_props; - else if (!strcmp(np->type, "dbdma") - || (ifunc == interpret_dbdma_props - && (!strcmp(np->type, "escc") - || !strcmp(np->type, "media-bay")))) + else if (!strcmp(np->type, "dbdma")) ifunc = interpret_dbdma_props; - else if (!strcmp(np->type, "mac-io")) + else if (!strcmp(np->type, "mac-io") + || ifunc == interpret_macio_props) ifunc = interpret_macio_props; else if (!strcmp(np->type, "isa")) ifunc = interpret_isa_props; - else + else if (!((ifunc == interpret_dbdma_props + || ifunc == interpret_macio_props) + && (!strcmp(np->type, "escc") + || !strcmp(np->type, "media-bay")))) ifunc = NULL; + /* if we were booted from BootX, convert the full name */ + if (boot_infos + && strncmp(np->full_name, "Devices:device-tree", 19) == 0) { + if (np->full_name[19] == 0) { + strcpy(np->full_name, "/"); + } else if (np->full_name[19] == ':') { + char *p = np->full_name + 19; + np->full_name = p; + for (; *p; ++p) + if (*p == ':') + *p = '/'; + } + } + for (child = np->child; child != NULL; child = child->sibling) mem_start = finish_node(child, mem_start, ifunc); return mem_start; } -__openfirmware +/* + * When BootX makes a copy of the device tree from the MacOS + * Name Registry, it is in the format we use but all of the pointers + * are offsets from the start of the tree. + * This procedure updates the pointers. + */ +__init +static void relocate_nodes(void) +{ + unsigned long base; + struct device_node *np; + struct property *pp; + +#define ADDBASE(x) (x = (x)? ((typeof (x))((unsigned long)(x) + base)): 0) + + base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset; + allnodes = (struct device_node *)(base + 4); + for (np = allnodes; np != 0; np = np->allnext) { + ADDBASE(np->full_name); + ADDBASE(np->properties); + ADDBASE(np->parent); + ADDBASE(np->child); + ADDBASE(np->sibling); + ADDBASE(np->allnext); + for (pp = np->properties; pp != 0; pp = pp->next) { + ADDBASE(pp->name); + ADDBASE(pp->value); + ADDBASE(pp->next); + } + } +} + +__init static unsigned long interpret_pci_props(struct device_node *np, unsigned long mem_start) { struct address_range *adr; struct pci_reg_property *pci_addrs; - int i, l, *ip; + int i, l, *ip, ml; + struct pci_intr_map *imp; pci_addrs = (struct pci_reg_property *) get_property(np, "assigned-addresses", &l); @@ -548,6 +728,30 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start) mem_start += i * sizeof(struct address_range); } + /* + * If the pci host bridge has an interrupt-map property, + * look for our node in it. + */ + if (np->parent != 0 && pci_addrs != 0 + && (imp = (struct pci_intr_map *) + get_property(np->parent, "interrupt-map", &ml)) != 0 + && (ip = (int *) get_property(np, "interrupts", &l)) != 0) { + unsigned int busdevfn = pci_addrs[0].addr.a_hi & 0xffff00; + np->n_intrs = 0; + np->intrs = (struct interrupt_info *) mem_start; + for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) { + if (imp[i].addr.a_hi == busdevfn) { + np->intrs[np->n_intrs].line = imp[i].intr; + np->intrs[np->n_intrs].sense = 0; + ++np->n_intrs; + } + } + if (np->n_intrs == 0) + np->intrs = 0; + mem_start += np->n_intrs * sizeof(struct interrupt_info); + return mem_start; + } + ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip == 0) ip = (int *) get_property(np, "interrupts", &l); @@ -564,7 +768,7 @@ interpret_pci_props(struct device_node *np, unsigned long mem_start) return mem_start; } -__openfirmware +__init static unsigned long interpret_dbdma_props(struct device_node *np, unsigned long mem_start) { @@ -613,7 +817,7 @@ interpret_dbdma_props(struct device_node *np, unsigned long mem_start) return mem_start; } -__openfirmware +__init static unsigned long interpret_macio_props(struct device_node *np, unsigned long mem_start) { @@ -651,18 +855,28 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start) ip = (int *) get_property(np, "AAPL,interrupts", &l); if (ip != 0) { np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = l / (2 * sizeof(int)); - mem_start += np->n_intrs * sizeof(struct interrupt_info); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = openpic_to_irq(*ip++); - np->intrs[i].sense = *ip++; + if (_machine == _MACH_Pmac) { + /* for the iMac */ + np->n_intrs = l / sizeof(int); + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = *ip++; + np->intrs[i].sense = 0; + } + } else { + /* CHRP machines */ + np->n_intrs = l / (2 * sizeof(int)); + for (i = 0; i < np->n_intrs; ++i) { + np->intrs[i].line = openpic_to_irq(*ip++); + np->intrs[i].sense = *ip++; + } } + mem_start += np->n_intrs * sizeof(struct interrupt_info); } return mem_start; } -__openfirmware +__init static unsigned long interpret_isa_props(struct device_node *np, unsigned long mem_start) { @@ -700,7 +914,7 @@ interpret_isa_props(struct device_node *np, unsigned long mem_start) return mem_start; } -__openfirmware +__init static unsigned long interpret_root_props(struct device_node *np, unsigned long mem_start) { @@ -779,6 +993,30 @@ find_type_devices(const char *type) return head; } +/* Checks if the given "compat" string matches one of the strings in + * the device's "compatible" property + */ +__openfirmware +int +device_is_compatible(struct device_node *device, const char *compat) +{ + const char* cp; + int cplen, l; + + cp = (char *) get_property(device, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strcasecmp(cp, compat) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + /* * Construct and return a list of the device_nodes with a given type * and compatible property. @@ -788,15 +1026,13 @@ struct device_node * find_compatible_devices(const char *type, const char *compat) { struct device_node *head, **prevp, *np; - const char *cp; prevp = &head; for (np = allnodes; np != 0; np = np->allnext) { if (type != NULL && !(np->type != 0 && strcasecmp(np->type, type) == 0)) continue; - cp = (char *) get_property(np, "compatible", NULL); - if (cp != NULL && strcasecmp(cp, compat) == 0) { + if (device_is_compatible(np, compat)) { *prevp = np; prevp = &np->next; } @@ -854,6 +1090,7 @@ get_property(struct device_node *np, const char *name, int *lenp) return 0; } +#if 0 __openfirmware void print_properties(struct device_node *np) @@ -904,7 +1141,9 @@ print_properties(struct device_node *np) } } } +#endif +/* this can be called after setup -- Cort */ __openfirmware int call_rtas(const char *service, int nargs, int nret, @@ -941,7 +1180,7 @@ call_rtas(const char *service, int nargs, int nret, return u.words[nargs+3]; } -__openfirmware +__init void abort() { @@ -951,3 +1190,563 @@ abort() #endif prom_exit(); } + +#define CALC_BASE(y) (bi->dispDeviceBase + bi->dispDeviceRect[0] * \ + (bi->dispDeviceDepth >> 3) + bi->dispDeviceRowBytes * (y)) + +__init +static void +clearscreen(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned long *base = (unsigned long *)CALC_BASE(0); + unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * + (bi->dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) + { + unsigned long *ptr = base; + for(j=width; j; --j) + *(ptr++) = 0; + base += (bi->dispDeviceRowBytes >> 2); + } +} + +#ifdef CONFIG_BOOTX_TEXT + +__init +static void +scrollscreen(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned long *src = (unsigned long *)CALC_BASE(16); + unsigned long *dst = (unsigned long *)CALC_BASE(0); + unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * + (bi->dispDeviceDepth >> 3)) >> 2; + int i,j; + + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) + { + unsigned long *src_ptr = src; + unsigned long *dst_ptr = dst; + for(j=width; j; --j) + *(dst_ptr++) = *(src_ptr++); + src += (bi->dispDeviceRowBytes >> 2); + dst += (bi->dispDeviceRowBytes >> 2); + } + for (i=0; i<16; i++) + { + unsigned long *dst_ptr = dst; + for(j=width; j; --j) + *(dst_ptr++) = 0; + dst += (bi->dispDeviceRowBytes >> 2); + } +} + +__init +static void +drawchar(char c) +{ + unsigned long offset = reloc_offset(); + + switch(c) + { + case '\r': RELOC(g_loc_X) = 0; break; + case '\n': RELOC(g_loc_X) = 0; RELOC(g_loc_Y)++; break; + default: + draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y)); + if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) + { + RELOC(g_loc_X) = 0; + RELOC(g_loc_Y)++; + } + } + while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) + { + scrollscreen(); + RELOC(g_loc_Y)--; + } +} + +__init +static void +drawstring(const char *c) +{ + while(*c) + drawchar(*(c++)); +} + +__init +static void +draw_byte(unsigned char c, long locX, long locY) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + unsigned char *base = bi->dispDeviceBase + + (bi->dispDeviceRowBytes * ((locY * 16) + bi->dispDeviceRect[1])) + + (bi->dispDeviceDepth >> 3) * ((locX * 8) + bi->dispDeviceRect[0]); + unsigned char *font = &RELOC(vga_font)[((unsigned long)c) * 16]; + + switch(bi->dispDeviceDepth) + { + case 32: + draw_byte_32(font, (unsigned long *)base); + break; + case 16: + draw_byte_16(font, (unsigned long *)base); + break; + case 8: + draw_byte_8(font, (unsigned long *)base); + break; + default: + break; + } +} + +__init +static unsigned long expand_bits_8[16] = { + 0x00000000, + 0x000000ff, + 0x0000ff00, + 0x0000ffff, + 0x00ff0000, + 0x00ff00ff, + 0x00ffff00, + 0x00ffffff, + 0xff000000, + 0xff0000ff, + 0xff00ff00, + 0xff00ffff, + 0xffff0000, + 0xffff00ff, + 0xffffff00, + 0xffffffff +}; + +__init +static unsigned long expand_bits_16[4] = { + 0x00000000, + 0x0000ffff, + 0xffff0000, + 0xffffffff +}; + + +__init +static void +draw_byte_32(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0xFFFFFFFFUL; + int bg = 0x00000000UL; + + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (-(bits >> 7) & fg) ^ bg; + base[1] = (-((bits >> 6) & 1) & fg) ^ bg; + base[2] = (-((bits >> 5) & 1) & fg) ^ bg; + base[3] = (-((bits >> 4) & 1) & fg) ^ bg; + base[4] = (-((bits >> 3) & 1) & fg) ^ bg; + base[5] = (-((bits >> 2) & 1) & fg) ^ bg; + base[6] = (-((bits >> 1) & 1) & fg) ^ bg; + base[7] = (-(bits & 1) & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static void +draw_byte_16(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0xFFFFFFFFUL; + int bg = 0x00000000UL; + unsigned long *eb = RELOC(expand_bits_16); + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (eb[bits >> 6] & fg) ^ bg; + base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; + base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; + base[3] = (eb[bits & 3] & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static void +draw_byte_8(unsigned char *font, unsigned long *base) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(boot_infos)); + int l, bits; + int fg = 0x0F0F0F0FUL; + int bg = 0x00000000UL; + unsigned long *eb = RELOC(expand_bits_8); + + for (l = 0; l < 16; ++l) + { + bits = *font++; + base[0] = (eb[bits >> 4] & fg) ^ bg; + base[1] = (eb[bits & 0xf] & fg) ^ bg; + base = (unsigned long *) ((char *)base + bi->dispDeviceRowBytes); + } +} + +__init +static unsigned char vga_font[cmapsz] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, +0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, +0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, +0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, +0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, +0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, +0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, +0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, +0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, +0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, +0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, +0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, +0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, +0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, +0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, +0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, +0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, +0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, +0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, +0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, +0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, +0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, +0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, +0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, +0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, +0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, +0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, +0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, +0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, +0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, +0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, +0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, +0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, +0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, +0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, +0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, +0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, +0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, +0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, +0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, +0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, +0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, +0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, +0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, +0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, +0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, +0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, +0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, +0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, +0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, +0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, +0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, +0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, +0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, +0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, +0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, +0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, +0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, +0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, +0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, +0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, +0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, +0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, +0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, +0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, +0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, +0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, +0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, +0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, +0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, +0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +}; + +#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c index b2e198f68..83333f660 100644 --- a/arch/ppc/kernel/residual.c +++ b/arch/ppc/kernel/residual.c @@ -1,5 +1,5 @@ /* - * $Id: residual.c,v 1.10 1998/07/09 22:23:18 cort Exp $ + * $Id: residual.c,v 1.14 1998/10/11 17:38:10 cort Exp $ * * Code to deal with the PReP residual data. * @@ -23,7 +23,6 @@ #include <asm/pnp.h> #include <asm/byteorder.h> -#if 0 #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -50,7 +49,7 @@ #include <asm/ide.h> -const char * PnP_BASE_TYPES[]= { +const char * PnP_BASE_TYPES[] __initdata = { "Reserved", "MassStorageDevice", "NetworkInterfaceController", @@ -66,7 +65,7 @@ const char * PnP_BASE_TYPES[]= { /* Device Sub Type Codes */ -const unsigned char * PnP_SUB_TYPES[] = { +const unsigned char * PnP_SUB_TYPES[] __initdata = { "\001\000SCSIController", "\001\001IDEController", "\001\002FloppyController", @@ -123,7 +122,7 @@ const unsigned char * PnP_SUB_TYPES[] = { /* Device Interface Type Codes */ -const unsigned char * PnP_INTERFACES[]= { +const unsigned char * PnP_INTERFACES[] __initdata = { "\000\000\000General", "\001\000\000GeneralSCSI", "\001\001\000GeneralIDE", @@ -241,7 +240,7 @@ const unsigned char * PnP_INTERFACES[]= { NULL }; -static const unsigned char *PnP_SUB_TYPE_STR(unsigned char BaseType, +static const unsigned char __init *PnP_SUB_TYPE_STR(unsigned char BaseType, unsigned char SubType) { const unsigned char ** s=PnP_SUB_TYPES; while (*s && !((*s)[0]==BaseType @@ -250,7 +249,7 @@ static const unsigned char *PnP_SUB_TYPE_STR(unsigned char BaseType, else return("Unknown !"); }; -static const unsigned char *PnP_INTERFACE_STR(unsigned char BaseType, +static const unsigned char __init *PnP_INTERFACE_STR(unsigned char BaseType, unsigned char SubType, unsigned char Interface) { const unsigned char ** s=PnP_INTERFACES; @@ -261,7 +260,7 @@ static const unsigned char *PnP_INTERFACE_STR(unsigned char BaseType, else return NULL; }; -static void printsmallvendor(PnP_TAG_PACKET *pkt, int size) { +static void __init printsmallvendor(PnP_TAG_PACKET *pkt, int size) { int i, c; char decomp[4]; #define p pkt->S14_Pack.S14_Data.S14_PPCPack @@ -286,7 +285,7 @@ static void printsmallvendor(PnP_TAG_PACKET *pkt, int size) { #undef p } -static void printsmallpacket(PnP_TAG_PACKET * pkt, int size) { +static void __init printsmallpacket(PnP_TAG_PACKET * pkt, int size) { static const unsigned char * intlevel[] = {"high", "low"}; static const unsigned char * intsense[] = {"edge", "level"}; @@ -353,7 +352,7 @@ static void printsmallpacket(PnP_TAG_PACKET * pkt, int size) { } } -static void printlargevendor(PnP_TAG_PACKET * pkt, int size) { +static void __init printlargevendor(PnP_TAG_PACKET * pkt, int size) { static const unsigned char * addrtype[] = {"I/O", "Memory", "System"}; static const unsigned char * inttype[] = {"8259", "MPIC", "RS6k BUID %d"}; static const unsigned char * convtype[] = {"Bus Memory", "Bus I/O", "DMA"}; @@ -463,9 +462,7 @@ static void printlargevendor(PnP_TAG_PACKET * pkt, int size) { } } -static void printlargepacket(PnP_TAG_PACKET * pkt, int size) { - int i; - +static void __init printlargepacket(PnP_TAG_PACKET * pkt, int size) { switch (tag_large_item_name(pkt->S1_Pack.Tag)) { case LargeVendorItem: printlargevendor(pkt, size); @@ -476,8 +473,7 @@ static void printlargepacket(PnP_TAG_PACKET * pkt, int size) { break; } } -static void printpackets(PnP_TAG_PACKET * pkt, const char * cat) { - PnP_TAG_PACKET tmp; +static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) { if (pkt->S1_Pack.Tag== END_TAG) { printk(" No packets describing %s resources.\n", cat); return; @@ -498,13 +494,11 @@ static void printpackets(PnP_TAG_PACKET * pkt, const char * cat) { } while (pkt->S1_Pack.Tag != END_TAG); } -void print_residual_device_info(void) +void __init print_residual_device_info(void) { int i; - union _PnP_TAG_PACKET *pkt; PPC_DEVICE *dev; #define did dev->DeviceId -return; /* make sure we have residual data first */ if ( res->ResidualLength == 0 ) @@ -552,18 +546,24 @@ return; PnP_BASE_TYPES[did.BaseType], PnP_SUB_TYPE_STR(did.BaseType,did.SubType), s); - printpackets( (union _PnP_TAG_PACKET *) - &res->DevicePnPHeap[dev->AllocatedOffset], "allocated"); - printpackets( (union _PnP_TAG_PACKET *) - &res->DevicePnPHeap[dev->PossibleOffset], "possible"); - printpackets( (union _PnP_TAG_PACKET *) - &res->DevicePnPHeap[dev->CompatibleOffset], "compatible"); + if ( dev->AllocatedOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->AllocatedOffset], + "allocated"); + if ( dev->PossibleOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->PossibleOffset], + "possible"); + if ( dev->CompatibleOffset ) + printpackets( (union _PnP_TAG_PACKET *) + &res->DevicePnPHeap[dev->CompatibleOffset], + "compatible"); } } - -static void printVPD(void) { +#if 0 +static void __init printVPD(void) { #define vpd res->VitalProductData int ps=vpd.PageSize, i, j; static const char* Usage[]={ @@ -628,7 +628,6 @@ static void printVPD(void) { /* * Spit out some info about residual data */ -#if 0 void print_residual_device_info(void) { int i; @@ -728,7 +727,6 @@ void print_residual_device_info(void) } #endif -#endif /* 0 */ /* Returns the device index in the residual data, any of the search items may be set as -1 for wildcard, DevID number field (second halfword) is big endian ! @@ -765,7 +763,7 @@ in this rarely used area we unencode and compare */ little endian in the heap, so we use two parameters to avoid writing two very similar functions */ -static int same_DevID(unsigned short vendor, +static int __init same_DevID(unsigned short vendor, unsigned short Number, char * str) { @@ -781,7 +779,7 @@ static int same_DevID(unsigned short vendor, return 0; } -PPC_DEVICE *residual_find_device(unsigned long BusMask, +PPC_DEVICE __init *residual_find_device(unsigned long BusMask, unsigned char * DevID, int BaseType, int SubType, @@ -804,6 +802,28 @@ PPC_DEVICE *residual_find_device(unsigned long BusMask, return 0; } +PPC_DEVICE __init *residual_find_device_id(unsigned long BusMask, + unsigned short DevID, + int BaseType, + int SubType, + int Interface, + int n) +{ + int i; + if ( !res->ResidualLength ) return NULL; + for (i=0; i<res->ActualNumDevices; i++) { +#define Dev res->Devices[i].DeviceId + if ( (Dev.BusId&BusMask) && + (BaseType==-1 || Dev.BaseType==BaseType) && + (SubType==-1 || Dev.SubType==SubType) && + (Interface==-1 || Dev.Interface==Interface) && + (DevID==0xffff || (Dev.DevId&0xffff) == DevID) && + !(n--) ) return res->Devices+i; +#undef Dev + } + return 0; +} + PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, unsigned packet_tag, int n) @@ -823,7 +843,7 @@ PnP_TAG_PACKET *PnP_find_packet(unsigned char *p, return 0; /* not found */ } -PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p, +PnP_TAG_PACKET __init *PnP_find_small_vendor_packet(unsigned char *p, unsigned packet_type, int n) { @@ -837,7 +857,7 @@ PnP_TAG_PACKET *PnP_find_small_vendor_packet(unsigned char *p, return 0; /* not found */ } -PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p, +PnP_TAG_PACKET __init *PnP_find_large_vendor_packet(unsigned char *p, unsigned packet_type, int n) { @@ -850,4 +870,3 @@ PnP_TAG_PACKET *PnP_find_large_vendor_packet(unsigned char *p, }; return 0; /* not found */ } - diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 7ea277866..706c1dde2 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -1,9 +1,10 @@ /* - * $Id: setup.c,v 1.95 1998/07/20 19:03:47 geert Exp $ + * $Id: setup.c,v 1.117 1998/11/09 19:55:53 geert Exp $ * Common prep/pmac/chrp boot and setup code. */ #include <linux/config.h> +#include <linux/module.h> #include <linux/string.h> #include <linux/sched.h> #include <linux/init.h> @@ -23,15 +24,22 @@ #include <asm/bootinfo.h> #include <asm/setup.h> #include <asm/amigappc.h> +#include <asm/smp.h> #ifdef CONFIG_MBX #include <asm/mbx.h> #endif +#include <asm/bootx.h> /* APUS defs */ extern unsigned long m68k_machtype; -extern struct mem_info ramdisk; extern int parse_bootinfo(const struct bi_record *); extern char _end[]; +#ifdef CONFIG_APUS +struct mem_info ramdisk; +unsigned long isa_io_base; +unsigned long isa_mem_base; +unsigned long pci_dram_offset; +#endif /* END APUS defs */ extern char cmd_line[512]; @@ -52,6 +60,8 @@ RESIDUAL *res = (RESIDUAL *)&__res; int _prep_type; +extern boot_infos_t *boot_infos; + /* * Perhaps we can put the pmac screen_info[] here * on pmac as well so we don't need the ifdef's. @@ -122,9 +132,7 @@ void machine_restart(char *cmd) cuda_poll(); break; case ADB_VIAPMU: - pmu_request(&req, NULL, 1, PMU_RESET); - for (;;) - pmu_poll(); + pmu_restart(); break; default: } @@ -197,10 +205,7 @@ void machine_power_off(void) cuda_poll(); break; case ADB_VIAPMU: - pmu_request(&req, NULL, 5, PMU_SHUTDOWN, - 'M', 'A', 'T', 'T'); - for (;;) - pmu_poll(); + pmu_shutdown(); break; default: } @@ -217,10 +222,7 @@ void machine_power_off(void) case _MACH_prep: machine_restart(NULL); case _MACH_apus: -#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF) - apm_set_power_state(APM_STATE_OFF); for (;;); -#endif } for (;;); #else /* CONFIG_MBX */ @@ -239,14 +241,16 @@ void machine_halt(void) } -#ifdef CONFIG_BLK_DEV_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) { #if !defined(CONFIG_MBX) && !defined(CONFIG_APUS) switch (_machine) { +#if defined(CONFIG_BLK_DEV_IDE_PMAC) case _MACH_Pmac: - pmac_ide_init_hwif_ports(p,base,irq); + pmac_ide_init_hwif_ports(p,base,irq); break; +#endif case _MACH_chrp: chrp_ide_init_hwif_ports(p,base,irq); break; @@ -256,72 +260,36 @@ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq) } #endif } +EXPORT_SYMBOL(ide_init_hwif_ports); #endif unsigned long cpu_temp(void) { -#if 0 - unsigned long i, temp, thrm1, dir; - int sanity; + unsigned char thres = 0; - /* - * setup thrm3 - need to give TAU at least 20us - * to do the compare so assume a 300MHz clock. - * We need 300*20 ticks then. - * -- Cort - */ - asm("mtspr 1020, %1\n\t" - "mtspr 1021, %1\n\t" - "mtspr 1022, %0\n\t":: - "r" ( ((300*20)<<18) | THRM3_E), "r" (0) ); - #if 0 - for ( i = 127 ; i >= 0 ; i-- ) - { - asm("mtspr 1020, %0\n\t":: - "r" (THRM1_TID|THRM1_V|(i<<2)) ); - /* check value */ - while ( !( thrm1 & THRM1_TIV) ) - asm("mfspr %0, 1020 \n\t": "=r" (thrm1) ); - if ( thrm1 & THRM1_TIN ) - { - printk("tin set: %x tiv %x\n", thrm1,thrm1&THRM1_TIV); - goto out; - } - - } + /* disable thrm2 */ + _set_THRM2( 0 ); + /* threshold 0 C, tid: exceeding threshold, tie: don't generate interrupt */ + _set_THRM1( THRM1_V ); + + /* we need 20us to do the compare - assume 300MHz processor clock */ + _set_THRM3(0); + _set_THRM3(THRM3_E | (300*30)<<18 ); + + udelay(100); + /* wait for the compare to complete */ + /*while ( !(_get_THRM1() & THRM1_TIV) ) ;*/ + if ( !(_get_THRM1() & THRM1_TIV) ) + printk("no tiv\n"); + if ( _get_THRM1() & THRM1_TIN ) + printk("crossed\n"); + /* turn everything off */ + _set_THRM3(0); + _set_THRM1(0); #endif -#if 0 - i = 32; /* increment */ - dir = 1; /* direction we're checking 0=up 1=down */ - temp = 64; /* threshold checking against */ - while ( i ) - { - _set_THRM1((1<<29) | THRM1_V | (temp<<2) ); - printk("checking %d in dir %d thrm set to %x/%x\n", temp,dir, - ( (1<<29) | THRM1_V | (temp<<2)),_get_THRM1()); - /* check value */ - sanity = 0x0fffffff; - while ( (!( thrm1 & THRM1_TIV)) && (sanity--) ) - thrm1 = _get_THRM1(); - /*asm("mfspr %0, 1020 \n\t": "=r" (thrm1) );*/ - if ( ! sanity || sanity==0xffffffff ) printk("no sanity\n"); - /* temp is not in that direction */ - if ( !(thrm1 & THRM1_TIN) ) - { - printk("not in that dir thrm1 %x\n",thrm1); - if ( dir == 0 ) dir = 1; - else dir = 0; - } - if ( dir ) temp -= i; - else temp += i; - i /= 2; - } - asm("mtspr 1020, %0\n\t" - "mtspr 1022, %0\n\t" ::"r" (0) ); -#endif -#endif - return 0; + + return thres; } int get_cpuinfo(char *buffer) @@ -333,14 +301,13 @@ int get_cpuinfo(char *buffer) unsigned long len = 0; unsigned long bogosum = 0; unsigned long i; - unsigned long cr; + #ifdef __SMP__ - extern unsigned long cpu_present_map; - extern struct cpuinfo_PPC cpu_data[NR_CPUS]; +#define CPU_PRESENT(x) (cpu_callin_map[(x)]) #define GET_PVR ((long int)(cpu_data[i].pvr)) #define CD(x) (cpu_data[i].x) #else -#define cpu_present_map 1L +#define CPU_PRESENT(x) ((x)==0) #define smp_num_cpus 1 #define GET_PVR ((long int)_get_PVR()) #define CD(x) (x) @@ -348,7 +315,7 @@ int get_cpuinfo(char *buffer) for ( i = 0; i < smp_num_cpus ; i++ ) { - if ( ! ( cpu_present_map & (1<<i) ) ) + if ( !CPU_PRESENT(i) ) continue; if ( i ) len += sprintf(len+buffer,"\n"); @@ -374,14 +341,6 @@ int get_cpuinfo(char *buffer) break; case 8: len += sprintf(len+buffer, "750\n"); - cr = _get_L2CR(); - if ( cr & (0x1<<28)) cr = 256; - else if ( cr & (0x2<<28)) cr = 512; - else if ( cr & (0x3<<28)) cr = 1024; - else cr = 0; - len += sprintf(len+buffer, "on-chip l2\t: " - "%ld KB (%s)\n", - cr,(_get_L2CR()&0x80000000) ? "on" : "off"); len += sprintf(len+buffer, "temperature \t: %lu C\n", cpu_temp()); break; @@ -436,9 +395,9 @@ int get_cpuinfo(char *buffer) #else /* CONFIG_MBX */ { bd_t *bp; - extern RESIDUAL res; + extern RESIDUAL *res; - bp = (bd_t *)&res; + bp = (bd_t *)res; len += sprintf(len+buffer,"clock\t\t: %dMHz\n" "bus clock\t: %dMHz\n", @@ -510,30 +469,41 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7)) { extern void setup_pci_ptrs(void); + +#ifdef __SMP__ + if ( first_cpu_booted ) return 0; +#endif /* __SMP__ */ + #ifndef CONFIG_MBX #ifndef CONFIG_MACH_SPECIFIC - char *model; - /* prep boot loader tells us if we're prep or not */ - if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) - { - _machine = _MACH_prep; - have_of = 0; - } /* boot loader will tell us if we're APUS */ - else if ( r3 == 0x61707573 ) + if ( r3 == 0x61707573 ) { _machine = _MACH_apus; have_of = 0; r3 = 0; - } else - { + } + /* prep boot loader tells us if we're prep or not */ + else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) { + _machine = _MACH_prep; + have_of = 0; + } else { + char *model; + have_of = 1; /* ask the OF info if we're a chrp or pmac */ - model = get_property(find_path_device("/"), "type", NULL); - if ( !strncmp("chrp",model,4) ) + model = get_property(find_path_device("/"), "device_type", NULL); + if ( model && !strncmp("chrp",model,4) ) _machine = _MACH_chrp; - else - _machine = _MACH_Pmac; + else + { + model = get_property(find_path_device("/"), + "model", NULL); + if ( model && !strncmp(model, "IBM", 3)) + _machine = _MACH_chrp; + else + _machine = _MACH_Pmac; + } } #endif /* CONFIG_MACH_SPECIFIC */ @@ -556,6 +526,20 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) { strncpy(cmd_line, (char *)r3 + KERNELBASE, sizeof(cmd_line)); + } else if (boot_infos != 0) { + /* booted by BootX - check for ramdisk */ + if (boot_infos->kernelParamsOffset != 0) + strncpy(cmd_line, (char *) boot_infos + + boot_infos->kernelParamsOffset, + sizeof(cmd_line)); +#ifdef CONFIG_BLK_DEV_INITRD + if (boot_infos->ramDisk) { + initrd_start = (unsigned long) boot_infos + + boot_infos->ramDisk; + initrd_end = initrd_start + boot_infos->ramDiskSize; + initrd_below_start_ok = 1; + } +#endif } else { struct device_node *chosen; char *p; @@ -568,6 +552,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); } #endif + cmd_line[0] = 0; chosen = find_devices("chosen"); if (chosen != NULL) { p = get_property(chosen, "bootargs", NULL); @@ -652,7 +637,6 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, break; #ifdef CONFIG_APUS case _MACH_apus: - setup_pci_ptrs(); /* Parse bootinfo. The bootinfo is located right after the kernel bss */ parse_bootinfo((const struct bi_record *)&_end); @@ -677,6 +661,7 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, default: printk("Unknown machine type in identify_machine!\n"); } + #else /* CONFIG_MBX */ if ( r3 ) @@ -702,6 +687,12 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, strcpy(cmd_line, (char *)(r6+KERNELBASE)); } #endif /* CONFIG_MBX */ + + /* Check for nobats option (used in mapin_ram). */ + if (strstr(cmd_line, "nobats")) { + extern int __map_without_bats; + __map_without_bats = 1; + } return 0; } @@ -722,6 +713,8 @@ __initfunc(void setup_arch(char **cmdline_p, #ifdef CONFIG_XMON extern void xmon_map_scc(void); xmon_map_scc(); + if (strstr(cmd_line, "xmon")) + xmon(0); #endif /* CONFIG_XMON */ /* reboot on panic */ @@ -739,20 +732,6 @@ __initfunc(void setup_arch(char **cmdline_p, *memory_start_p = find_available_memory(); *memory_end_p = (unsigned long) end_of_DRAM; -#ifdef CONFIG_BLK_DEV_INITRD - /* initrd_start and size are setup by boot/head.S and kernel/head.S */ - if ( initrd_start ) - { - if (initrd_end > *memory_end_p) - { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_end,*memory_end_p); - initrd_start = 0; - } - } -#endif - #ifdef CONFIG_MBX mbx_setup_arch(memory_start_p,memory_end_p); #else /* CONFIG_MBX */ @@ -771,7 +750,7 @@ __initfunc(void setup_arch(char **cmdline_p, m68k_machtype = MACH_AMIGA; apus_setup_arch(memory_start_p,memory_end_p); break; -#endif +#endif default: printk("Unknown machine %d in setup_arch()\n", _machine); } diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 6d2d4279e..3ffb7981e 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -1,7 +1,7 @@ /* * linux/arch/ppc/kernel/signal.c * - * $Id: signal.c,v 1.16 1998/06/16 23:34:10 cort Exp $ + * $Id: signal.c,v 1.21 1998/10/22 19:37:49 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -128,6 +128,13 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused) do_exit(SIGSEGV); } +asmlinkage int +sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + struct pt_regs *regs = (struct pt_regs *) &uss; + return do_sigaltstack(uss, uoss, regs->gpr[1]); +} + int sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact) @@ -238,7 +245,7 @@ int sys_sigreturn(struct pt_regs *regs) goto badframe; sr = (struct sigregs *) sigctx.regs; regs->gpr[3] = ret = sigctx.signal; - regs->gpr[4] = (unsigned long) sr; + regs->gpr[4] = (unsigned long) sc; regs->link = (unsigned long) &sr->tramp; regs->nip = sigctx.handler; @@ -286,7 +293,7 @@ setup_frame(struct pt_regs *regs, struct sigregs *frame, || get_user(regs->gpr[3], &sc->signal)) goto badframe; regs->gpr[1] = newsp; - regs->gpr[4] = (unsigned long) frame; + regs->gpr[4] = (unsigned long) sc; regs->link = (unsigned long) frame->tramp; return; @@ -483,3 +490,4 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) setup_frame(regs, (struct sigregs *) frame, newsp); return 1; } + diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index ca8d81de1..75445925f 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -1,5 +1,5 @@ /* - * $Id: smp.c,v 1.28 1998/08/04 04:47:45 cort Exp $ + * $Id: smp.c,v 1.36 1998/10/08 01:17:48 cort Exp $ * * Smp support for ppc. * @@ -35,22 +35,20 @@ int smp_threads_ready = 0; volatile int smp_commenced = 0; int smp_num_cpus = 1; -unsigned long cpu_present_map = 0; -volatile int cpu_number_map[NR_CPUS]; -volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; -volatile int __cpu_logical_map[NR_CPUS]; -static unsigned char boot_cpu_id = 0; struct cpuinfo_PPC cpu_data[NR_CPUS]; struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */ volatile unsigned long ipi_count; spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; - unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; +int first_cpu_booted = 0; -int start_secondary(void *); +/* all cpu mappings are 1-1 -- Cort */ +int cpu_number_map[NR_CPUS] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,}; +volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; +int start_secondary(void *); extern int cpu_idle(void *unused); void smp_local_timer_interrupt(struct pt_regs * regs) @@ -58,7 +56,6 @@ void smp_local_timer_interrupt(struct pt_regs * regs) int cpu = smp_processor_id(); extern void update_one_process(struct task_struct *,unsigned long, unsigned long,unsigned long,int); - if (!--prof_counter[cpu]) { int user=0,system=0; struct task_struct * p = current; @@ -104,7 +101,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs) * Right now it only works for stop cpu's but will be setup * later for more general message passing. * - * As it is now, if we're sending two message as the same time + * As it is now, if we're sending two message at the same time * we have race conditions. I avoided doing locks here since * all that works right now is the stop cpu message. * @@ -115,17 +112,25 @@ void smp_message_recv(void) { int msg = smp_message[smp_processor_id()]; - printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg); + /* clear interrupt */ + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); /* make sure msg is for us */ if ( msg == -1 ) return; -printk("recv after msg check\n"); + + ipi_count++; + /*printk("SMP %d: smp_message_recv() msg %x\n", smp_processor_id(),msg);*/ + switch( msg ) { case MSG_STOP_CPU: __cli(); while (1) ; break; + case MSG_RESCHEDULE: + current->need_resched = 1; + break; case 0xf0f0: /* syncing time bases - just return */ break; default: @@ -139,19 +144,17 @@ printk("recv after msg check\n"); void smp_send_reschedule(int cpu) { - /* for now, nothing */ + smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0); } - spinlock_t mesg_pass_lock = SPIN_LOCK_UNLOCKED; void smp_message_pass(int target, int msg, unsigned long data, int wait) { - printk("SMP %d: sending smp message\n", current->processor); - - spin_lock(&mesg_pass_lock); if ( _machine != _MACH_Pmac ) return; - + /*printk("SMP %d: sending smp message\n", current->processor);*/ +if (smp_processor_id() ) printk("pass from cpu 1\n"); + spin_lock(&mesg_pass_lock); #define OTHER (~smp_processor_id() & 1) switch( target ) @@ -167,9 +170,10 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) break; } /* interrupt secondary processor */ - /**(volatile unsigned long *)(0xf80000c0) = 0xffffffff; - eieio();*/ - *(volatile unsigned long *)(0xf80000c0) = 0; + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); + *(volatile unsigned long *)(0xf80000c0) = 0L; + eieio(); /* interrupt primary */ /**(volatile unsigned long *)(0xf3019000);*/ spin_unlock(&mesg_pass_lock); @@ -177,29 +181,25 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) __initfunc(void smp_boot_cpus(void)) { - extern unsigned long secondary_entry[]; extern struct task_struct *current_set[NR_CPUS]; - int i, timeout; + extern void __secondary_start(void); + int i; struct task_struct *p; printk("Entering SMP Mode...\n"); + + first_cpu_booted = 1; + dcbf(&first_cpu_booted); for (i = 0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; prof_counter[i] = 1; prof_multiplier[i] = 1; } - - cpu_present_map = 0; - for(i=0; i < NR_CPUS; i++) - __cpu_logical_map[i] = -1; - smp_store_cpu_info(boot_cpu_id); - active_kernel_processor = boot_cpu_id; - current->processor = boot_cpu_id; - cpu_present_map |= 1; - cpu_number_map[boot_cpu_id] = 0; - __cpu_logical_map[0] = boot_cpu_id; + cpu_callin_map[0] = 1; + smp_store_cpu_info(0); + active_kernel_processor = 0; + current->processor = 0; if ( _machine != _MACH_Pmac ) { @@ -207,10 +207,6 @@ __initfunc(void smp_boot_cpus(void)) return; } - /* assume a 2nd processor for now */ - cpu_present_map |= (1 << 1); - smp_num_cpus = 2; - /* create a process for second processor */ kernel_thread(start_secondary, NULL, CLONE_PID); p = task[1]; @@ -218,14 +214,16 @@ __initfunc(void smp_boot_cpus(void)) panic("No idle task for secondary processor\n"); p->processor = 1; current_set[1] = p; + /* need to flush here since secondary bat's aren't setup */ - dcbf((volatile unsigned long *)¤t_set[1]); - + dcbf((void *)¤t_set[1]); /* setup entry point of secondary processor */ - *(volatile unsigned long *)(0xf2800000) - = (unsigned long)secondary_entry-KERNELBASE; + *(volatile unsigned long *)(0xf2800000) = + (unsigned long)__secondary_start-KERNELBASE; eieio(); /* interrupt secondary to begin executing code */ + *(volatile unsigned long *)(0xf80000c0) = ~0L; + eieio(); *(volatile unsigned long *)(0xf80000c0) = 0L; eieio(); /* @@ -234,24 +232,23 @@ __initfunc(void smp_boot_cpus(void)) * calibrate_delay() so use this value that I found through * experimentation. -- Cort */ - udelay(1); + for ( i = 1000; i && !cpu_callin_map[1] ; i-- ) + udelay(100); + if(cpu_callin_map[1]) { - cpu_number_map[1] = 1; - __cpu_logical_map[i] = 1; - printk("Processor 1 found.\n"); - + printk("Processor %d found.\n", smp_num_cpus); + smp_num_cpus++; #if 0 /* this sync's the decr's, but we don't want this now -- Cort */ set_dec(decrementer_count); #endif - /* interrupt secondary to start decr's again */ - smp_message_pass(1,0xf0f0, 0, 0); - /* interrupt secondary to begin executing code */ - /**(volatile unsigned long *)(0xf80000c0) = 0L; - eieio();*/ } else { - smp_num_cpus--; - printk("Processor %d is stuck.\n", 1); + printk("Processor %d is stuck. \n", smp_num_cpus); } + /* reset the entry point so if we get another intr we won't + * try to startup again */ + *(volatile unsigned long *)(0xf2800000) = 0x100; + /* send interrupt to other processors to start decr's on all cpus */ + smp_message_pass(1,0xf0f0, 0, 0); } __initfunc(void smp_commence(void)) @@ -271,7 +268,7 @@ __initfunc(void initialize_secondary(void)) } /* Activate a secondary processor. */ -__initfunc(int start_secondary(void *unused)) +asmlinkage int __init start_secondary(void *unused) { printk("SMP %d: start_secondary()\n",current->processor); smp_callin(); @@ -281,16 +278,14 @@ __initfunc(int start_secondary(void *unused)) __initfunc(void smp_callin(void)) { printk("SMP %d: smp_callin()\n",current->processor); - smp_store_cpu_info(1); + smp_store_cpu_info(current->processor); set_dec(decrementer_count); current->mm->mmap->vm_page_prot = PAGE_SHARED; current->mm->mmap->vm_start = PAGE_OFFSET; current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; - - /* assume we're just the secondary processor for now */ - cpu_callin_map[1] = 1; + cpu_callin_map[current->processor] = current->processor; while(!smp_commenced) barrier(); __sti(); @@ -310,6 +305,7 @@ __initfunc(void smp_store_cpu_info(int id)) { struct cpuinfo_PPC *c = &cpu_data[id]; + /* assume bogomips are same for everything */ c->loops_per_sec = loops_per_sec; c->pvr = _get_PVR(); } diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c index 91a8d0ccf..b97456226 100644 --- a/arch/ppc/kernel/syscalls.c +++ b/arch/ppc/kernel/syscalls.c @@ -209,7 +209,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, goto out; } - /*flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);*/ + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); ret = do_mmap(file, addr, len, prot, flags, offset); out: unlock_kernel(); diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 0857c2633..8bada0e69 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -1,5 +1,5 @@ /* - * $Id: time.c,v 1.35 1998/07/24 11:05:47 geert Exp $ + * $Id: time.c,v 1.36 1998/10/10 12:16:08 geert Exp $ * Common time routines among all ppc machines. * * Written by Cort Dougan (cort@cs.nmt.edu) to merge @@ -106,7 +106,12 @@ void timer_interrupt(struct pt_regs * regs) #ifdef __SMP__ smp_local_timer_interrupt(regs); #endif - +#ifdef CONFIG_APUS + { + extern void apus_heartbeat (void); + apus_heartbeat (); + } +#endif hardirq_exit(cpu); /* restore the HID0 in case dcache was off - see idle.c * this hack should leave for a better solution -- Cort */ diff --git a/arch/ppc/kernel/totalmp.c b/arch/ppc/kernel/totalmp.c new file mode 100644 index 000000000..5f87755a7 --- /dev/null +++ b/arch/ppc/kernel/totalmp.c @@ -0,0 +1,109 @@ +/* + * $Id: totalmp.c,v 1.5 1998/08/26 13:58:50 cort Exp $ + * + * Support for Total Impact's TotalMP PowerPC accelerator board. + * + * Written by Cort Dougan (cort@cs.nmt.edu) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/openpic.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/mm.h> + +#include <asm/io.h> + +extern void totalmp_init(void); + +extern inline void openpic_writefield(volatile u_int *addr, u_int mask, + u_int field); +__initfunc(void totalmp_init(void)) +{ + struct pci_dev *dev; + u32 val; + unsigned long ctl_area, ctl_area_phys; + + /* it's a pci card */ + if ( !pci_present() ) return; + + /* search for a MPIC. For now, we assume + * only one TotalMP card installed. -- Cort + */ + for(dev=pci_devices; dev; dev=dev->next) + { + if ( (dev->vendor == PCI_VENDOR_ID_IBM) + && ((dev->device == PCI_DEVICE_ID_IBM_MPIC) + || (dev->device==PCI_DEVICE_ID_IBM_MPIC_2)) ) + { + break; + } + } + + if ( !dev ) return; + + OpenPIC = (struct OpenPIC *)bus_to_virt(dev->base_address[0]); +#if 0 + if ( (ulong)OpenPIC > 0x10000000 ) + { + printk("TotalMP: relocating base %lx -> %lx\n", + (ulong)OpenPIC, ((ulong)OpenPIC & 0x00FFFFFF) | 0x01000000); + OpenPIC = (struct OpenPIC *)(((ulong)OpenPIC & 0x00FFFFFF) | 0x01000000); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, (ulong)OpenPIC); + }*/ +#endif + OpenPIC = (struct OpenPIC *)((ulong)OpenPIC + _IO_BASE); + + openpic_init(0); + + /* put openpic in 8259-cascade mode */ + openpic_writefield(&OpenPIC->Global.Global_Configuration0, 0, 0x20000000); + /* set ipi to highest priority */ + openpic_writefield(&OpenPIC->Global._IPI_Vector_Priority[0].Reg, 0, 0x000f0000); + + /* allocate and remap the control area to be no-cache */ + ctl_area = __get_free_pages(GFP_ATOMIC, 3); + ctl_area_phys = (unsigned long) virt_to_phys((void *)ctl_area); + ctl_area = (unsigned long)ioremap(ctl_area, 0x8000); + + /* soft reset cpu 0 */ + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &val); + openpic_writefield(&OpenPIC->Global._Processor_Initialization.Reg, 0, 0x1); + + /* wait for base address reg to change, signaling that cpu 0 is done */ +#define wait_for(where) { \ + udelay(100); \ + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &val); \ + if ( val != 0x77700000 ) \ + { \ + printk("TotalMP: CPU0 did not respond: val %x %d\n", val, where); \ + /*free_pages((ulong)phys_to_virt(ctl_area_phys),1);*/ \ + return; \ + } } + + /* tell cpu0 where the control area is */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,(~val) >> 16); + wait_for(0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + ((ulong)ctl_area & 0xff000000)>>20); + wait_for(1); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + ((ulong)ctl_area & 0x00ff0000)>>12); + wait_for(2); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + ((ulong)ctl_area & 0x0000ff00)>>4); + wait_for(3); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + ((ulong)ctl_area & 0x000000ff)<<4); + wait_for(4); +#undef wait_for + /* wait for cpu0 to "sign-on" */ +} + diff --git a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c index 0bb06f808..073e7076c 100644 --- a/arch/ppc/lib/locks.c +++ b/arch/ppc/lib/locks.c @@ -1,5 +1,5 @@ /* - * $Id: locks.c,v 1.18 1998/07/28 03:50:27 cort Exp $ + * $Id: locks.c,v 1.20 1998/10/08 01:17:32 cort Exp $ * * Locks for smp ppc * @@ -18,13 +18,13 @@ #define DEBUG_LOCKS 1 #undef INIT_STUCK -#define INIT_STUCK 10000 +#define INIT_STUCK 0xffffffff void _spin_lock(spinlock_t *lock) { int cpu = smp_processor_id(); #ifdef DEBUG_LOCKS - int stuck = INIT_STUCK; + unsigned int stuck = INIT_STUCK; #endif /* DEBUG_LOCKS */ /* try expensive atomic load/store to get lock */ while((unsigned long )xchg_u32((void *)&lock->lock,0xffffffff)) { @@ -67,13 +67,13 @@ int spin_trylock(spinlock_t *lock) void _spin_unlock(spinlock_t *lp) { #ifdef DEBUG_LOCKS - if ( !lp->lock ) - panic("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp, - smp_processor_id(),current->comm,current->pid); + if ( !lp->lock ) + printk("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp, + smp_processor_id(),current->comm,current->pid); if ( lp->owner_cpu != smp_processor_id() ) - panic("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n", - lp, smp_processor_id(), (int)lp->owner_cpu, - lp->owner_pc,lp->lock); + printk("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n", + lp, smp_processor_id(), (int)lp->owner_cpu, + lp->owner_pc,lp->lock); #endif /* DEBUG_LOCKS */ lp->owner_pc = lp->owner_cpu = 0; eieio(); diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S index cc59aaa81..2ff171ee3 100644 --- a/arch/ppc/lib/string.S +++ b/arch/ppc/lib/string.S @@ -219,12 +219,12 @@ memchr: .globl __copy_tofrom_user __copy_tofrom_user: - rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ + srwi. r7,r5,3 addi r6,r3,-4 addi r4,r4,-4 - li r3,0 /* success return value */ - beq 2f /* if less than 8 bytes to do */ - andi. r0,r6,3 /* get dest word aligned */ + li r3,0 /* success return value */ + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ mtctr r7 bne 5f 1: lwz r7,4(r4) @@ -238,7 +238,7 @@ __copy_tofrom_user: 14: lwzu r0,4(r4) addi r5,r5,-4 15: stwu r0,4(r6) -3: cmpwi 0,r5,0 +3: cmpwi 0,r5,0 /* do 1 byte at a time for the remainder */ beqlr mtctr r5 addi r4,r4,3 @@ -247,32 +247,78 @@ __copy_tofrom_user: 16: stbu r0,1(r6) bdnz 4b blr -5: subfic r0,r0,4 - mtctr r0 +5: subfic r0,r0,4 /* copy bytes until we have the */ + mtctr r0 /* destination 4-byte aligned */ + subf r5,r0,r5 6: lbz r7,4(r4) addi r4,r4,1 17: stb r7,4(r6) addi r6,r6,1 bdnz 6b - subf r5,r0,r5 - rlwinm. r7,r5,32-3,3,31 + srwi. r7,r5,3 beq 2b mtctr r7 b 1b -99: li r3,-EFAULT +/* we come here on a fault in the 8-byte-at-a-time loop */ +88: subi r4,r4,8 /* compensate for the lwzu */ +98: mfctr r0 + rlwimi r5,r0,3,0,28 /* use the byte-at-a-time loop to */ + b 3b /* copy up to the byte at fault */ +/* here on a write fault in the single-word copy */ +96: subi r4,r4,4 + b 3b +/* here on a read fault in the initial single-byte copy */ +90: mfctr r3 + add r3,r3,r5 + b 70f +/* here on a read fault in the final single-byte copy */ +99: mfctr r3 + subi r6,r6,3 +/* clear out the rest of the destination: r3 bytes starting at 4(r6) */ +70: li r0,0 + mr. r5,r3 + beq 76f +71: andi. r4,r6,3 + beq 72f +77: stb r0,4(r6) + addi r6,r6,1 + addic. r5,r5,-1 + bne 71b +72: srwi. r7,r5,2 + beq 73f + mtctr r7 +74: stwu r0,4(r6) + bdnz 74b +73: andi. r5,r5,3 + beq 76f + mtctr r5 + addi r6,r6,3 +75: stbu r0,1(r6) + bdnz 75b +76: blr +/* here on a write fault in the initial single-byte copy */ +80: mfctr r3 + add r3,r3,r5 blr +/* here on a write fault in the final single-byte copy */ +81: mfctr r3 + blr + .section __ex_table,"a" .align 2 - .long 1b,99b - .long 11b,99b - .long 12b,99b - .long 13b,99b - .long 14b,99b - .long 15b,99b + .long 1b,98b + .long 11b,98b + .long 12b,88b + .long 13b,88b + .long 14b,3b + .long 15b,96b .long 4b,99b - .long 16b,99b - .long 6b,99b - .long 17b,99b + .long 16b,81b + .long 6b,90b + .long 17b,80b + .long 77b,76b + .long 74b,76b + .long 75b,76b .text #undef CLEAR_USE_DCBZ 1 diff --git a/arch/ppc/mbx_defconfig b/arch/ppc/mbx_defconfig index 1b8829134..e0b94ce6a 100644 --- a/arch/ppc/mbx_defconfig +++ b/arch/ppc/mbx_defconfig @@ -171,7 +171,6 @@ CONFIG_LOCKD=y # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_MOUSE is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 9f4b287a7..b45f4e6f4 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -38,7 +38,7 @@ extern void (*debugger)(struct pt_regs *); extern void (*debugger_fault_handler)(struct pt_regs *); extern int (*debugger_dabr_match)(struct pt_regs *); -int debugger_kernel_faults = 0; +int debugger_kernel_faults = 1; #endif unsigned long htab_reloads = 0; /* updated by head.S:hash_page() */ diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 2bf73835b..44104fd4e 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1,5 +1,5 @@ /* - * $Id: init.c,v 1.115 1998/08/04 20:48:38 davem Exp $ + * $Id: init.c,v 1.130 1998/11/10 10:09:20 paulus Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) @@ -33,6 +33,7 @@ #include <linux/stddef.h> #include <linux/vmalloc.h> #include <linux/init.h> +#include <linux/delay.h> #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> /* for initrd_* */ #endif @@ -46,6 +47,8 @@ #include <asm/uaccess.h> #include <asm/8xx_immap.h> #include <asm/mbx.h> +#include <asm/smp.h> +#include <asm/bootx.h> /* APUS includes */ #include <asm/setup.h> #include <asm/amigahw.h> @@ -69,6 +72,7 @@ unsigned long ioremap_bot; unsigned long avail_start; struct pgtable_cache_struct quicklists; struct mem_info memory[NUM_MEMINFO]; +extern boot_infos_t *boot_infos; void MMU_init(void); static void *MMU_get_page(void); @@ -110,7 +114,8 @@ struct batrange { /* stores address ranges mapped by BATs */ * (i.e. page tables) instead of the bats. * -- Cort */ -#undef MAP_RAM_WITH_SEGREGS 1 +int __map_without_bats = 0; + /* optimization for 603 to load the tlb directly from the linux table -- Cort */ #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */ @@ -229,7 +234,7 @@ void show_mem(void) { printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ", p->comm,p->pid, - p->mm->count,p->mm->context, + atomic_read(&p->mm->count),p->mm->context, p->mm->context<<4, p->tss.last_syscall, user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip, (ulong)p); @@ -239,20 +244,24 @@ void show_mem(void) printk("%3d ", p->processor); if ( (p->processor != NO_PROC_ID) && (p == current_set[p->processor]) ) - + { + iscur = 1; + printk("current"); + } #else if ( p == current ) -#endif /* __SMP__ */ { iscur = 1; printk("current"); } + if ( p == last_task_used_math ) { if ( iscur ) printk(","); printk("last math"); } +#endif /* __SMP__ */ printk("\n"); } } @@ -673,18 +682,21 @@ __initfunc(static void sort_mem_pieces(struct mem_pieces *mp)) __initfunc(static void coalesce_mem_pieces(struct mem_pieces *mp)) { - unsigned long a, e; + unsigned long a, s, ns; int i, j, d; d = 0; for (i = 0; i < mp->n_regions; i = j) { a = mp->regions[i].address; - e = a + mp->regions[i].size; + s = mp->regions[i].size; for (j = i + 1; j < mp->n_regions - && mp->regions[j].address <= e; ++j) - e = mp->regions[j].address + mp->regions[j].size; + && mp->regions[j].address - a <= s; ++j) { + ns = mp->regions[j].address + mp->regions[j].size - a; + if (ns > s) + s = ns; + } mp->regions[d].address = a; - mp->regions[d].size = e - a; + mp->regions[d].size = s; ++d; } mp->n_regions = d; @@ -796,33 +808,41 @@ __initfunc(static void mapin_ram(void)) int i; unsigned long v, p, s, f; #ifndef CONFIG_8xx - unsigned long tot, mem_base, bl, done; - -#ifndef MAP_RAM_WITH_SEGREGS - /* Set up BAT2 and if necessary BAT3 to cover RAM. */ - mem_base = __pa(KERNELBASE); - tot = (unsigned long)end_of_DRAM - KERNELBASE; - for (bl = 128<<10; bl < 256<<20; bl <<= 1) { - if (bl * 2 > tot) - break; - /* On some APUS systems, memory grows downwards, i.e., - 24MB will be 8MB aligned. Handle that properly by - mapping first 8MB, then 16MB. */ - if (((bl * 2) - 1) & mem_base) - break; - } - setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE); - done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1; - if (done < tot) { - /* use BAT3 to cover a bit more */ - tot -= done; - for (bl = 128<<10; bl < 256<<20; bl <<= 1) + if (!__map_without_bats) { + unsigned long tot, mem_base, bl, done; + unsigned long max_size = (256<<20); + unsigned long align; + + /* Set up BAT2 and if necessary BAT3 to cover RAM. */ + mem_base = __pa(KERNELBASE); + + /* Make sure we don't map a block larger than the + smallest alignment of the physical address. */ + /* alignment of mem_base */ + align = ~(mem_base-1) & mem_base; + /* set BAT block size to MIN(max_size, align) */ + if (align && align < max_size) + max_size = align; + + tot = (unsigned long)end_of_DRAM - KERNELBASE; + for (bl = 128<<10; bl < max_size; bl <<= 1) { if (bl * 2 > tot) break; - setbat(3, KERNELBASE+done, mem_base+done, bl, RAM_PAGE); + } + + setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE); + done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1; + if (done < tot) { + /* use BAT3 to cover a bit more */ + tot -= done; + for (bl = 128<<10; bl < max_size; bl <<= 1) + if (bl * 2 > tot) + break; + setbat(3, KERNELBASE+done, mem_base+done, bl, + RAM_PAGE); + } } -#endif v = KERNELBASE; for (i = 0; i < phys_mem.n_regions; ++i) { @@ -884,7 +904,6 @@ __initfunc(void free_initmem(void)) unsigned long a; unsigned long num_freed_pages = 0, num_prep_pages = 0, num_pmac_pages = 0, num_openfirmware_pages = 0; - #define FREESEC(START,END,CNT) do { \ a = (unsigned long)(&START); \ for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ @@ -899,7 +918,10 @@ __initfunc(void free_initmem(void)) switch (_machine) { case _MACH_Pmac: + FREESEC(__prep_begin,__prep_end,num_prep_pages); + break; case _MACH_chrp: + FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); FREESEC(__prep_begin,__prep_end,num_prep_pages); break; case _MACH_prep: @@ -933,6 +955,11 @@ __initfunc(void free_initmem(void)) */ __initfunc(void MMU_init(void)) { + +#ifdef __SMP__ + if ( first_cpu_booted ) return; +#endif /* __SMP__ */ + #ifndef CONFIG_8xx if (have_of) end_of_DRAM = pmac_find_end_of_memory(); @@ -962,12 +989,18 @@ __initfunc(void MMU_init(void)) setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE); break; case _MACH_Pmac: - setbat(0, 0xf3000000, 0xf3000000, 0x100000, IO_PAGE); - ioremap_base = 0xf0000000; + { + unsigned long base = 0xf3000000; + struct device_node *macio = find_devices("mac-io"); + if (macio && macio->n_addrs) + base = macio->addrs[0].address; + setbat(0, base, base, 0x100000, IO_PAGE); + ioremap_base = 0xf0000000; + } break; case _MACH_apus: /* Map PPC exception vectors. */ - setbat(0, 0xfff00000, 0xfff00000, 0x00010000, RAM_PAGE); + setbat(0, 0xfff00000, 0xfff00000, 0x00020000, RAM_PAGE); /* Map chip and ZorroII memory */ setbat(1, zTwoBase, 0x00000000, 0x01000000, IO_PAGE); /* Note: a temporary hack in arch/ppc/amiga/setup.c @@ -997,17 +1030,16 @@ __initfunc(void MMU_init(void)) /* * Find some memory for setup_arch to return. - * We use the last chunk of available memory as the area + * We use the largest chunk of available memory as the area * that setup_arch returns, making sure that there are at * least 32 pages unused before this for MMU_get_page to use. */ __initfunc(unsigned long find_available_memory(void)) { - int i; + int i, rn; unsigned long a, free; unsigned long start, end; - free = 0; if (_machine == _MACH_mbx) { /* Return the first, not the last region, because we * may not yet have properly initialized the additonal @@ -1018,12 +1050,17 @@ __initfunc(unsigned long find_available_memory(void)) return avail_start; } - for (i = 0; i < phys_avail.n_regions - 1; ++i) { + rn = 0; + for (i = 1; i < phys_avail.n_regions; ++i) + if (phys_avail.regions[i].size > phys_avail.regions[rn].size) + rn = i; + free = 0; + for (i = 0; i < rn; ++i) { start = phys_avail.regions[i].address; end = start + phys_avail.regions[i].size; free += (end & PAGE_MASK) - PAGE_ALIGN(start); } - a = PAGE_ALIGN(phys_avail.regions[i].address); + a = PAGE_ALIGN(phys_avail.regions[rn].address); if (free < 32 * PAGE_SIZE) a += 32 * PAGE_SIZE - free; avail_start = (unsigned long) __va(a); @@ -1082,6 +1119,15 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) } phys_avail.n_regions = 0; +#ifdef CONFIG_BLK_DEV_INITRD + /* if we are booted from BootX with an initial ramdisk, + make sure the ramdisk pages aren't reserved. */ + if (initrd_start) { + for (a = initrd_start; a < initrd_end; a += PAGE_SIZE) + clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags); + } +#endif /* CONFIG_BLK_DEV_INITRD */ + /* free the prom's memory - no-op on prep */ for (i = 0; i < prom_mem.n_regions; ++i) { a = (unsigned long) __va(prom_mem.regions[i].address); @@ -1216,8 +1262,13 @@ __initfunc(unsigned long *pmac_find_end_of_memory(void)) phys_mem.n_regions = 1; } - /* record which bits the prom is using */ - get_mem_prop("available", &phys_avail); + if (boot_infos == 0) { + /* record which bits the prom is using */ + get_mem_prop("available", &phys_avail); + } else { + /* booted from BootX - it's all available (after klimit) */ + phys_avail = phys_mem; + } prom_mem = phys_mem; for (i = 0; i < phys_avail.n_regions; ++i) remove_mem_piece(&prom_mem, phys_avail.regions[i].address, @@ -1274,36 +1325,69 @@ __initfunc(unsigned long *prep_find_end_of_memory(void)) #define HARDWARE_MAPPED_SIZE (512*1024) __initfunc(unsigned long *apus_find_end_of_memory(void)) { - unsigned long kstart, ksize; + int shadow = 0; - /* Add the chunk that ADOS does not see. This may also - * include a ROM mapping which we reclaim. The top 512KB is - * removed again below. - * Do it by aligning the size to the nearest 2MB limit upwards. - */ - memory[0].size = ((memory[0].size+0x001fffff) & 0xffe00000); + /* The memory size reported by ADOS excludes the 512KB + reserved for PPC exception registers and possibly 512KB + containing a shadow of the ADOS ROM. */ + { + unsigned long size = memory[0].size; + + /* If 2MB aligned, size was probably user + specified. We can't tell anything about shadowing + in this case so skip shadow assignment. */ + if (0 != (size & 0x1fffff)){ + /* Align to 512KB to ensure correct handling + of both memfile and system specified + sizes. */ + size = ((size+0x0007ffff) & 0xfff80000); + /* If memory is 1MB aligned, assume + shadowing. */ + shadow = !(size & 0x80000); + } - append_mem_piece(&phys_mem, memory[0].addr, memory[0].size); + /* Add the chunk that ADOS does not see. by aligning + the size to the nearest 2MB limit upwards. */ + memory[0].size = ((size+0x001fffff) & 0xffe00000); + } - phys_avail = phys_mem; - kstart = __pa(_stext); - ksize = PAGE_ALIGN(klimit - _stext); - remove_mem_piece(&phys_avail, kstart, ksize, 1); + /* Now register the memory block. */ + { + unsigned long kstart, ksize; - /* Remove the upper HARDWARE_MAPPED_SIZE bytes where the address - * range 0xfff00000-0xfffx0000 is mapped to. - * We do it this way to ensure that the memory registered in the - * system has a power-of-two size. - */ - remove_mem_piece(&phys_avail, - (memory[0].addr + memory[0].size - - HARDWARE_MAPPED_SIZE), - HARDWARE_MAPPED_SIZE, 1); + append_mem_piece(&phys_mem, memory[0].addr, memory[0].size); + phys_avail = phys_mem; + kstart = __pa(_stext); + ksize = PAGE_ALIGN(klimit - _stext); + remove_mem_piece(&phys_avail, kstart, ksize, 0); + } + + /* Remove the memory chunks that are controlled by special + Phase5 hardware. */ + { + unsigned long top = memory[0].addr + memory[0].size; + + /* Remove the upper 512KB if it contains a shadow of + the ADOS ROM. FIXME: It might be possible to + disable this shadow HW. Check the booter + (ppc_boot.c) */ + if (shadow) + { + top -= HARDWARE_MAPPED_SIZE; + remove_mem_piece(&phys_avail, top, + HARDWARE_MAPPED_SIZE, 0); + } + + /* Remove the upper 512KB where the PPC exception + vectors are mapped. */ + top -= HARDWARE_MAPPED_SIZE; + remove_mem_piece(&phys_avail, top, + HARDWARE_MAPPED_SIZE, 0); + } /* FIXME:APUS: Only handles one block of memory! Problem is - * that the VTOP/PTOV code in head.S would be a mess if it had - * to handle more than one block. - */ + that the VTOP/PTOV code in head.S would be a mess if it had + to handle more than one block. */ return __va(memory[0].addr + memory[0].size); } @@ -1393,6 +1477,5 @@ __initfunc(static void hash_init(void)) } else Hash_end = 0; - } #endif /* ndef CONFIG_8xx */ diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig index 5be933292..ae1303bb4 100644 --- a/arch/ppc/pmac_defconfig +++ b/arch/ppc/pmac_defconfig @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # @@ -35,16 +35,20 @@ CONFIG_KERNEL_ELF=y CONFIG_BINFMT_MISC=m # CONFIG_BINFMT_JAVA is not set # CONFIG_PARPORT is not set -# CONFIG_FB is not set # CONFIG_VGA_CONSOLE is not set -# CONFIG_PMAC_PBOOK is not set +CONFIG_FB=y +CONFIG_FB_COMPAT_XPMAC=y +CONFIG_PMAC_PBOOK=y CONFIG_MAC_KEYBOARD=y CONFIG_MAC_FLOPPY=y CONFIG_MAC_SERIAL=y -CONFIG_MACMOUSE=y +CONFIG_ADBMOUSE=y +CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_PROC_DEVICETREE=y # CONFIG_KGDB is not set # CONFIG_XMON is not set +# CONFIG_TOTALMP is not set +CONFIG_BOOTX_TEXT=y # # Plug and Play support @@ -56,17 +60,29 @@ CONFIG_PROC_DEVICETREE=y # # CONFIG_BLK_DEV_FD is not set CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDEDISK=y CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y # CONFIG_BLK_DEV_IDESCSI is not set # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_RZ1000 is not set # CONFIG_BLK_DEV_IDEPCI is not set # CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDE_PMAC=y +CONFIG_BLK_DEV_IDEDMA_PMAC=y +CONFIG_BLK_DEV_IDEDMA=y +CONFIG_PMAC_IDEDMA_AUTO=y # CONFIG_IDE_CHIPSETS is not set + +# +# Additional Block Devices +# # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set @@ -98,10 +114,18 @@ CONFIG_IP_MULTICAST=y # CONFIG_IP_MROUTE is not set CONFIG_IP_ALIAS=y # CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# CONFIG_INET_RARP=y CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set + +# +# +# # CONFIG_IPX is not set CONFIG_ATALK=m # CONFIG_X25 is not set @@ -119,11 +143,19 @@ CONFIG_ATALK=m # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y # CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -135,7 +167,7 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set -CONFIG_SCSI_AIC7XXX=m +CONFIG_SCSI_AIC7XXX=y # CONFIG_OVERRIDE_CMDS is not set CONFIG_AIC7XXX_PROC_STATS=y CONFIG_AIC7XXX_RESET_DELAY=15 @@ -192,27 +224,35 @@ CONFIG_NET_EISA=y # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set # CONFIG_CS89x0 is not set -CONFIG_DE4X5=m +CONFIG_DE4X5=y CONFIG_DEC_ELCP=m # CONFIG_DGRS is not set # CONFIG_EEXPRESS_PRO100 is not set # CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set # CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set +# CONFIG_HIPPI is not set # CONFIG_DLCI is not set # CONFIG_LTPC is not set # CONFIG_COPS is not set # CONFIG_IPDDP is not set -CONFIG_PPP=m +CONFIG_PPP=y + +# +# CCP compressors for PPP are only built as modules. +# # CONFIG_SLIP is not set # CONFIG_NET_RADIO is not set # CONFIG_TR is not set # CONFIG_SHAPER is not set +# CONFIG_HOSTESS_SV11 is not set # # Amateur Radio support @@ -230,6 +270,58 @@ CONFIG_PPP=m # CONFIG_CD_NO_IDESCSI is not set # +# Console drivers +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_OF=y +CONFIG_FB_CONTROL=y +CONFIG_FB_PLATINUM=y +CONFIG_FB_VALKYRIE=y +CONFIG_FB_ATY=y +CONFIG_FB_IMSTT=y +CONFIG_FB_CT65550=y +# CONFIG_FB_S3TRIO is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +CONFIG_FBCON_FONTS=y +# CONFIG_FONT_8x8 is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_SUN8x16=y +CONFIG_FONT_SUN12x22=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=m +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_MOUSE is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +CONFIG_NVRAM=y +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# # Filesystems # # CONFIG_QUOTA is not set @@ -244,6 +336,7 @@ CONFIG_VFAT_FS=m CONFIG_PROC_FS=y CONFIG_NFS_FS=y CONFIG_NFSD=y +# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_CODA_FS is not set @@ -252,12 +345,16 @@ CONFIG_LOCKD=y # CONFIG_NTFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=m +CONFIG_HFS_FS=y # CONFIG_ROMFS_FS is not set CONFIG_AUTOFS_FS=y # CONFIG_UFS_FS is not set -# CONFIG_ADFS_FS is not set +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SMD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set CONFIG_DEVPTS_FS=y +# CONFIG_ADFS_FS is not set +# CONFIG_QNX4FS_FS is not set CONFIG_MAC_PARTITION=y CONFIG_NLS=y @@ -292,33 +389,13 @@ CONFIG_NLS_CODEPAGE_437=y # CONFIG_NLS_KOI8_R is not set # -# Console drivers -# - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_MOUSE is not set -# CONFIG_UMISC is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set -# CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_VIDEO_DEV is not set -CONFIG_NVRAM=y -# CONFIG_JOYSTICK is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set - -# # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +CONFIG_DMASOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set diff --git a/arch/ppc/prep_defconfig b/arch/ppc/prep_defconfig index c3521f370..41db35a4a 100644 --- a/arch/ppc/prep_defconfig +++ b/arch/ppc/prep_defconfig @@ -41,7 +41,7 @@ CONFIG_VGA_CONSOLE=y # CONFIG_MAC_KEYBOARD is not set # CONFIG_MAC_FLOPPY is not set # CONFIG_MAC_SERIAL is not set -# CONFIG_MACMOUSE is not set +# CONFIG_ADBMOUSE is not set # CONFIG_PROC_DEVICETREE is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set @@ -196,9 +196,9 @@ CONFIG_DE4X5=y # CONFIG_EEXPRESS_PRO100 is not set # CONFIG_LNE390 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_TLAN is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set -# CONFIG_TLAN is not set # CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # CONFIG_FDDI is not set @@ -225,6 +225,39 @@ CONFIG_PPP=m # CONFIG_CD_NO_IDESCSI is not set # +# Console drivers +# + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_MOUSE=y +# CONFIG_ATIXL_BUSMOUSE is not set +# CONFIG_BUSMOUSE is not set +# CONFIG_MS_BUSMOUSE is not set +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_UMISC is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_WATCHDOG is not set +# CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_NVRAM is not set +# CONFIG_JOYSTICK is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set + +# # Filesystems # # CONFIG_QUOTA is not set @@ -287,41 +320,42 @@ CONFIG_NLS=y # CONFIG_NLS_KOI8_R is not set # -# Console drivers -# - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=y -CONFIG_SERIAL_CONSOLE=y -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_MOUSE=y -# CONFIG_ATIXL_BUSMOUSE is not set -# CONFIG_BUSMOUSE is not set -# CONFIG_MS_BUSMOUSE is not set -CONFIG_PSMOUSE=y -# CONFIG_82C710_MOUSE is not set -# CONFIG_PC110_PAD is not set -# CONFIG_UMISC is not set -# CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set -# CONFIG_WATCHDOG is not set -# CONFIG_RTC is not set -# CONFIG_VIDEO_DEV is not set -# CONFIG_NVRAM is not set -# CONFIG_JOYSTICK is not set -# CONFIG_MISC_RADIO is not set - -# -# Ftape, the floppy tape device driver +# Sound # -# CONFIG_FTAPE is not set +CONFIG_SOUND=y +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +CONFIG_SOUND_OSS=y +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_WAVEFRONT is not set +CONFIG_SOUND_CS4232=y +CONFIG_CS4232_BASE=530 +CONFIG_CS4232_IRQ=11 +CONFIG_CS4232_DMA=0 +CONFIG_CS4232_DMA2=3 +CONFIG_CS4232_MPU_BASE=330 +CONFIG_CS4232_MPU_IRQ=9 +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_UART6850 is not set # -# Sound +# Additional low level sound drivers # -# CONFIG_SOUND is not set +# CONFIG_LOWLEVEL_SOUND is not set diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index fa171a7f7..45bec8353 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.36 1998/06/02 00:36:40 davem Exp $ +# $Id: Makefile,v 1.39 1998/09/16 12:31:31 jj Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -15,26 +15,35 @@ SHELL =/bin/bash # Uncomment the first CFLAGS if you are doing kgdb source level # debugging of the kernel to get the proper debugging information. +IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi) +NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) + +ifeq ($(NEW_GAS),y) +AS := $(AS) -32 +LD := $(LD) -m elf32_sparc +endif + #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 +ifneq ($(IS_EGCS),y) CFLAGS := $(CFLAGS) -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 +else +CFLAGS := $(CFLAGS) -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 +endif #LINKFLAGS = -N -Ttext 0xf0004000 LINKFLAGS = -T arch/sparc/vmlinux.lds HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o -# Note arch/sparc/mm has to be the last subdir SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/prom \ - arch/sparc/mm + arch/sparc/mm arch/sparc/math-emu -CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES) +CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES) \ + arch/sparc/math-emu/math-emu.o LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ $(TOPDIR)/arch/sparc/lib/lib.a -SUBDIRS += arch/sparc/math-emu -CORE_FILES += arch/sparc/math-emu/math-emu.o - ifdef CONFIG_AP1000 SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o \ @@ -43,8 +52,14 @@ DRIVERS := $(DRIVERS) drivers/ap1000/ap1000.a CFLAGS := $(CFLAGS) -D__MPP__=1 endif +# This one has to come last +SUBDIRS += arch/sparc/boot +CORE_FILES_NO_BTFIX := $(CORE_FILES) +CORE_FILES += arch/sparc/boot/btfix.o + archclean: - -$(MAKE) -C arch/sparc/boot archclean + rm -f $(TOPDIR)/vmlinux.aout + -$(MAKE) -C arch/sparc/boot clean archmrproper: -$(MAKE) -C arch/sparc/math-emu cleansymlinks @@ -57,19 +72,3 @@ check_asm: tftpboot.img: $(MAKE) -C arch/sparc/boot tftpboot.img - -vmlinux.o: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs - $(LD) -r $(VMLINUX.OBJS) -o vmlinux.o - -arch/sparc/boot/btfix.s: arch/sparc/boot/btfixupprep vmlinux.o - $(OBJDUMP) -x vmlinux.o | arch/sparc/boot/btfixupprep > arch/sparc/boot/btfix.s - -arch/sparc/boot/btfix.o: arch/sparc/boot/btfix.s - $(CC) -c -o arch/sparc/boot/btfix.o arch/sparc/boot/btfix.s - -arch/sparc/boot/btfixupprep: arch/sparc/boot/btfixupprep.c - $(MAKE) -C arch/sparc/boot btfixupprep - -vmlinux: arch/sparc/boot/btfix.o - $(LD) $(LINKFLAGS) vmlinux.o arch/sparc/boot/btfix.o -o vmlinux - $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile index c9301a79e..b0f7f63ea 100644 --- a/arch/sparc/boot/Makefile +++ b/arch/sparc/boot/Makefile @@ -1,16 +1,13 @@ -# $Id: Makefile,v 1.6 1998/02/23 01:44:39 rth Exp $ +# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $ # Makefile for the Sparc boot stuff. # # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) -# Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) +# Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) ROOT_IMG =/usr/src/root.img ELFTOAOUT =elftoaout -all: boot - -boot: - @echo "Nothing special to be done for 'boot' on Linux/SPARC." +all: btfix.o tftpboot.img: piggyback $(ELFTOAOUT) $(TOPDIR)/vmlinux -o tftpboot.img @@ -22,8 +19,24 @@ piggyback: piggyback.c btfixupprep: btfixupprep.c $(HOSTCC) $(HOSTCFLAGS) -o btfixupprep btfixupprep.c -archclean: - rm -f btfixupprep piggyback tftpboot.img +clean: + rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s + +BTOBJS := $(HEAD) init/main.o init/version.o \ + $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \ + $(NETWORKS) $(DRIVERS) + +# I wanted to make this depend upon BTOBJS so that a parallel +# build would work, but this fails because $(HEAD) cannot work +# properly as it will cause head.o to be built with the implicit +# rules not the ones in kernel/Makefile. Someone please fix. --DaveM +vmlinux.o: dummy + $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o + +btfix.s: btfixupprep vmlinux.o + $(OBJDUMP) -x vmlinux.o | ./btfixupprep > btfix.s -dep: +btfix.o: btfix.s + $(CC) -c -o btfix.o btfix.s +include $(TOPDIR)/Rules.make diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c index 1bef965af..af0a1dc4e 100644 --- a/arch/sparc/boot/btfixupprep.c +++ b/arch/sparc/boot/btfixupprep.c @@ -1,4 +1,4 @@ -/* $Id: btfixupprep.c,v 1.3 1998/03/09 14:03:10 jj Exp $ +/* $Id: btfixupprep.c,v 1.5 1998/09/16 12:24:55 jj Exp $ Simple utility to prepare vmlinux image for sparc. Resolves all BTFIXUP uses and settings and creates a special .s object to link to the image. @@ -29,8 +29,11 @@ #define MAXSYMS 1024 +static char *symtab = "SYMBOL TABLE:"; static char *relrec = "RELOCATION RECORDS FOR ["; static int rellen; +static int symlen; +int mode; struct _btfixup; @@ -97,6 +100,20 @@ int main(int argc,char **argv) unsigned long offset; char *initvalstr; + symlen = strlen(symtab); + while (fgets (buffer, 1024, stdin) != NULL) + if (!strncmp (buffer, symtab, symlen)) + goto main0; + fatal(); +main0: + if (fgets (buffer, 1024, stdin) == NULL || buffer[0] < '0' || buffer[0] > '9') + fatal(); + for (mode = 0;; mode++) + if (buffer[mode] < '0' || buffer[mode] > '9') + break; + if (mode != 8 && mode != 16) + fatal(); + rellen = strlen(relrec); while (fgets (buffer, 1024, stdin) != NULL) if (!strncmp (buffer, relrec, rellen)) @@ -112,17 +129,19 @@ main1: if (fgets (buffer, 1024, stdin) == NULL) fatal(); while (fgets (buffer, 1024, stdin) != NULL) { + int nbase; if (!strncmp (buffer, relrec, rellen)) goto main1; p = strchr (buffer, '\n'); if (p) *p = 0; - if (strlen (buffer) < 30) + if (strlen (buffer) < 22+mode) continue; - if (strncmp (buffer + 8, " R_SPARC_", 9)) + if (strncmp (buffer + mode, " R_SPARC_", 9)) continue; - if (buffer[27] != '_' || buffer[28] != '_' || buffer[29] != '_') + nbase = 27 - 8 + mode; + if (buffer[nbase] != '_' || buffer[nbase+1] != '_' || buffer[nbase+2] != '_') continue; - switch (buffer[30]) { + switch (buffer[nbase+3]) { case 'f': /* CALL */ case 'b': /* BLACKBOX */ case 's': /* SIMM13 */ @@ -133,26 +152,26 @@ main1: default: continue; } - p = strchr (buffer + 32, '+'); + p = strchr (buffer + nbase+5, '+'); if (p) *p = 0; - shift = 32; - if (buffer[31] == 's' && buffer[32] == '_') { - shift = 33; + shift = nbase + 5; + if (buffer[nbase+4] == 's' && buffer[nbase+5] == '_') { + shift = nbase + 6; if (strcmp (sect, ".text.init")) { fprintf(stderr, "Wrong use of '%s' BTFIXUPSET.\nBTFIXUPSET_CALL can be used only in __init sections\n", buffer+shift); exit(1); } - } else if (buffer[31] != '_') + } else if (buffer[nbase+4] != '_') continue; - if (strcmp (sect, ".text") && strcmp (sect, ".text.init") && (strcmp (sect, "__ksymtab") || buffer[30] != 'f')) { - if (buffer[30] == 'f') - fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .text.init and __ksymtab\n", buffer + shift, sect); + if (strcmp (sect, ".text") && strcmp (sect, ".text.init") && strcmp (sect, ".fixup") && (strcmp (sect, "__ksymtab") || buffer[nbase+3] != 'f')) { + if (buffer[nbase+3] == 'f') + fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .text.init, .fixup and __ksymtab\n", buffer + shift, sect); else - fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text and .text.init\n", buffer + shift, sect); + fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .fixup and .text.init\n", buffer + shift, sect); exit(1); } p = strstr (buffer + shift, "__btset_"); - if (p && buffer[31] == 's') { + if (p && buffer[nbase+4] == 's') { fprintf(stderr, "__btset_ in BTFIXUP name can only be used when defining the variable, not for setting\n%s\n", buffer); exit(1); } @@ -171,23 +190,23 @@ main1: initvalstr = p + 10; *p = 0; } - f = find(buffer[30], buffer + shift); - if (buffer[31] == 's') + f = find(buffer[nbase+3], buffer + shift); + if (buffer[nbase+4] == 's') continue; - switch (buffer[30]) { + switch (buffer[nbase+3]) { case 'f': if (initval) { fprintf(stderr, "Cannot use pre-initalized fixups for calls\n%s\n", buffer); exit(1); } if (!strcmp (sect, "__ksymtab")) { - if (strncmp (buffer + 17, "32 ", 10)) { + if (strncmp (buffer + mode+9, "32 ", 10)) { fprintf(stderr, "BTFIXUP_CALL in EXPORT_SYMBOL results in relocation other than R_SPARC_32\n\%s\n", buffer); exit(1); } - } else if (strncmp (buffer + 17, "WDISP30 ", 10) && - strncmp (buffer + 17, "HI22 ", 10) && - strncmp (buffer + 17, "LO10 ", 10)) { + } else if (strncmp (buffer + mode+9, "WDISP30 ", 10) && + strncmp (buffer + mode+9, "HI22 ", 10) && + strncmp (buffer + mode+9, "LO10 ", 10)) { fprintf(stderr, "BTFIXUP_CALL results in relocation other than R_SPARC_WDISP30, R_SPARC_HI22 or R_SPARC_LO10\n%s\n", buffer); exit(1); } @@ -197,7 +216,7 @@ main1: fprintf(stderr, "Cannot use pre-initialized fixups for blackboxes\n%s\n", buffer); exit(1); } - if (strncmp (buffer + 17, "HI22 ", 10)) { + if (strncmp (buffer + mode+9, "HI22 ", 10)) { fprintf(stderr, "BTFIXUP_BLACKBOX results in relocation other than R_SPARC_HI22\n%s\n", buffer); exit(1); } @@ -207,7 +226,7 @@ main1: fprintf(stderr, "Wrong initializer for SIMM13. Has to be from $fffff000 to $00000fff\n%s\n", buffer); exit(1); } - if (strncmp (buffer + 17, "13 ", 10)) { + if (strncmp (buffer + mode+9, "13 ", 10)) { fprintf(stderr, "BTFIXUP_SIMM13 results in relocation other than R_SPARC_13\n%s\n", buffer); exit(1); } @@ -217,7 +236,7 @@ main1: fprintf(stderr, "Wrong initializer for HALF.\n%s\n", buffer); exit(1); } - if (strncmp (buffer + 17, "13 ", 10)) { + if (strncmp (buffer + mode+9, "13 ", 10)) { fprintf(stderr, "BTFIXUP_HALF results in relocation other than R_SPARC_13\n%s\n", buffer); exit(1); } @@ -227,7 +246,7 @@ main1: fprintf(stderr, "Wrong initializer for SETHI. Cannot have set low 10 bits\n%s\n", buffer); exit(1); } - if (strncmp (buffer + 17, "HI22 ", 10)) { + if (strncmp (buffer + mode+9, "HI22 ", 10)) { fprintf(stderr, "BTFIXUP_SETHI results in relocation other than R_SPARC_HI22\n%s\n", buffer); exit(1); } @@ -237,7 +256,7 @@ main1: fprintf(stderr, "Cannot use pre-initalized fixups for INT\n%s\n", buffer); exit(1); } - if (strncmp (buffer + 17, "HI22 ", 10) && strncmp (buffer + 17, "LO10 ", 10)) { + if (strncmp (buffer + mode+9, "HI22 ", 10) && strncmp (buffer + mode+9, "LO10 ", 10)) { fprintf(stderr, "BTFIXUP_INT results in relocation other than R_SPARC_HI22 and R_SPARC_LO10\n%s\n", buffer); exit(1); } @@ -261,7 +280,7 @@ main1: exit(1); } offset = strtoul(buffer, &q, 16); - if (q != buffer + 8 || (!offset && strncmp (buffer, "00000000 ", 9))) { + if (q != buffer + mode || (!offset && (mode == 8 ? strncmp (buffer, "00000000 ", 9) : strncmp (buffer, "0000000000000000 ", 17)))) { fprintf(stderr, "Malformed relocation address in\n%s\n", buffer); exit(1); } @@ -274,7 +293,7 @@ main1: if (!*rr) fatal(); (*rr)->offset = offset; (*rr)->f = NULL; - if (buffer[30] == 'f') { + if (buffer[nbase+3] == 'f') { lastf = f; lastfoffset = offset; lastfrelno = k; @@ -302,11 +321,13 @@ main1: printf("0\n"); for (r = f->rel, j--; r != NULL; j--, r = r->next) { if (!strcmp (r->sect, ".text")) - printf ("_stext+0x%08x", r->offset); + printf ("_stext+0x%08lx", r->offset); else if (!strcmp (r->sect, ".text.init")) - printf ("__init_begin+0x%08x", r->offset); + printf ("__init_begin+0x%08lx", r->offset); else if (!strcmp (r->sect, "__ksymtab")) - printf ("__start___ksymtab+0x%08x", r->offset); + printf ("__start___ksymtab+0x%08lx", r->offset); + else if (!strcmp (r->sect, ".fixup")) + printf ("__start___fixup+0x%08lx", r->offset); else fatal(); if (f->type == 'f' || !r->f) diff --git a/arch/sparc/config.in b/arch/sparc/config.in index e3aaea31c..97c970481 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.58 1998/07/29 05:06:41 davem Exp $ +# $Id: config.in,v 1.63 1998/09/21 05:05:56 jj Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -35,6 +35,9 @@ if [ "$CONFIG_AP1000" = "y" ]; then tristate 'OPIU DDV Driver' CONFIG_DDV else bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4 + if [ "$CONFIG_SUN4" != "y" ]; then + bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI + fi mainmenu_option next_comment comment 'Console drivers' @@ -54,9 +57,7 @@ else define_bool CONFIG_SUN_CONSOLE y define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y - if [ "$CONFIG_SUN4" = "y" ]; then - bool 'Force early PROM Console' CONFIG_SUN4_FORCECONSOLE - else + if [ "$CONFIG_SUN4" != "y" ]; then source drivers/sbus/char/Config.in source drivers/sbus/audio/Config.in fi diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 52801ae68..7ea12a128 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -21,6 +21,7 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y # CONFIG_AP1000 is not set # CONFIG_SUN4 is not set +# CONFIG_PCI is not set # # Console drivers @@ -67,6 +68,8 @@ CONFIG_SUN_MOSTEK_RTC=y # CONFIG_SPARCAUDIO is not set # CONFIG_SPARCAUDIO_AMD7930 is not set # CONFIG_SPARCAUDIO_CS4231 is not set +# CONFIG_SPARCAUDIO_DBRI is not set +# CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m CONFIG_NET=y CONFIG_SYSVIPC=y @@ -74,7 +77,7 @@ CONFIG_SYSVIPC=y CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y +CONFIG_BINFMT_MISC=m CONFIG_BINFMT_JAVA=m # @@ -82,52 +85,32 @@ CONFIG_BINFMT_JAVA=m # CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -CONFIG_MD_STRIPED=y +CONFIG_MD_LINEAR=m +CONFIG_MD_STRIPED=m CONFIG_MD_MIRRORING=m CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_NBD=m # # Networking options # CONFIG_PACKET=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -# CONFIG_NETLINK_DEV is not set -CONFIG_FIREWALL=y -CONFIG_NET_ALIAS=y +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -CONFIG_IP_MULTICAST=y +# CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -CONFIG_IP_FIREWALL=y -# CONFIG_IP_FIREWALL_NETLINK is not set -# CONFIG_IP_TRANSPARENT_PROXY is not set -# CONFIG_IP_ALWAYS_DEFRAG is not set -CONFIG_IP_MASQUERADE=y - -# -# Protocol-specific masquerading support will be built as modules. -# -# CONFIG_IP_MASQUERADE_ICMP is not set - -# -# Protocol-specific masquerading support will be built as modules. -# -# CONFIG_IP_MASQUERADE_IPAUTOFW is not set -# CONFIG_IP_MASQUERADE_IPPORTFW is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y -# CONFIG_ARPD is not set +# CONFIG_IP_ALIAS is not set # CONFIG_SYN_COOKIES is not set # @@ -146,7 +129,7 @@ CONFIG_IPX=m # CONFIG_IPX_INTERN is not set # CONFIG_SPX is not set CONFIG_ATALK=m -CONFIG_X25=m +# CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set # CONFIG_LLC is not set @@ -155,18 +138,7 @@ CONFIG_X25=m # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set # CONFIG_CPU_IS_SLOW is not set -CONFIG_NET_SCHED=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_CSZ=m -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -# CONFIG_NET_SCH_TEQL is not set -CONFIG_NET_SCH_TBF=y -# CONFIG_NET_QOS is not set -# CONFIG_NET_CLS is not set +# CONFIG_NET_SCHED is not set # # ISDN subsystem @@ -185,7 +157,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SG=m # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -236,21 +208,22 @@ CONFIG_MYRI_SBUS=m # # Filesystems # -CONFIG_QUOTA=y +# CONFIG_QUOTA is not set CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y +CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=m CONFIG_PROC_FS=y CONFIG_NFS_FS=y CONFIG_NFSD=m +# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set +CONFIG_CODA_FS=m CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m @@ -268,12 +241,12 @@ CONFIG_AFFS_FS=m CONFIG_ROMFS_FS=m CONFIG_AUTOFS_FS=m CONFIG_AMIGA_PARTITION=y -CONFIG_UFS_FS=y +CONFIG_UFS_FS=m CONFIG_BSD_DISKLABEL=y CONFIG_SMD_DISKLABEL=y -# CONFIG_SOLARIS_X86_PARTITION is not set +CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_ADFS_FS is not set -CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set # CONFIG_MAC_PARTITION is not set CONFIG_NLS=y diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 9606064b3..18e487d86 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.45 1998/07/28 16:52:42 jj Exp $ +# $Id: Makefile,v 1.48 1998/09/21 05:04:46 jj Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -22,7 +22,7 @@ O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \ sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \ sunos_ioctl.o time.o windows.o cpu.o devices.o \ sclow.o solaris.o tadpole.o tick14.o ptrace.o sys_solaris.o \ - unaligned.o muldiv.o + unaligned.o muldiv.o pcic.o OX_OBJS := sparc_ksyms.o @@ -38,6 +38,10 @@ ifdef CONFIG_SUN_AUXIO O_OBJS += auxio.o endif +ifdef CONFIG_PCI +O_OBJS += ebus.o +endif + head.o: head.S $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c index 13d34310f..a5e24ac52 100644 --- a/arch/sparc/kernel/auxio.c +++ b/arch/sparc/kernel/auxio.c @@ -5,6 +5,7 @@ #include <linux/stddef.h> #include <linux/init.h> +#include <linux/config.h> #include <asm/oplib.h> #include <asm/io.h> #include <asm/auxio.h> @@ -32,6 +33,11 @@ __initfunc(void auxio_probe(void)) node = prom_getchild(node); auxio_nd = prom_searchsiblings(node, "auxio"); if(!auxio_nd) { +#ifdef CONFIG_PCI + /* There may be auxio on Ebus */ + auxio_register = 0; + return; +#else if(prom_searchsiblings(node, "leds")) { /* VME chassis sun4m machine, no auxio exists. */ auxio_register = 0; @@ -39,6 +45,7 @@ __initfunc(void auxio_probe(void)) } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); +#endif } } prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs)); diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index dd4dbb3c6..69f3070e5 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c @@ -1,5 +1,5 @@ /* devices.c: Initial scan of the prom device tree for important - * Sparc device nodes which we need to find. + * Sparc device nodes which we need to find. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ @@ -14,8 +14,8 @@ #include <asm/smp.h> #include <asm/system.h> -struct prom_cpuinfo linux_cpus[NR_CPUS]; -int linux_num_cpus; +struct prom_cpuinfo linux_cpus[32]; +int linux_num_cpus = 0; extern void cpu_probe(void); extern void clock_stop_probe(void); /* tadpole.c */ @@ -25,64 +25,55 @@ __initfunc(unsigned long device_scan(unsigned long mem_start)) { char node_str[128]; - int nd, prom_node_cpu, thismid; - int cpu_nds[NR_CPUS]; /* One node for each cpu */ - int cpu_ctr = 0; + int thismid; prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); if(strcmp(node_str, "cpu") == 0) { - cpu_nds[0] = prom_root_node; - cpu_ctr++; + linux_num_cpus++; } else { int scan; scan = prom_getchild(prom_root_node); prom_printf("root child is %08lx\n", (unsigned long) scan); - nd = 0; while((scan = prom_getsibling(scan)) != 0) { prom_getstring(scan, "device_type", node_str, sizeof(node_str)); if(strcmp(node_str, "cpu") == 0) { - cpu_nds[cpu_ctr] = scan; - linux_cpus[cpu_ctr].prom_node = scan; + linux_cpus[linux_num_cpus].prom_node = scan; prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid)); - linux_cpus[cpu_ctr].mid = thismid; + linux_cpus[linux_num_cpus].mid = thismid; prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", - cpu_ctr, (unsigned long) scan, + linux_num_cpus, (unsigned long) scan, thismid); - cpu_ctr++; + linux_num_cpus++; } }; - if(cpu_ctr == 0) { + if(linux_num_cpus == 0) { if (sparc_cpu_model == sun4d) { scan = prom_getchild(prom_root_node); for (scan = prom_searchsiblings(scan, "cpu-unit"); scan; scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) { int node = prom_getchild(scan); - + prom_getstring(node, "device_type", node_str, sizeof(node_str)); if (strcmp(node_str, "cpu") == 0) { prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid)); - cpu_nds[cpu_ctr] = node; - linux_cpus[cpu_ctr].prom_node = node; - linux_cpus[cpu_ctr].mid = 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", - cpu_ctr, (unsigned long) node, + linux_num_cpus, (unsigned long) node, thismid); - cpu_ctr++; + linux_num_cpus++; } } } } - if(cpu_ctr == 0) { + if(linux_num_cpus == 0) { printk("No CPU nodes found, cannot continue.\n"); /* Probably a sun4e, Sun is trying to trick us ;-) */ halt(); } - printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); + printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus); }; - prom_node_cpu = cpu_nds[0]; - - linux_num_cpus = cpu_ctr; cpu_probe(); #ifdef CONFIG_SUN_AUXIO diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c new file mode 100644 index 000000000..7c3eda88e --- /dev/null +++ b/arch/sparc/kernel/ebus.c @@ -0,0 +1,331 @@ +/* $Id: ebus.c,v 1.2 1998/10/07 11:35:16 jj Exp $ + * ebus.c: PCI to EBus bridge device. + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * + * Adopted for sparc by V. Roganov and G. Raiko. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/malloc.h> +#include <linux/string.h> + +#include <asm/system.h> +#include <asm/page.h> +#include <asm/pbm.h> +#include <asm/ebus.h> +#include <asm/io.h> +#include <asm/oplib.h> +#include <asm/bpp.h> + +#undef PROM_DEBUG +#undef DEBUG_FILL_EBUS_DEV + +#ifdef PROM_DEBUG +#define dprintf prom_printf +#else +#define dprintf printk +#endif + +struct linux_ebus *ebus_chain = 0; + +#ifdef CONFIG_SUN_OPENPROMIO +extern int openprom_init(void); +#endif +#ifdef CONFIG_SPARCAUDIO +extern int sparcaudio_init(void); +#endif +#ifdef CONFIG_SUN_AUXIO +extern void auxio_probe(void); +#endif +#ifdef CONFIG_OBP_FLASH +extern int flash_init(void); +#endif +#ifdef CONFIG_ENVCTRL +extern int envctrl_init(void); +#endif + +static inline unsigned long ebus_alloc(size_t size) +{ + return (unsigned long)kmalloc(size, GFP_ATOMIC); +} + +__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg, + struct linux_ebus_child *dev)) +{ + int regs[PROMREG_MAX]; + int irqs[PROMREG_MAX]; + char lbuf[128]; + int i, len; + + dev->prom_node = node; + prom_getstring(node, "name", lbuf, sizeof(lbuf)); + strcpy(dev->prom_name, lbuf); + + len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); + dev->num_addrs = len / sizeof(regs[0]); + + for (i = 0; i < dev->num_addrs; i++) { + if (regs[i] >= dev->parent->num_addrs) { + prom_printf("UGH: property for %s was %d, need < %d\n", + dev->prom_name, len, dev->parent->num_addrs); + panic(__FUNCTION__); + } + dev->base_address[i] = dev->parent->base_address[regs[i]]; + } + + len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); + if ((len == -1) || (len == 0)) { + dev->num_irqs = 0; + /* + * Oh, well, some PROMs don't export interrupts + * property to children of EBus devices... + * + * Be smart about PS/2 keyboard and mouse. + */ + if (!strcmp(dev->parent->prom_name, "8042")) { + dev->num_irqs = 1; + dev->irqs[0] = dev->parent->irqs[0]; + } + } else { + dev->num_irqs = len / sizeof(irqs[0]); + printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]); + } + +#ifdef DEBUG_FILL_EBUS_DEV + dprintk("child '%s': address%s\n", dev->prom_name, + dev->num_addrs > 1 ? "es" : ""); + for (i = 0; i < dev->num_addrs; i++) + dprintk(" %016lx\n", dev->base_address[i]); + if (dev->num_irqs) { + dprintk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); + for (i = 0; i < dev->num_irqs; i++) + dprintk(" %08x", dev->irqs[i]); + dprintk("\n"); + } +#endif +} + +__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) +{ + struct linux_prom_registers regs[PROMREG_MAX]; + struct linux_ebus_child *child; + int irqs[PROMINTR_MAX]; + char lbuf[128]; + int i, n, len; + + dev->prom_node = node; + prom_getstring(node, "name", lbuf, sizeof(lbuf)); + strcpy(dev->prom_name, lbuf); + + len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); + if (len % sizeof(struct linux_prom_registers)) { + prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", + dev->prom_name, len, + (int)sizeof(struct linux_prom_registers)); + panic(__FUNCTION__); + } + dev->num_addrs = len / sizeof(struct linux_prom_registers); + + for (i = 0; i < dev->num_addrs; i++) { + n = (regs[i].which_io - 0x10) >> 2; + + dev->base_address[i] = dev->bus->self->base_address[n]; + dev->base_address[i] += regs[i].phys_addr; + + if (dev->base_address[i]) { + dev->base_address[i] = + (unsigned long)sparc_alloc_io (dev->base_address[i], 0, + regs[i].reg_size, + dev->prom_name, 0, 0); + /* Some drivers call 'check_region', so we release it */ + release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE); + + if (dev->base_address[i] == 0 ) { + panic("ebus: unable sparc_alloc_io for dev %s", + dev->prom_name); + } + } + } + + len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); + if ((len == -1) || (len == 0)) { + dev->num_irqs = 0; + } else { + dev->num_irqs = len / sizeof(irqs[0]); + +#define IRQ_8042 7 + if (irqs[0] == 4) dev->irqs[0] = IRQ_8042; + printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]); + } + +#ifdef DEBUG_FILL_EBUS_DEV + dprintk("'%s': address%s\n", dev->prom_name, + dev->num_addrs > 1 ? "es" : ""); + for (i = 0; i < dev->num_addrs; i++) + dprintk(" %016lx\n", dev->base_address[i]); + if (dev->num_irqs) { + dprintk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); + for (i = 0; i < dev->num_irqs; i++) + dprintk(" %08x", dev->irqs[i]); + dprintk("\n"); + } +#endif + if ((node = prom_getchild(node))) { + dev->children = (struct linux_ebus_child *) + ebus_alloc(sizeof(struct linux_ebus_child)); + + child = dev->children; + child->next = 0; + child->parent = dev; + child->bus = dev->bus; + fill_ebus_child(node, ®s[0], child); + + while ((node = prom_getsibling(node))) { + child->next = (struct linux_ebus_child *) + ebus_alloc(sizeof(struct linux_ebus_child)); + + child = child->next; + child->next = 0; + child->parent = dev; + child->bus = dev->bus; + fill_ebus_child(node, ®s[0], child); + } + } +} + +__initfunc(void ebus_init(void)) +{ + struct linux_prom_pci_registers regs[PROMREG_MAX]; + struct linux_pbm_info *pbm; + struct linux_ebus_device *dev; + struct linux_ebus *ebus; + struct pci_dev *pdev; + struct pcidev_cookie *cookie; + char lbuf[128]; + unsigned long addr, *base; + unsigned short pci_command; + int nd, len, ebusnd; + int reg, nreg; + int num_ebus = 0; + + if (!pci_present()) + return; + + pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0); + if (!pdev) { +#ifdef PROM_DEBUG + dprintk("ebus: No EBus's found.\n"); +#endif + return; + } + cookie = pdev->sysdata; + ebusnd = cookie->prom_node; + + ebus_chain = ebus = (struct linux_ebus *) + ebus_alloc(sizeof(struct linux_ebus)); + ebus->next = 0; + + while (ebusnd) { +#ifdef PROM_DEBUG + dprintk("ebus%d:", num_ebus); +#endif + + prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf)); + ebus->prom_node = ebusnd; + strcpy(ebus->prom_name, lbuf); + ebus->self = pdev; + ebus->parent = pbm = cookie->pbm; + + /* Enable BUS Master. */ + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + pci_command |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + + len = prom_getproperty(ebusnd, "reg", (void *)regs, + sizeof(regs)); + if (len == 0 || len == -1) { + prom_printf("%s: can't find reg property\n", + __FUNCTION__); + prom_halt(); + } + nreg = len / sizeof(struct linux_prom_pci_registers); + + base = &ebus->self->base_address[0]; + for (reg = 0; reg < nreg; reg++) { + if (!(regs[reg].which_io & 0x03000000)) + continue; + + addr = regs[reg].phys_lo; + *base++ = addr; +#ifdef PROM_DEBUG + dprintk(" %lx[%x]", addr, regs[reg].size_lo); +#endif + } +#ifdef PROM_DEBUG + dprintk("\n"); +#endif + + nd = prom_getchild(ebusnd); + if (!nd) + goto next_ebus; + + ebus->devices = (struct linux_ebus_device *) + ebus_alloc(sizeof(struct linux_ebus_device)); + + dev = ebus->devices; + dev->next = 0; + dev->children = 0; + dev->bus = ebus; + fill_ebus_device(nd, dev); + + while ((nd = prom_getsibling(nd))) { + dev->next = (struct linux_ebus_device *) + ebus_alloc(sizeof(struct linux_ebus_device)); + + dev = dev->next; + dev->next = 0; + dev->children = 0; + dev->bus = ebus; + fill_ebus_device(nd, dev); + } + + next_ebus: + pdev = pci_find_device(PCI_VENDOR_ID_SUN, + PCI_DEVICE_ID_SUN_EBUS, pdev); + if (!pdev) + break; + + cookie = pdev->sysdata; + ebusnd = cookie->prom_node; + + ebus->next = (struct linux_ebus *) + ebus_alloc(sizeof(struct linux_ebus)); + ebus = ebus->next; + ebus->next = 0; + ++num_ebus; + } + +#ifdef CONFIG_SUN_OPENPROMIO + openprom_init(); +#endif + +#ifdef CONFIG_SPARCAUDIO + sparcaudio_init(); +#endif +#ifdef CONFIG_SUN_BPP + bpp_init(); +#endif +#ifdef CONFIG_SUN_AUXIO + auxio_probe(); +#endif +#ifdef CONFIG_ENVCTRL + envctrl_init(); +#endif +#ifdef CONFIG_OBP_FLASH + flash_init(); +#endif +} diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 66ae02054..d628c0c8d 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.152 1998/07/29 16:32:24 jj Exp $ +/* $Id: entry.S,v 1.153 1998/11/11 15:12:33 jj Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -313,7 +313,8 @@ real_irq_continue: patch_handler_irq: call C_LABEL(handler_irq) add %sp, REGWIN_SZ, %o1 ! pt_regs ptr - wr %l0, PSR_ET, %psr + or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq + wr %g2, PSR_ET, %psr ! keep ET up WRITE_PAUSE RESTORE_ALL diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c index 506a98622..156ed4337 100644 --- a/arch/sparc/kernel/init_task.c +++ b/arch/sparc/kernel/init_task.c @@ -6,7 +6,7 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index d2d27d90a..4c8f78c8a 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.86 1998/06/04 09:54:49 jj Exp $ +/* $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj 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 @@ -6,8 +6,9 @@ * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) - * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@ipmce.su) + * 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) */ #include <linux/config.h> @@ -40,6 +41,7 @@ #include <asm/spinlock.h> #include <asm/hardirq.h> #include <asm/softirq.h> +#include <asm/pcic.h> /* * Dave Redman (djhr@tadpole.co.uk) @@ -190,13 +192,9 @@ void free_irq(unsigned int irq, void *dev_id) restore_flags(flags); } -/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */ +/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */ +unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -#ifdef __SMP__ -atomic_t __sparc_bh_counter = ATOMIC_INIT(0); -#else -int __sparc_bh_counter = 0; -#endif #ifdef __SMP__ /* SMP interrupt locking on Sparc. */ @@ -207,14 +205,33 @@ unsigned char global_irq_holder = NO_PROC_ID; /* This protects IRQ's. */ spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; -/* This protects BH software state (masks, things like that). */ -spinlock_t global_bh_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 +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#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) +{ + int stuck = INIT_STUCK; + do { + STUCK; + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} + static unsigned long previous_irqholder; #undef INIT_STUCK @@ -224,36 +241,83 @@ static unsigned long previous_irqholder; #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; } +/* + * We have to allow irqs to arrive between __sti and __cli + */ +#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") + static inline void wait_on_irq(int cpu, unsigned long where) { int stuck = INIT_STUCK; int local_count = local_irq_count[cpu]; - /* Are we the only one in an interrupt context? */ - while (local_count != atomic_read(&global_irq_count)) { + for (;;) { + /* - * No such luck. Now we need to release the lock, - * _and_ release our interrupt context, because - * otherwise we'd have dead-locks and live-locks - * and other fun things. + * Wait until all interrupts are gone. Wait + * for bottom half handlers unless we're + * already executing in one.. */ - atomic_sub(local_count, &global_irq_count); + if (!atomic_read(&global_irq_count)) { + if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ spin_unlock(&global_irq_lock); - /* - * Wait for everybody else to go away and release - * their things before trying to get the lock again. - */ for (;;) { STUCK; + + __sti(); + SYNC_OTHER_CORES(cpu); + __cli(); + if (atomic_read(&global_irq_count)) continue; if (*((unsigned char *)&global_irq_lock)) continue; + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + continue; if (spin_trylock(&global_irq_lock)) break; } - atomic_add(local_count, &global_irq_count); + } +} + +/* + * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +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); + } +} + +/* + * This is called when we want to synchronize with + * interrupts. We may for example tell a device to + * stop sending interrupts: but to make sure there + * are no interrupts that are executing on another + * CPU we need to call this function. + */ +void synchronize_irq(void) +{ + if (atomic_read(&global_irq_count)) { + /* Stupid approach */ + cli(); + sti(); } } @@ -280,54 +344,106 @@ static inline void get_irqlock(int cpu, unsigned long where) } while (*((volatile unsigned char *)&global_irq_lock)); } while (!spin_trylock(&global_irq_lock)); } - /* - * Ok, we got the lock bit. - * But that's actually just the easy part.. Now - * we need to make sure that nobody else is running + /* + * We also to make sure that nobody else is running * in an interrupt context. */ wait_on_irq(cpu, where); /* - * Finally. + * Ok, finally.. */ global_irq_holder = cpu; previous_irqholder = where; } +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + * + * If we already have local interrupts disabled, + * this will not turn a local disable into a + * global one (problems with spinlocks: this makes + * save_flags+cli+sti usable inside a spinlock). + */ void __global_cli(void) { - int cpu = smp_processor_id(); + unsigned int flags; unsigned long where; __asm__("mov %%i7, %0" : "=r" (where)); - __cli(); - get_irqlock(cpu, where); + + __save_flags(flags); + + if ((flags & PSR_PIL) != PSR_PIL) { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count[cpu]) + get_irqlock(cpu, where); + } } void __global_sti(void) { - release_irqlock(smp_processor_id()); + int cpu = smp_processor_id(); + + if (!local_irq_count[cpu]) + release_irqlock(cpu); __sti(); } +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ unsigned long __global_save_flags(void) { - return global_irq_holder == (unsigned char) smp_processor_id(); + int retval; + int local_enabled = 0; + unsigned long flags; + + __save_flags(flags); + + if ((flags & PSR_PIL) != PSR_PIL) + local_enabled = 1; + + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count[smp_processor_id()]) { + if (local_enabled) + retval = 1; + if (global_irq_holder == (unsigned char) smp_processor_id()) + retval = 0; + } + return retval; } void __global_restore_flags(unsigned long flags) { - if(flags & 1) { + switch (flags) { + case 0: __global_cli(); - } else { - /* release_irqlock() */ - if(global_irq_holder == smp_processor_id()) { - global_irq_holder = NO_PROC_ID; - spin_unlock(&global_irq_lock); - } - if(!(flags & 2)) - __sti(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + printk("global_restore_flags: %08lx (%08lx)\n", + flags, (&flags)[-1]); } } @@ -352,7 +468,7 @@ void irq_enter(int cpu, int irq, void *_opaque) while (*((volatile unsigned char *)&global_irq_lock)) { if ((unsigned char) cpu == global_irq_holder) { struct pt_regs *regs = _opaque; - int sbh_cnt = atomic_read(&__sparc_bh_counter); + 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]; @@ -385,24 +501,6 @@ void irq_exit(int cpu, int irq) } #endif /* DEBUG_IRQLOCK */ - -/* There has to be a better way. */ -void synchronize_irq(void) -{ - int cpu = smp_processor_id(); - int local_count = local_irq_count[cpu]; - - if(local_count != atomic_read(&global_irq_count)) { - unsigned long flags; - - /* See comment below at __global_save_flags to understand - * why we must do it this way on Sparc. - */ - save_and_cli(flags); - restore_flags(flags); - } -} - #endif /* __SMP__ */ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs) @@ -510,12 +608,13 @@ int request_fast_irq(unsigned int irq, /* If this is flagged as statically allocated then we use our * private struct which is never freed. */ - if (irqflags & SA_STATIC_ALLOC) + if (irqflags & SA_STATIC_ALLOC) { if (static_irq_count < MAX_STATIC_ALLOC) action = &static_irqaction[static_irq_count++]; else printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", irq, devname); + } if (action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), @@ -603,11 +702,12 @@ int request_irq(unsigned int irq, /* If this is flagged as statically allocated then we use our * private struct which is never freed. */ - if (irqflags & SA_STATIC_ALLOC) + if (irqflags & SA_STATIC_ALLOC) { if (static_irq_count < MAX_STATIC_ALLOC) action = &static_irqaction[static_irq_count++]; else printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname); + } if (action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), @@ -669,6 +769,13 @@ __initfunc(void init_IRQ(void)) break; case sun4m: +#ifdef CONFIG_PCI + pcic_probe(); + if (pci_present()) { + sun4m_pci_init_IRQ(); + break; + } +#endif sun4m_init_IRQ(); break; diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c new file mode 100644 index 000000000..aae13c515 --- /dev/null +++ b/arch/sparc/kernel/pcic.c @@ -0,0 +1,762 @@ +/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $ + * pcic.c: Sparc/PCI controller support + * + * Copyright (C) 1998 V. Roganov and G. Raiko + * + * Code is derived from Ultra/PCI PSYCHO controller support, see that + * for author info. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/malloc.h> + +#include <asm/ebus.h> +#include <asm/sbus.h> /* for sanity check... */ + +#include <asm/io.h> + +#undef PROM_DEBUG +#undef FIXUP_REGS_DEBUG +#undef FIXUP_IRQ_DEBUG +#undef FIXUP_VMA_DEBUG + +#ifdef PROM_DEBUG +#define dprintf prom_printf +#else +#define dprintf printk +#endif + +#include <linux/ctype.h> +#include <linux/pci.h> +#include <linux/timex.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/oplib.h> +#include <asm/pcic.h> +#include <asm/timer.h> +#include <asm/uaccess.h> + +#ifndef CONFIG_PCI + +int pcibios_present(void) +{ + return 0; +} + +asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + return 0; +} + +asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + return 0; +} + +#else + +static struct linux_pcic PCIC; +static struct linux_pcic *pcic = NULL; + +static void pci_do_gettimeofday(struct timeval *tv); +static void pci_do_settimeofday(struct timeval *tv); + +__initfunc(void pcic_probe(void)) +{ + struct linux_prom_registers regs[PROMREG_MAX]; + struct linux_pbm_info* pbm; + char namebuf[64]; + int node; + int err; + + if (pcibios_present()) { + prom_printf("PCIC: called twice!\n"); + prom_halt(); + } + + node = prom_getchild (prom_root_node); + node = prom_searchsiblings (node, "pci"); + if (node == 0) + return; + /* + * Map in PCIC register set, config space, and IO base + */ + err = prom_getproperty(node, "reg", (char*)regs, sizeof(regs)); + if (err == 0 || err == -1) { + prom_printf("PCIC: Error, cannot get PCIC registers " + "from PROM.\n"); + prom_halt(); + } + + pcic = &PCIC; + + pcic->pcic_regs = (unsigned long)sparc_alloc_io(regs[0].phys_addr, NULL, + regs[0].reg_size, + "PCIC Registers", 0, 0); + if (!pcic->pcic_regs) { + prom_printf("PCIC: Error, cannot map PCIC registers.\n"); + prom_halt(); + } + + pcic->pcic_io_phys = regs[1].phys_addr; + pcic->pcic_io = (unsigned long)sparc_alloc_io(regs[1].phys_addr, NULL, + regs[1].reg_size, + "PCIC IO Base", 0, 0); + if (pcic->pcic_io == 0UL) { + prom_printf("PCIC: Error, cannot map PCIC IO Base.\n"); + prom_halt(); + } + + pcic->pcic_config_space_addr = + (unsigned long)sparc_alloc_io (regs[2].phys_addr, NULL, + regs[2].reg_size * 2, + "PCI Config Space Address", 0, 0); + if (pcic->pcic_config_space_addr == 0UL) { + prom_printf("PCIC: Error, cannot map" + "PCI Configuration Space Address.\n"); + prom_halt(); + } + + /* + * Docs say three least significant bits in address and data + * must be the same. Thus, we need adjust size of data. + */ + pcic->pcic_config_space_data = + (unsigned long)sparc_alloc_io (regs[3].phys_addr, NULL, + regs[3].reg_size * 2, + "PCI Config Space Data", 0, 0); + if (pcic->pcic_config_space_data == 0UL) { + prom_printf("PCIC: Error, cannot map" + "PCI Configuration Space Data.\n"); + prom_halt(); + } + + pbm = &pcic->pbm; + pbm->prom_node = node; + prom_getstring(node, "name", namebuf, sizeof(namebuf)); + strcpy(pbm->prom_name, namebuf); +} + +__initfunc(void pcibios_init(void)) +{ + /* + * PCIC should be initialized at start of the timer. + * So, here we report the presence of PCIC and do some magic passes. + */ + if(!pcic) + return; + + printk("PCIC MAP: config addr=0x%lx; config data=0x%lx, " + "regs=0x%lx io=0x%lx\n", + pcic->pcic_config_space_addr, pcic->pcic_config_space_data, + pcic->pcic_regs, pcic->pcic_io); + + /* + * FIXME: + * Switch off IOTLB translation. + * It'll be great to use IOMMU to handle HME's rings + * but we couldn't. Thus, we have to flush CPU cache + * in HME. + */ + writeb(PCI_DVMA_CONTROL_IOTLB_DISABLE, + pcic->pcic_regs+PCI_DVMA_CONTROL); + + /* + * FIXME: + * Increase mapped size for PCI memory space (DMA access). + * Should be done in that order (size first, address second). + * Why we couldn't set up 4GB and forget about it ? + */ + writel(0xF0000000UL, pcic->pcic_regs+PCI_SIZE_0); + writel(0+PCI_BASE_ADDRESS_SPACE_MEMORY, + pcic->pcic_regs+PCI_BASE_ADDRESS_0); +} + +int pcibios_present(void) +{ + return pcic != NULL; +} + +__initfunc(static int pdev_to_pnode(struct linux_pbm_info *pbm, + struct pci_dev *pdev)) +{ + struct linux_prom_pci_registers regs[PROMREG_MAX]; + int err; + int node = prom_getchild(pbm->prom_node); + + while(node) { + err = prom_getproperty(node, "reg", + (char *)®s[0], sizeof(regs)); + if(err != 0 && err != -1) { + unsigned long devfn = (regs[0].which_io >> 8) & 0xff; + if(devfn == pdev->devfn) + return node; /* Match */ + } + node = prom_getsibling(node); + } + return 0; +} + +static inline struct pcidev_cookie *pci_devcookie_alloc(void) +{ + return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC); +} + + +static void pcic_map_pci_device (struct pci_dev *dev) { + int node, pcinode; + int i, j; + + /* Is any valid address present ? */ + i = 0; + for(j = 0; j < 6; j++) + if (dev->base_address[j]) i++; + if (!i) return; /* nothing to do */ + + /* + * find related address and get it's window length + */ + pcinode = prom_getchild(prom_root_node); + pcinode = prom_searchsiblings(pcinode, "pci"); + if (!pcinode) + panic("PCIC: failed to locate 'pci' node"); + + + for (node = prom_getchild(pcinode); node; + node = prom_getsibling(node)) { + struct linux_prom_pci_assigned_addresses addrs[6]; + int addrlen = prom_getproperty(node,"assigned-addresses", + (char*)addrs, sizeof(addrs)); + if (addrlen == -1) + continue; + + addrlen /= sizeof(struct linux_prom_pci_assigned_addresses); + for (i = 0; i < addrlen; i++ ) + for (j = 0; j < 6; j++) { + if (!dev->base_address[j] || !addrs[i].phys_lo) + continue; + if (addrs[i].phys_lo == dev->base_address[j]) { + unsigned long address = dev->base_address[j]; + int length = addrs[i].size_lo; + char namebuf[128] = { 0, }; + unsigned long mapaddr, addrflags; + + prom_getstring(node, "name", + namebuf, sizeof(namebuf)); + + /* FIXME: + * failure in allocation too large space + */ + if (length > 0x200000) { + length = 0x200000; + prom_printf("PCIC: map window for device '%s' " + "reduced to 2MB !\n", namebuf); + } + + /* + * Be careful with MEM/IO address flags + */ + if ((address & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_IO) { + mapaddr = address & PCI_BASE_ADDRESS_IO_MASK; + } else { + mapaddr = address & PCI_BASE_ADDRESS_MEM_MASK; + } + addrflags = address ^ mapaddr; + + dev->base_address[j] = + (unsigned long)sparc_alloc_io(address, 0, + length, + namebuf, 0, 0); + if ( dev->base_address[j] == 0 ) + panic("PCIC: failed make mapping for " + "pci device '%s' with address %lx\n", + namebuf, address); + + dev->base_address[j] ^= addrflags; + return; + } + } + } + + panic("PCIC: unable to locate prom node for pci device (%x,%x) \n", + dev->device, dev->vendor); +} + +/* + * Assign IO space for a device. + * This is a chance for devices which have the same IO and Mem Space to + * fork access to IO and Mem. + * + * Now, we assume there is one such device only (IGA 1682) but code below + * should work in cases when space of all such devices is less then 16MB. + */ +unsigned long pcic_alloc_io( unsigned long* addr ) +{ + unsigned long paddr = *addr; + unsigned long offset; + + if(pcic->pcic_mapped_io == 0) { + pcic->pcic_mapped_io = paddr & ~(PCI_SPACE_SIZE-1) ; + writeb((pcic->pcic_mapped_io>>24) & 0xff, + pcic->pcic_regs+PCI_PIBAR); + writeb((pcic->pcic_io_phys>>24) & PCI_SIBAR_ADDRESS_MASK, + pcic->pcic_regs+PCI_SIBAR); + writeb(PCI_ISIZE_16M, pcic->pcic_regs+PCI_ISIZE); + } + if(paddr < pcic->pcic_mapped_io || + paddr > pcic->pcic_mapped_io + PCI_SPACE_SIZE) + return 0; + offset = paddr - pcic->pcic_mapped_io; + *addr = pcic->pcic_io_phys + offset; + return pcic->pcic_io + offset; +} + +/* + * Stolen from both i386 and sparc64 branch + */ +__initfunc(void pcibios_fixup(void)) +{ + struct pci_dev *dev; + int i, has_io, has_mem; + unsigned short cmd; + + if(pcic == NULL) { + prom_printf("PCI: Error, PCIC not found.\n"); + prom_halt(); + } + + for (dev = pci_devices; dev; dev=dev->next) { + /* + * Comment from i386 branch: + * There are buggy BIOSes that forget to enable I/O and memory + * access to PCI devices. We try to fix this, but we need to + * be sure that the BIOS didn't forget to assign an address + * to the device. [mj] + * OBP is a case of such BIOS :-) + */ + has_io = has_mem = 0; + for(i=0; i<6; i++) { + unsigned long a = dev->base_address[i]; + if (a & PCI_BASE_ADDRESS_SPACE_IO) { + has_io = 1; + } else if (a & PCI_BASE_ADDRESS_MEM_MASK) + has_mem = 1; + } + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (has_io && !(cmd & PCI_COMMAND_IO)) { + printk("PCI: Enabling I/O for device %02x:%02x\n", + dev->bus->number, dev->devfn); + cmd |= PCI_COMMAND_IO; + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) { + printk("PCI: Enabling memory for device %02x:%02x\n", + dev->bus->number, dev->devfn); + cmd |= PCI_COMMAND_MEMORY; + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + + /* cookies */ + { + struct pcidev_cookie *pcp; + struct linux_pbm_info* pbm = &pcic->pbm; + int node = pdev_to_pnode(pbm, dev); + + if(node == 0) + node = -1; + pcp = pci_devcookie_alloc(); + pcp->pbm = pbm; + pcp->prom_node = node; + dev->sysdata = pcp; + } + + /* memory mapping */ + if (!(dev->vendor == PCI_VENDOR_ID_SUN && + dev->device == PCI_DEVICE_ID_SUN_EBUS)) { + pcic_map_pci_device(dev); + } + + /* irq */ +#define SETIRQ(vend,devid,irqn) \ + if (dev->vendor==vend && dev->device==devid) dev->irq = irqn; + + SETIRQ(PCI_VENDOR_ID_SUN,PCI_DEVICE_ID_SUN_HAPPYMEAL,3); + } + ebus_init(); +} + +/* Makes compiler happy */ +static volatile int pcic_timer_dummy; + +static void pcic_clear_clock_irq(void) +{ + pcic_timer_dummy = readl(pcic->pcic_regs+PCI_SYS_LIMIT); +} + +static void pcic_timer_handler (int irq, void *h, struct pt_regs *regs) +{ + pcic_clear_clock_irq(); + do_timer(regs); +} + +#define USECS_PER_JIFFY 10000 /* We have 100HZ "standard" timer for sparc */ +#define TICK_TIMER_LIMIT ((100*1000000/4)/100) + +__initfunc(void pci_time_init(void)) +{ + unsigned long v; + int timer_irq, irq; + + do_get_fast_time = pci_do_gettimeofday; + /* A hack until do_gettimeofday prototype is moved to arch specific headers + and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */ + ((unsigned int *)do_gettimeofday)[0] = + 0x10800000 | ((((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) >> 2) & 0x003fffff); + ((unsigned int *)do_gettimeofday)[1] = + 0x01000000; + BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM); + btfixup(); + + writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT); + /* PROM should set appropriate irq */ + v = readb(pcic->pcic_regs+PCI_COUNTER_IRQ); + timer_irq = PCI_COUNTER_IRQ_SYS(v); + writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), + pcic->pcic_regs+PCI_COUNTER_IRQ); + irq = request_irq(timer_irq, pcic_timer_handler, + (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL); + if (irq) { + prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); + prom_halt(); + } + __sti(); +} + +static __inline__ unsigned long do_gettimeoffset(void) +{ + unsigned long offset = 0; + + /* + * We devide all to 100 + * to have microsecond resolution and to avoid overflow + */ + unsigned long count = + readl(pcic->pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; + count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100); + + if(test_bit(TIMER_BH, &bh_active)) + offset = 1000000; + return offset + count; +} + +extern volatile unsigned long lost_ticks; + +static void pci_do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_and_cli(flags); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. lost_ticks is + * nonzero if the timer bottom half hasnt executed yet. + */ + if (lost_ticks) + tv->tv_usec += USECS_PER_JIFFY; + + restore_flags(flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +static void pci_do_settimeofday(struct timeval *tv) +{ + cli(); + tv->tv_usec -= do_gettimeoffset(); + if(tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + xtime = *tv; + time_state = TIME_BAD; + time_maxerror = 0x70000000; + time_esterror = 0x70000000; + sti(); +} + +#if 0 +static void watchdog_reset() { + writeb(0, pcic->pcic_regs+PCI_SYS_STATUS); +} +#endif + +#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) + +int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) +{ + unsigned int v; + + pcibios_read_config_dword (bus, device_fn, where&~3, &v); + *value = 0xff & (v >> (8*(where & 3))); + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_word (unsigned char bus, + unsigned char device_fn, + unsigned char where, unsigned short *value) +{ + unsigned int v; + if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; + + pcibios_read_config_dword (bus, device_fn, where&~3, &v); + *value = 0xffff & (v >> (8*(where & 3))); + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) +{ + unsigned long flags; + if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; + if (bus != 0 || + (device_fn != 0 && device_fn != 1 && device_fn != 0x80)) { + *value = 0xffffffff; + return PCIBIOS_SUCCESSFUL; + } + + /* FIXME: IGA haven't got high config memory addresses !!! */ + if (device_fn == 0x80 && where > PCI_INTERRUPT_LINE) { + *value = 0xffffffff; + return PCIBIOS_SUCCESSFUL; + } + + save_and_cli(flags); + writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr); + *value = readl(pcic->pcic_config_space_data + (where&4)); + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned char value) +{ + unsigned int v; + + pcibios_read_config_dword (bus, devfn, where&~3, &v); + v = (v & ~(0xff << (8*(where&3)))) | + ((0xff&(unsigned)value) << (8*(where&3))); + return pcibios_write_config_dword (bus, devfn, where&~3, v); +} + +int pcibios_write_config_word (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned short value) +{ + unsigned int v; + if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; + + pcibios_read_config_dword (bus, devfn, where&~3, &v); + v = (v & ~(0xffff << (8*(where&3)))) | + ((0xffff&(unsigned)value) << (8*(where&3))); + return pcibios_write_config_dword (bus, devfn, where&~3, v); +} + +int pcibios_write_config_dword (unsigned char bus, unsigned char devfn, + unsigned char where, unsigned int value) +{ + unsigned long flags; + if ((where&3) || bus != 0 || (devfn != 0 && devfn != 1 && devfn != 0x80)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + save_and_cli(flags); + writel(CONFIG_CMD(bus,devfn,where),pcic->pcic_config_space_addr); + writel(value, pcic->pcic_config_space_data + (where&4)); + restore_flags(flags); + return PCIBIOS_SUCCESSFUL; +} + +__initfunc(char *pcibios_setup(char *str)) +{ + return str; +} + +/* + * Following code added to handle extra PCI-related system calls + */ +asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + int err = 0; + + if(!suser()) + return -EPERM; + + lock_kernel(); + switch(len) { + case 1: + pcibios_read_config_byte(bus, dfn, off, &ubyte); + put_user(ubyte, (unsigned char *)buf); + break; + case 2: + pcibios_read_config_word(bus, dfn, off, &ushort); + put_user(ushort, (unsigned short *)buf); + break; + case 4: + pcibios_read_config_dword(bus, dfn, off, &uint); + put_user(uint, (unsigned int *)buf); + break; + + default: + err = -EINVAL; + break; + }; + unlock_kernel(); + + return err; +} + +asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + int err = 0; + + if(!suser()) + return -EPERM; + + lock_kernel(); + switch(len) { + case 1: + err = get_user(ubyte, (unsigned char *)buf); + if(err) + break; + pcibios_write_config_byte(bus, dfn, off, ubyte); + break; + + case 2: + err = get_user(ushort, (unsigned short *)buf); + if(err) + break; + pcibios_write_config_byte(bus, dfn, off, ushort); + break; + + case 4: + err = get_user(uint, (unsigned int *)buf); + if(err) + break; + pcibios_write_config_byte(bus, dfn, off, uint); + break; + + default: + err = -EINVAL; + break; + + }; + unlock_kernel(); + + return err; +} + +static inline unsigned long get_irqmask(int irq_nr) +{ + return 1 << irq_nr; +} + +static inline char *pcic_irq_itoa(unsigned int irq) +{ + static char buff[16]; + sprintf(buff, "%d", irq); + return buff; +} + +static void pcic_disable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + + mask = get_irqmask(irq_nr); + save_and_cli(flags); + writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); + restore_flags(flags); +} + +static void pcic_enable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + + mask = get_irqmask(irq_nr); + save_and_cli(flags); + writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); + restore_flags(flags); +} + +static void pcic_clear_profile_irq(int cpu) +{ + printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); +} + +static void pcic_load_profile_irq(int cpu, unsigned int limit) +{ + printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); +} + +/* We assume the caller is local cli()'d when these are called, or else + * very bizarre behavior will result. + */ +static void pcic_disable_pil_irq(unsigned int pil) +{ + writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); +} + +static void pcic_enable_pil_irq(unsigned int pil) +{ + writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); +} + +__initfunc(void sun4m_pci_init_IRQ(void)) +{ + BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM); +} + +__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +{ +} + +#endif diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index c52674431..3aeee6f6b 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.118 1998/08/04 20:48:47 davem Exp $ +/* $Id: process.c,v 1.126 1998/09/21 05:05:18 jj Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -61,8 +61,8 @@ asmlinkage int sys_idle(void) goto out; /* endless idle loop with no priority at all */ - current->priority = -100; - current->counter = -100; + current->priority = 0; + current->counter = 0; for (;;) { if (ARCH_SUN4C_SUN4) { static int count = HZ; @@ -108,16 +108,13 @@ out: /* This is being executed in task 0 'user space'. */ int cpu_idle(void *unused) { - extern volatile int smp_commenced; - - current->priority = -100; + current->priority = 0; while(1) { - srmmu_check_pgt_cache(); - run_task_queue(&tq_scheduler); - /* endless idle loop with no priority at all */ - current->counter = -100; - if(!smp_commenced || current->need_resched) - schedule(); + check_pgt_cache(); + run_task_queue(&tq_scheduler); + /* endless idle loop with no priority at all */ + current->counter = 0; + schedule(); } } @@ -176,8 +173,10 @@ void machine_restart(char * cmd) void machine_power_off(void) { +#ifdef CONFIG_SUN_AUXIO if (auxio_power_register) *auxio_power_register |= AUXIO_POWER_OFF; +#endif machine_halt(); } @@ -594,8 +593,44 @@ void dump_thread(struct pt_regs * regs, struct user * dump) */ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) { - /* Currently we report that we couldn't dump the fpu structure */ - return 0; + if (current->used_math == 0) { + memset(fpregs, 0, sizeof(*fpregs)); + fpregs->pr_q_entrysize = 8; + return 1; + } +#ifdef __SMP__ + if (current->flags & PF_USEDFPU) { + put_psr(get_psr() | PSR_EF); + fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, + ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + regs->psr &= ~(PSR_EF); + current->flags &= ~(PF_USEDFPU); + } +#else + if (current == last_task_used_math) { + put_psr(get_psr() | PSR_EF); + fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, + ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); + last_task_used_math = 0; + regs->psr &= ~(PSR_EF); + } +#endif + memcpy(&fpregs->pr_fr.pr_regs[0], + ¤t->tss.float_regs[0], + (sizeof(unsigned long) * 32)); + fpregs->pr_fsr = current->tss.fsr; + fpregs->pr_qcnt = current->tss.fpqdepth; + fpregs->pr_q_entrysize = 8; + fpregs->pr_en = 1; + if(fpregs->pr_qcnt != 0) { + memcpy(&fpregs->pr_q[0], + ¤t->tss.fpqueue[0], + sizeof(struct fpq) * fpregs->pr_qcnt); + } + /* Zero out the rest. */ + memset(&fpregs->pr_q[fpregs->pr_qcnt], 0, + sizeof(struct fpq) * (32 - fpregs->pr_qcnt)); + return 1; } /* diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 257b1c086..84190cf5a 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.99 1998/07/28 16:52:45 jj Exp $ +/* $Id: setup.c,v 1.103 1998/09/21 05:05:23 jj Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -332,9 +332,6 @@ __initfunc(void setup_arch(char **cmdline_p, switch(sparc_cpu_model) { case sun4: printk("SUN4\n"); -#ifdef CONFIG_SUN4_FORCECONSOLE - register_console(&prom_console); -#endif packed = 0; break; case sun4c: @@ -443,8 +440,14 @@ __initfunc(void setup_arch(char **cmdline_p, serial_console = 1; } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) { serial_console = 2; + } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) { + prom_printf("MrCoffee ttya\n"); + serial_console = 1; + } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) { + serial_console = 0; + prom_printf("MrCoffee keyboard\n"); } else { - prom_printf("Inconsistent console\n"); + prom_printf("Inconsistent or unknown console\n"); prom_halt(); } } diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 357d30af5..287ed6cdc 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.82 1998/07/31 05:18:51 jj Exp $ +/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -75,6 +75,7 @@ struct new_signal_frame { __siginfo_fpu_t *fpu_save; unsigned long insns [2] __attribute__ ((aligned (8))); unsigned int extramask[_NSIG_WORDS - 1]; + unsigned int extra_size; /* Should be 0 */ __siginfo_fpu_t fpu_state; }; @@ -86,6 +87,7 @@ struct rt_signal_frame { __siginfo_fpu_t *fpu_save; unsigned int insns [2]; stack_t stack; + unsigned int extra_size; /* Should be 0 */ __siginfo_fpu_t fpu_state; }; @@ -203,16 +205,19 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) #endif current->used_math = 1; current->flags &= ~PF_USEDFPU; + + if (verify_area (VERIFY_READ, fpu, sizeof(*fpu))) + return -EFAULT; - err = copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0], - (sizeof(unsigned long) * 32)); + err = __copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0], + (sizeof(unsigned long) * 32)); err |= __get_user(current->tss.fsr, &fpu->si_fsr); err |= __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth); if (current->tss.fpqdepth != 0) - err |= copy_from_user(¤t->tss.fpqueue[0], - &fpu->si_fpqueue[0], - ((sizeof(unsigned long) + - (sizeof(unsigned long *)))*16)); + err |= __copy_from_user(¤t->tss.fpqueue[0], + &fpu->si_fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); return err; } @@ -241,7 +246,7 @@ static inline void do_new_sigreturn (struct pt_regs *regs) /* 2. Restore the state */ up_psr = regs->psr; - err |= copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)); + err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)); /* User can only change condition codes and FPU enabling in %psr. */ regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) @@ -250,14 +255,14 @@ static inline void do_new_sigreturn (struct pt_regs *regs) err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) - err |= restore_fpu_state(regs, sf->fpu_save); + err |= restore_fpu_state(regs, fpu_save); /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ err |= __get_user(set.sig[0], &sf->info.si_mask); - err |= copy_from_user(&set.sig[1], &sf->extramask, - (_NSIG_WORDS-1) * sizeof(unsigned int)); + err |= __copy_from_user(&set.sig[1], &sf->extramask, + (_NSIG_WORDS-1) * sizeof(unsigned int)); if (err) goto segv_and_exit; @@ -270,8 +275,6 @@ static inline void do_new_sigreturn (struct pt_regs *regs) return; segv_and_exit: - /* Ugh, we need to grab master lock in these rare cases ;-( */ - lock_kernel(); do_exit(SIGSEGV); } @@ -305,8 +308,8 @@ asmlinkage void do_sigreturn(struct pt_regs *regs) */ err |= __get_user(set.sig[0], &scptr->sigc_mask); /* Note that scptr + 1 points to extramask */ - err |= copy_from_user(&set.sig[1], scptr + 1, - (_NSIG_WORDS - 1) * sizeof(unsigned int)); + err |= __copy_from_user(&set.sig[1], scptr + 1, + (_NSIG_WORDS - 1) * sizeof(unsigned int)); if (err) goto segv_and_exit; @@ -352,7 +355,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) (((unsigned long) sf) & 0x03)) goto segv; - err = get_user(pc, &sf->regs.pc); + err = __get_user(pc, &sf->regs.pc); err |= __get_user(npc, &sf->regs.npc); err |= ((pc | npc) & 0x03); @@ -366,8 +369,8 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs) err |= __get_user(fpu_save, &sf->fpu_save); if(fpu_save) - err |= restore_fpu_state(regs, &sf->fpu_state); - err |= copy_from_user(&set, &sf->mask, sizeof(sigset_t)); + err |= restore_fpu_state(regs, fpu_save); + err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t)); @@ -423,7 +426,7 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, { struct signal_sframe *sframep; struct sigcontext *sc; - int window = 0; + int window = 0, err; synchronize_user_stack(); sframep = (struct signal_sframe *)get_sigframe(sa, regs, SF_ALIGNEDSZ); @@ -443,58 +446,63 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, sc = &sframep->sig_context; /* We've already made sure frame pointer isn't in kernel space... */ - __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), &sc->sigc_onstack); - __put_user(oldset->sig[0], &sc->sigc_mask); - __copy_to_user(sframep->extramask, &oldset->sig[1], - (_NSIG_WORDS - 1) * sizeof(unsigned int)); - __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); - __put_user(pc, &sc->sigc_pc); - __put_user(npc, &sc->sigc_npc); - __put_user(regs->psr, &sc->sigc_psr); - __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); - __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); - __put_user(current->tss.w_saved, &sc->sigc_oswins); + err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), + &sc->sigc_onstack); + err |= __put_user(oldset->sig[0], &sc->sigc_mask); + err |= __copy_to_user(sframep->extramask, &oldset->sig[1], + (_NSIG_WORDS - 1) * sizeof(unsigned int)); + err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); + err |= __put_user(pc, &sc->sigc_pc); + err |= __put_user(npc, &sc->sigc_npc); + err |= __put_user(regs->psr, &sc->sigc_psr); + err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); + err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); + err |= __put_user(current->tss.w_saved, &sc->sigc_oswins); if(current->tss.w_saved) for(window = 0; window < current->tss.w_saved; window++) { sc->sigc_spbuf[window] = (char *)current->tss.rwbuf_stkptrs[window]; - copy_to_user(&sc->sigc_wbuf[window], - ¤t->tss.reg_window[window], - sizeof(struct reg_window)); + err |= __copy_to_user(&sc->sigc_wbuf[window], + ¤t->tss.reg_window[window], + sizeof(struct reg_window)); } else - copy_to_user(sframep, (char *)regs->u_regs[UREG_FP], - sizeof(struct reg_window)); + err |= __copy_to_user(sframep, (char *)regs->u_regs[UREG_FP], + sizeof(struct reg_window)); current->tss.w_saved = 0; /* So process is allowed to execute. */ - __put_user(signr, &sframep->sig_num); + err |= __put_user(signr, &sframep->sig_num); if(signr == SIGSEGV || signr == SIGILL || signr == SIGFPE || signr == SIGBUS || signr == SIGEMT) { - __put_user(current->tss.sig_desc, &sframep->sig_code); - __put_user(current->tss.sig_address, &sframep->sig_address); + err |= __put_user(current->tss.sig_desc, &sframep->sig_code); + err |= __put_user(current->tss.sig_address, &sframep->sig_address); } else { - __put_user(0, &sframep->sig_code); - __put_user(0, &sframep->sig_address); + err |= __put_user(0, &sframep->sig_code); + err |= __put_user(0, &sframep->sig_address); } - __put_user(sc, &sframep->sig_scptr); + err |= __put_user(sc, &sframep->sig_scptr); + if (err) + goto sigsegv; + regs->u_regs[UREG_FP] = (unsigned long) sframep; regs->pc = (unsigned long) sa->sa_handler; regs->npc = (regs->pc + 4); return; sigill_and_return: - /* Ugh, we need to grab master lock in these rare cases ;-( */ - lock_kernel(); do_exit(SIGILL); +sigsegv: + do_exit(SIGSEGV); } -static inline void +static inline int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { + int err = 0; #ifdef __SMP__ if (current->flags & PF_USEDFPU) { put_psr(get_psr() | PSR_EF); @@ -512,15 +520,16 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) regs->psr &= ~(PSR_EF); } #endif - copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], - (sizeof(unsigned long) * 32)); - __put_user(current->tss.fsr, &fpu->si_fsr); - __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); + err |= __copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], + (sizeof(unsigned long) * 32)); + err |= __put_user(current->tss.fsr, &fpu->si_fsr); + err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); if (current->tss.fpqdepth != 0) - copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0], - ((sizeof(unsigned long) + - (sizeof(unsigned long *)))*16)); + err |= __copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); current->used_math = 0; + return err; } static inline void @@ -528,7 +537,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset) { struct new_signal_frame *sf; - int sigframe_size; + int sigframe_size, err; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -551,20 +560,24 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, } /* 2. Save the current process state */ - copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs)); + err = __copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs)); + + err |= __put_user(0, &sf->extra_size); if (current->used_math) { - save_fpu_state(regs, &sf->fpu_state); - __put_user(&sf->fpu_state, &sf->fpu_save); + err |= save_fpu_state(regs, &sf->fpu_state); + err |= __put_user(&sf->fpu_state, &sf->fpu_save); } else { - __put_user(0, &sf->fpu_save); + err |= __put_user(0, &sf->fpu_save); } - __put_user(oldset->sig[0], &sf->info.si_mask); - __copy_to_user(sf->extramask, &oldset->sig[1], - (_NSIG_WORDS - 1) * sizeof(unsigned int)); - copy_to_user(sf, (char *) regs->u_regs [UREG_FP], - sizeof (struct reg_window)); + err |= __put_user(oldset->sig[0], &sf->info.si_mask); + err |= __copy_to_user(sf->extramask, &oldset->sig[1], + (_NSIG_WORDS - 1) * sizeof(unsigned int)); + err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP], + sizeof (struct reg_window)); + if (err) + goto sigsegv; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; @@ -581,8 +594,13 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, else { regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + /* mov __NR_sigreturn, %g1 */ + err |= __put_user(0x821020d8, &sf->insns[0]); + + /* t 0x10 */ + err |= __put_user(0x91d02010, &sf->insns[1]); + if (err) + goto sigsegv; /* Flush instruction space. */ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); @@ -590,8 +608,9 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, return; sigill_and_return: - lock_kernel(); do_exit(SIGILL); +sigsegv: + do_exit(SIGSEGV); } static inline void @@ -601,7 +620,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, struct rt_signal_frame *sf; int sigframe_size; unsigned int psr; - int i; + int err; synchronize_user_stack(); sigframe_size = RT_ALIGNEDSZ; @@ -613,30 +632,33 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, if(current->tss.w_saved != 0) goto sigill; - put_user(regs->pc, &sf->regs.pc); - __put_user(regs->npc, &sf->regs.npc); - __put_user(regs->y, &sf->regs.y); + err = __put_user(regs->pc, &sf->regs.pc); + err |= __put_user(regs->npc, &sf->regs.npc); + err |= __put_user(regs->y, &sf->regs.y); psr = regs->psr; if(current->used_math) psr |= PSR_EF; - __put_user(psr, &sf->regs.psr); - for(i = 0; i < 16; i++) - __put_user(regs->u_regs[i], &sf->regs.u_regs[i]); + err |= __put_user(psr, &sf->regs.psr); + err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs)); + err |= __put_user(0, &sf->extra_size); + if(psr & PSR_EF) { - save_fpu_state(regs, &sf->fpu_state); - __put_user(&sf->fpu_state, &sf->fpu_save); + err |= save_fpu_state(regs, &sf->fpu_state); + err |= __put_user(&sf->fpu_state, &sf->fpu_save); } else { - __put_user(0, &sf->fpu_save); + err |= __put_user(0, &sf->fpu_save); } - __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t)); + err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t)); /* Setup sigaltstack */ - __put_user(current->sas_ss_sp, &sf->stack.ss_sp); - __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); - __put_user(current->sas_ss_size, &sf->stack.ss_size); + err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); + err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); - copy_to_user(sf, (char *) regs->u_regs [UREG_FP], - sizeof (struct reg_window)); + err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP], + sizeof (struct reg_window)); + if (err) + goto sigsegv; regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; @@ -650,8 +672,13 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, else { regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + /* mov __NR_sigreturn, %g1 */ + err |= __put_user(0x821020d8, &sf->insns[0]); + + /* t 0x10 */ + err |= __put_user(0x91d02010, &sf->insns[1]); + if (err) + goto sigsegv; /* Flush instruction space. */ flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); @@ -659,8 +686,9 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, return; sigill: - lock_kernel(); do_exit(SIGILL); +sigsegv: + do_exit(SIGSEGV); } /* Setup a Solaris stack frame */ @@ -675,7 +703,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, svr4_gwindows_t *gw; svr4_ucontext_t *uc; svr4_sigset_t setv; - int window = 0; + int window = 0, err; synchronize_user_stack(); sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, SVR4_SF_ALIGNED + REGWIN_SZ); @@ -688,7 +716,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, } /* Start with a clean frame pointer and fill it */ - clear_user(sfp, sizeof (*sfp)); + err = __clear_user(sfp, sizeof (*sfp)); /* Setup convenience variables */ si = &sfp->si; @@ -706,32 +734,32 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, if (_NSIG_WORDS >= 4) { setv.sigbits[2] = oldset->sig[2]; setv.sigbits[3] = oldset->sig[3]; - __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); } else - __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); + err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); /* Store registers */ - __put_user(regs->pc, &((*gr) [SVR4_PC])); - __put_user(regs->npc, &((*gr) [SVR4_NPC])); - __put_user(regs->psr, &((*gr) [SVR4_PSR])); - __put_user(regs->y, &((*gr) [SVR4_Y])); + err |= __put_user(regs->pc, &((*gr) [SVR4_PC])); + err |= __put_user(regs->npc, &((*gr) [SVR4_NPC])); + err |= __put_user(regs->psr, &((*gr) [SVR4_PSR])); + err |= __put_user(regs->y, &((*gr) [SVR4_Y])); /* Copy g [1..7] and o [0..7] registers */ - copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7); - copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8); + err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7); + err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8); /* Setup sigaltstack */ - __put_user(current->sas_ss_sp, &uc->stack.sp); - __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); - __put_user(current->sas_ss_size, &uc->stack.size); + err |= __put_user(current->sas_ss_sp, &uc->stack.sp); + err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); + err |= __put_user(current->sas_ss_size, &uc->stack.size); /* Save the currently window file: */ /* 1. Link sfp->uc->gwins to our windows */ - __put_user(gw, &mc->gwin); + err |= __put_user(gw, &mc->gwin); /* 2. Number of windows to restore at setcontext (): */ - __put_user(current->tss.w_saved, &gw->count); + err |= __put_user(current->tss.w_saved, &gw->count); /* 3. Save each valid window * Currently, it makes a copy of the windows from the kernel copy. @@ -745,9 +773,11 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, * to flush the user windows. */ for(window = 0; window < current->tss.w_saved; window++) { - __put_user((int *) &(gw->win [window]), &gw->winptr [window]); - copy_to_user(&gw->win [window], ¤t->tss.reg_window [window], sizeof (svr4_rwindow_t)); - __put_user(0, gw->winptr [window]); + err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]); + err |= __copy_to_user(&gw->win [window], + ¤t->tss.reg_window [window], + sizeof (svr4_rwindow_t)); + err |= __put_user(0, gw->winptr [window]); } /* 4. We just pay attention to the gw->count field on setcontext */ @@ -758,8 +788,10 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, * that much currently, should use those that David already * is providing with tss.sig_desc */ - __put_user(signr, &si->siginfo.signo); - __put_user(SVR4_SINOINFO, &si->siginfo.code); + err |= __put_user(signr, &si->siginfo.signo); + err |= __put_user(SVR4_SINOINFO, &si->siginfo.code); + if (err) + goto sigsegv; regs->u_regs[UREG_FP] = (unsigned long) sfp; regs->pc = (unsigned long) sa->sa_handler; @@ -772,10 +804,13 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, if (regs->u_regs [14]){ struct reg_window *rw = (struct reg_window *) regs->u_regs [14]; - __put_user(signr, &rw->ins [0]); - __put_user(si, &rw->ins [1]); - __put_user(uc, &rw->ins [2]); - __put_user(sfp, &rw->ins [6]); /* frame pointer */ + err |= __put_user(signr, &rw->ins [0]); + err |= __put_user(si, &rw->ins [1]); + err |= __put_user(uc, &rw->ins [2]); + err |= __put_user(sfp, &rw->ins [6]); /* frame pointer */ + if (err) + goto sigsegv; + regs->u_regs[UREG_I0] = signr; regs->u_regs[UREG_I1] = (uint) si; regs->u_regs[UREG_I2] = (uint) uc; @@ -783,8 +818,9 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, return; sigill_and_return: - lock_kernel(); do_exit(SIGILL); +sigsegv: + do_exit(SIGSEGV); } asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) @@ -792,13 +828,15 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) svr4_gregset_t *gr; svr4_mcontext_t *mc; svr4_sigset_t setv; + int err = 0; synchronize_user_stack(); if (current->tss.w_saved) goto sigsegv_and_return; - if(clear_user(uc, sizeof (*uc))) + err = clear_user(uc, sizeof (*uc)); + if (err) return -EFAULT; /* Setup convenience variables */ @@ -810,32 +848,31 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs) if (_NSIG_WORDS >= 4) { setv.sigbits[2] = current->blocked.sig[2]; setv.sigbits[3] = current->blocked.sig[3]; - __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); } else - __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); + err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); /* Store registers */ - __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]); - __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]); - __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]); - __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); + err |= __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]); + err |= __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]); + err |= __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]); + err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); /* Copy g [1..7] and o [0..7] registers */ - copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7); - copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8); + err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7); + err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8); /* Setup sigaltstack */ - __put_user(current->sas_ss_sp, &uc->stack.sp); - __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); - __put_user(current->sas_ss_size, &uc->stack.size); + err |= __put_user(current->sas_ss_sp, &uc->stack.sp); + err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); + err |= __put_user(current->sas_ss_size, &uc->stack.size); /* The register file is not saved * we have already stuffed all of it with sync_user_stack */ - return 0; + return (err ? -EFAULT : 0); sigsegv_and_return: - lock_kernel(); do_exit(SIGSEGV); } @@ -905,18 +942,19 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs) spin_unlock_irq(¤t->sigmask_lock); regs->pc = pc; regs->npc = npc | 1; - __get_user(regs->y, &((*gr) [SVR4_Y])); - __get_user(psr, &((*gr) [SVR4_PSR])); + err |= __get_user(regs->y, &((*gr) [SVR4_Y])); + err |= __get_user(psr, &((*gr) [SVR4_PSR])); regs->psr &= ~(PSR_ICC); regs->psr |= (psr & PSR_ICC); /* Restore g[1..7] and o[0..7] registers */ - copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7); - copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8); - return 0; + err |= __copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], + sizeof (long) * 7); + err |= __copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], + sizeof (long) * 8); + return (err ? -EFAULT : 0); sigsegv_and_return: - lock_kernel(); do_exit(SIGSEGV); } @@ -1069,7 +1107,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); - if(current->binfmt->core_dump(signr, regs)) + if(current->binfmt && + current->binfmt->core_dump && + current->binfmt->core_dump(signr, regs)) exit_code |= 0x80; unlock_kernel(); } diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 0d9c43e9d..f77d823aa 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -64,6 +64,9 @@ volatile int __cpu_logical_map[NR_CPUS]; /* Kernel spinlock */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +/* Used to make bitops atomic */ +unsigned char bitops_spinlock = 0; + volatile unsigned long ipi_count; volatile int smp_process_available=0; @@ -159,7 +162,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm) local_flush_tlb_mm(mm); } else { xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm); - if(mm->count == 1 && current->mm == mm) + if(atomic_read(&mm->count) == 1 && current->mm == mm) mm->cpu_vm_mask = (1 << smp_processor_id()); } } @@ -275,3 +278,26 @@ int setup_profiling_timer(unsigned int multiplier) return 0; } + +int smp_bogo_info(char *buf) +{ + int len = 0, i; + + for (i = 0; i < NR_CPUS; i++) + if (cpu_present_map & (1 << i)) + len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", + i, + cpu_data[i].udelay_val/500000, + (cpu_data[i].udelay_val/5000)%100); + return len; +} + +int smp_info(char *buf) +{ + int len = 0, i; + + for (i = 0; i < NR_CPUS; i++) + if (cpu_present_map & (1 << i)) + len += sprintf(buf + len, "CPU%d\t\t: online\n", i); + return len; +} diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index e6aad243d..43f963217 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.65 1998/06/04 09:54:50 jj Exp $ +/* $Id: sparc_ksyms.c,v 1.73 1998/11/06 13:49:54 jj Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -41,6 +41,7 @@ #endif #include <asm/a.out.h> #include <asm/spinlock.h> +#include <asm/io-unit.h> struct poll { int fd; @@ -68,6 +69,10 @@ extern int __ashrdi3(int, int); extern void dump_thread(struct pt_regs *, struct user *); +#ifdef __SMP__ +extern spinlock_t kernel_flag; +#endif + /* One thing to note is that the way the symbols of the mul/div * support routines are named is a mess, they all start with * a '.' which makes it a bitch to export, here is the trick: @@ -85,48 +90,27 @@ __attribute__((section("__ksymtab"))) = \ /* used by various drivers */ EXPORT_SYMBOL(sparc_cpu_model); -#ifdef __SMP__ -EXPORT_SYMBOL(klock_info); -#endif -EXPORT_SYMBOL_PRIVATE(_lock_kernel); -EXPORT_SYMBOL_PRIVATE(_unlock_kernel); EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor); #ifdef SPIN_LOCK_DEBUG -EXPORT_SYMBOL(_spin_lock); -EXPORT_SYMBOL(_spin_unlock); +EXPORT_SYMBOL(_do_spin_lock); +EXPORT_SYMBOL(_do_spin_unlock); EXPORT_SYMBOL(_spin_trylock); -EXPORT_SYMBOL(_spin_lock_irq); -EXPORT_SYMBOL(_spin_unlock_irq); -EXPORT_SYMBOL(_spin_lock_irqsave); -EXPORT_SYMBOL(_spin_unlock_irqrestore); -EXPORT_SYMBOL(_read_lock); -EXPORT_SYMBOL(_read_unlock); -EXPORT_SYMBOL(_read_lock_irq); -EXPORT_SYMBOL(_read_unlock_irq); -EXPORT_SYMBOL(_read_lock_irqsave); -EXPORT_SYMBOL(_read_unlock_irqrestore); -EXPORT_SYMBOL(_write_lock); -EXPORT_SYMBOL(_write_unlock); -EXPORT_SYMBOL(_write_lock_irq); -EXPORT_SYMBOL(_write_unlock_irq); -EXPORT_SYMBOL(_write_lock_irqsave); -EXPORT_SYMBOL(_write_unlock_irqrestore); +EXPORT_SYMBOL(_do_read_lock); +EXPORT_SYMBOL(_do_read_unlock); +EXPORT_SYMBOL(_do_write_lock); +EXPORT_SYMBOL(_do_write_unlock); #else EXPORT_SYMBOL_PRIVATE(_rw_read_enter); EXPORT_SYMBOL_PRIVATE(_rw_read_exit); EXPORT_SYMBOL_PRIVATE(_rw_write_enter); #endif -EXPORT_SYMBOL(__sparc_bh_counter); #ifdef __SMP__ #ifdef DEBUG_IRQLOCK -EXPORT_SYMBOL(irq_enter); -EXPORT_SYMBOL(irq_exit); +EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_cli); #else -EXPORT_SYMBOL_PRIVATE(_irq_enter); -EXPORT_SYMBOL_PRIVATE(_irq_exit); EXPORT_SYMBOL_PRIVATE(_global_restore_flags); EXPORT_SYMBOL_PRIVATE(_global_sti); EXPORT_SYMBOL_PRIVATE(_global_cli); @@ -134,7 +118,10 @@ EXPORT_SYMBOL_PRIVATE(_global_cli); #endif EXPORT_SYMBOL(page_offset); + +#ifndef CONFIG_SUN4 EXPORT_SYMBOL(stack_top); +#endif /* Atomic operations. */ EXPORT_SYMBOL_PRIVATE(_atomic_add); @@ -148,14 +135,19 @@ EXPORT_SYMBOL_PRIVATE(_set_le_bit); EXPORT_SYMBOL_PRIVATE(_clear_le_bit); /* IRQ implementation. */ -EXPORT_SYMBOL(local_irq_count); #ifdef __SMP__ +EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(global_irq_lock); EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(global_bh_count); +EXPORT_SYMBOL(sparc_bh_lock); EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(synchronize_bh); #endif +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(udelay); EXPORT_SYMBOL(mstk48t02_regs); @@ -166,6 +158,8 @@ EXPORT_SYMBOL(request_fast_irq); EXPORT_SYMBOL(sparc_alloc_io); EXPORT_SYMBOL(sparc_free_io); EXPORT_SYMBOL(io_remap_page_range); +EXPORT_SYMBOL(iounit_map_dma_init); +EXPORT_SYMBOL(iounit_map_dma_page); /* Btfixup stuff cannot have versions, it would be complicated too much */ #ifndef __SMP__ @@ -227,7 +221,7 @@ EXPORT_SYMBOL(__prom_getsibling); /* sparc library symbols */ EXPORT_SYMBOL(bcopy); -EXPORT_SYMBOL(memscan); +EXPORT_SYMBOL_NOVERS(memscan); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strcpy); @@ -235,7 +229,7 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL_NOVERS(strncmp); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strpbrk); diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index cda7564dc..cafd61955 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c @@ -121,7 +121,7 @@ static void sun4c_clear_clock_irq(void) { volatile unsigned int clear_intr; #ifdef CONFIG_SUN4 - if( idprom->id_machtype == SM_SUN4 | SM_4_260 ) + if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) clear_intr = sun4_timer.timer_limit10; else #endif @@ -146,7 +146,7 @@ __initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct * the cache chip on the sun4c. */ #ifdef CONFIG_SUN4 - if (idprom->id_machtype == SM_SUN4 | SM_4_260) + if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) sun4c_timers = &sun4_timer; else #endif @@ -171,7 +171,10 @@ __initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct prom_halt(); } +#if 0 + /* This does not work on 4/330 */ sun4c_enable_irq(10); +#endif claim_ticker14(NULL, PROFILE_IRQ, 0); } diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 3a37df0c9..93474714a 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.14 1998/06/04 09:54:47 jj Exp $ +/* $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -284,11 +284,12 @@ int sun4d_request_irq(unsigned int irq, /* If this is flagged as statically allocated then we use our * private struct which is never freed. */ - if (irqflags & SA_STATIC_ALLOC) + if (irqflags & SA_STATIC_ALLOC) { if (static_irq_count < MAX_STATIC_ALLOC) action = &static_irqaction[static_irq_count++]; else printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname); + } if (action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), @@ -437,8 +438,13 @@ __initfunc(static void sun4d_init_timers(void (*counter_fn)(int, void *, struct int cpu; /* Map the User Timer registers. */ - sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0, +#ifdef __SMP__ + sun4d_timers = sparc_alloc_io(CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT, 0, PAGE_SIZE, "user timer", 0xf, 0x0); +#else + sun4d_timers = sparc_alloc_io(CSR_BASE(0)+BW_TIMER_LIMIT, 0, + PAGE_SIZE, "user timer", 0xf, 0x0); +#endif sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); master_l10_counter = &sun4d_timers->l10_cur_count; diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 5563a0cc6..af0aaf58d 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -8,6 +8,7 @@ #include <asm/head.h> +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/tasks.h> @@ -57,7 +58,6 @@ extern unsigned char boot_cpu_id; extern int smp_activated; extern volatile int cpu_number_map[NR_CPUS]; extern volatile int __cpu_logical_map[NR_CPUS]; -extern struct klock_info klock_info; extern volatile unsigned long ipi_count; extern volatile int smp_process_available; extern volatile int smp_commenced; @@ -71,31 +71,6 @@ extern int __smp4d_processor_id(void); #define SMP_PRINTK(x) #endif -int smp4d_bogo_info(char *buf) -{ - int len = 0, i; - - for (i = 0; i < NR_CPUS; i++) - if (cpu_present_map & (1 << i)) - len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", - i, - cpu_data[i].udelay_val/500000, - (cpu_data[i].udelay_val/5000)%100); - return len; -} - -int smp4d_info(char *buf) -{ - int len = 0, i; - - for (i = 0; i < NR_CPUS; i++) - if (cpu_present_map & (1 << i)) - len += sprintf(buf + len, "CPU%d\t\t: %s\n", - i, - (klock_info.akp == i) ? "akp" : "online"); - return len; -} - static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val) { __asm__ __volatile__("swap [%1], %0\n\t" : @@ -193,10 +168,6 @@ __initfunc(void smp4d_boot_cpus(void)) printk("Entering SMP Mode...\n"); - smp_penguin_ctable.which_io = 0; - smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; - smp_penguin_ctable.reg_size = 0; - for (i = 0; i < NR_CPUS; i++) cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data; @@ -216,7 +187,6 @@ __initfunc(void smp4d_boot_cpus(void)) mid_xlate[i] = i; cpu_number_map[boot_cpu_id] = 0; __cpu_logical_map[0] = boot_cpu_id; - klock_info.akp = boot_cpu_id; current->processor = boot_cpu_id; smp_store_cpu_info(boot_cpu_id); smp_setup_percpu_timer(); @@ -246,7 +216,16 @@ __initfunc(void smp4d_boot_cpus(void)) for (no = 0; no < linux_num_cpus; no++) if (linux_cpus[no].mid == i) break; - + + /* + * Initialize the contexts table + * Since the call to prom_startcpu() trashes the structure, + * we need to re-initialize it for each cpu + */ + smp_penguin_ctable.which_io = 0; + smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; + smp_penguin_ctable.reg_size = 0; + /* whirrr, whirrr, whirrrrrrrrr... */ SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, linux_cpus[no].prom_node)); local_flush_cache_all(); @@ -256,10 +235,10 @@ __initfunc(void smp4d_boot_cpus(void)) SMP_PRINTK(("prom_startcpu returned :)\n")); /* wheee... it's going... */ - for(timeout = 0; timeout < 5000000; timeout++) { + for(timeout = 0; timeout < 10000; timeout++) { if(cpu_callin_map[i]) break; - udelay(100); + udelay(200); } if(cpu_callin_map[i]) { @@ -436,6 +415,8 @@ void smp4d_message_pass(int target, int msg, unsigned long data, int wait) /* Protects counters touched during level14 ticker */ static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; +#ifdef CONFIG_PROFILE + /* 32-bit Sparc specific profiling function. */ static inline void sparc_do_profile(unsigned long pc) { @@ -454,6 +435,8 @@ static inline void sparc_do_profile(unsigned long pc) } } +#endif + extern unsigned int prof_multiplier[NR_CPUS]; extern unsigned int prof_counter[NR_CPUS]; @@ -479,9 +462,10 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) show_leds(cpu); } +#ifdef CONFIG_PROFILE if(!user_mode(regs)) sparc_do_profile(regs->pc); - +#endif if(!--prof_counter[cpu]) { int user = user_mode(regs); if(current->pid) { @@ -559,8 +543,6 @@ __initfunc(void sun4d_init_smp(void)) BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(smp_message_pass, smp4d_message_pass, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_bogo_info, smp4d_bogo_info, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_info, smp4d_info, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(__smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); for (i = 0; i < NR_CPUS; i++) { diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 68c04014f..bd6fc8e20 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -47,10 +47,12 @@ unsigned long *irq_rcvreg = &dummy; * * take an encoded intr value and lookup if it's valid * then get the mask bits that match from irq_mask + * + * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. */ static unsigned char irq_xlate[32] = { /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ - 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 0, 0, 7, + 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7, 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 }; diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 597ee7665..183ea7323 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -53,7 +53,6 @@ extern unsigned char boot_cpu_id; extern int smp_activated; extern volatile int cpu_number_map[NR_CPUS]; extern volatile int __cpu_logical_map[NR_CPUS]; -extern struct klock_info klock_info; extern volatile unsigned long ipi_count; extern volatile int smp_process_available; extern volatile int smp_commenced; @@ -67,30 +66,6 @@ extern int __smp4m_processor_id(void); #define SMP_PRINTK(x) #endif -int smp4m_bogo_info(char *buf) -{ - return sprintf(buf, - "Cpu0Bogo\t: %lu.%02lu\n" - "Cpu1Bogo\t: %lu.%02lu\n" - "Cpu2Bogo\t: %lu.%02lu\n" - "Cpu3Bogo\t: %lu.%02lu\n", - cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100, - cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100, - cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100, - cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100); -} - -int smp4m_info(char *buf) -{ - return sprintf(buf, -" CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n" -"State: %s\t\t%s\t\t%s\t\t%s\n", -(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline", -(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline", -(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline", -(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline"); -} - static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val) { __asm__ __volatile__("swap [%1], %0\n\t" : @@ -168,10 +143,6 @@ __initfunc(void smp4m_boot_cpus(void)) printk("Entering SMP Mode...\n"); - smp_penguin_ctable.which_io = 0; - smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; - smp_penguin_ctable.reg_size = 0; - for (i = 0; i < NR_CPUS; i++) cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data; @@ -186,7 +157,6 @@ __initfunc(void smp4m_boot_cpus(void)) mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8); cpu_number_map[boot_cpu_id] = 0; __cpu_logical_map[0] = boot_cpu_id; - klock_info.akp = boot_cpu_id; current->processor = boot_cpu_id; smp_store_cpu_info(boot_cpu_id); set_irq_udt(mid_xlate[boot_cpu_id]); @@ -215,6 +185,15 @@ __initfunc(void smp4m_boot_cpus(void)) /* See trampoline.S for details... */ entry += ((i-1) * 3); + /* + * Initialize the contexts table + * Since the call to prom_startcpu() trashes the structure, + * we need to re-initialize it for each cpu + */ + smp_penguin_ctable.which_io = 0; + smp_penguin_ctable.phys_addr = (unsigned int) srmmu_ctx_table_phys; + smp_penguin_ctable.reg_size = 0; + /* whirrr, whirrr, whirrrrrrrrr... */ printk("Starting CPU %d at %p\n", i, entry); mid_xlate[i] = (linux_cpus[i].mid & ~8); @@ -223,10 +202,10 @@ __initfunc(void smp4m_boot_cpus(void)) &smp_penguin_ctable, 0, (char *)entry); /* wheee... it's going... */ - for(timeout = 0; timeout < 5000000; timeout++) { + for(timeout = 0; timeout < 10000; timeout++) { if(cpu_callin_map[i]) break; - udelay(100); + udelay(200); } if(cpu_callin_map[i]) { /* Another "Red Snapper". */ @@ -468,6 +447,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) if(!--prof_counter[cpu]) { int user = user_mode(regs); + if(current->pid) { update_one_process(current, 1, user, !user, cpu); @@ -534,7 +514,5 @@ __initfunc(void sun4m_init_smp(void)) BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current); BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(smp_message_pass, smp4m_message_pass, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_bogo_info, smp4m_bogo_info, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(smp_info, smp4m_info, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(__smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM); } diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c index deb1aa79e..2f0fe9ed7 100644 --- a/arch/sparc/kernel/sunos_ioctl.c +++ b/arch/sparc/kernel/sunos_ioctl.c @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl.c,v 1.30 1998/01/21 06:17:32 ecd Exp $ +/* $Id: sunos_ioctl.c,v 1.31 1998/10/25 19:31:04 davem Exp $ * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -218,7 +218,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) } #if 0 - if (cmd & 0xff00 == ('k' << 8)){ + if ((cmd & 0xff00) == ('k' << 8)) { printk ("[[KBIO: %8.8x\n", (unsigned int) cmd); } #endif diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 7529c679a..e5ea2e9b3 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.46 1998/08/03 23:58:01 davem Exp $ +/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -181,6 +181,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, struct file * file = NULL; unsigned long retval = -EBADF; + down(¤t->mm->mmap_sem); lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); @@ -206,6 +207,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, } } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, off); out_putf: @@ -213,6 +215,7 @@ out_putf: fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -298,6 +301,11 @@ sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, if (sigsetsize != sizeof(sigset_t)) return -EINVAL; + /* All tasks which use RT signals (effectively) use + * new style signals. + */ + current->tss.new_signal = 1; + if (act) { new_ka.ka_restorer = restorer; if (copy_from_user(&new_ka.sa, act, sizeof(*act))) diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index d54c9352d..086a473e3 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.91 1998/06/16 04:37:04 davem Exp $ +/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -68,6 +68,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, struct file * file = NULL; unsigned long retval, ret_type; + down(¤t->mm->mmap_sem); lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { @@ -118,6 +119,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, } } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, off); if(!ret_type) retval = ((retval < PAGE_OFFSET) ? 0 : retval); @@ -127,6 +129,7 @@ out_putf: fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -146,6 +149,7 @@ asmlinkage int sunos_brk(unsigned long brk) unsigned long rlim; unsigned long newbrk, oldbrk; + down(¤t->mm->mmap_sem); lock_kernel(); if(ARCH_SUN4C_SUN4) { if(brk >= 0x20000000 && brk < 0xe0000000) { @@ -212,6 +216,7 @@ asmlinkage int sunos_brk(unsigned long brk) retval = 0; out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -578,20 +583,16 @@ struct sunos_utsname { asmlinkage int sunos_uname(struct sunos_utsname *name) { - int ret = -EFAULT; - + int ret; down(&uts_sem); - if(!name) - goto out; - if(copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1)) - goto out; - copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); - put_user('\0', &name->nname[8]); - copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); - copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); - copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); - ret = 0; -out: + ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1); + if (!ret) { + ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); + ret |= __put_user('\0', &name->nname[8]); + ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); + ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); + ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); + } up(&uts_sem); return ret; } @@ -842,7 +843,7 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data) strncpy (linux_nfs_mount.hostname, the_name, 254); linux_nfs_mount.hostname [255] = 0; putname (the_name); - + dev = get_unnamed_dev (); ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount); @@ -859,6 +860,9 @@ sunos_mount(char *type, char *dir, int flags, void *data) int ret = -EINVAL; char *dev_fname = 0; + if (!capable (CAP_SYS_ADMIN)) + return -EPERM; + lock_kernel(); /* We don't handle the integer fs type */ if ((flags & SMNT_NEWTYPE) == 0) diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 08aae84c9..5508f850a 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.75 1998/07/28 13:07:48 jj Exp $ +/* $Id: systbls.S,v 1.80 1998/09/21 05:04:59 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -9,212 +9,156 @@ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) */ -#include <asm/cprefix.h> - .data .align 4 /* First, the Linux native syscall table. */ - .globl C_LABEL(sys_call_table) -C_LABEL(sys_call_table): -/*0*/ .long C_LABEL(sys_setup), C_LABEL(sys_exit), C_LABEL(sys_fork) - .long C_LABEL(sys_read), C_LABEL(sys_write) -/*5*/ .long C_LABEL(sys_open), C_LABEL(sys_close), C_LABEL(sys_wait4) - .long C_LABEL(sys_creat), C_LABEL(sys_link) -/*10*/ .long C_LABEL(sys_unlink), C_LABEL(sunos_execv), C_LABEL(sys_chdir) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_mknod) -/*15*/ .long C_LABEL(sys_chmod), C_LABEL(sys_lchown), C_LABEL(sparc_brk) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_lseek) -/*20*/ .long C_LABEL(sys_getpid), C_LABEL(sys_capget), C_LABEL(sys_capset) - .long C_LABEL(sys_setuid), C_LABEL(sys_getuid) -/*25*/ .long C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm) - .long C_LABEL(sys_sigaltstack), C_LABEL(sys_pause) -/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat) - .long C_LABEL(sys_sendfile), C_LABEL(sys_newlstat), C_LABEL(sys_dup) - .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid) - .long C_LABEL(sys_signal), C_LABEL(sys_geteuid) -/*50*/ .long C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_ioctl), C_LABEL(sys_reboot) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink) - .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot) - .long C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize) - .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_pread) - .long C_LABEL(sys_pwrite), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap) - .long C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getgroups) - .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_setitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_swapon) - .long C_LABEL(sys_getitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_sethostname) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_dup2), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) -/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_rt_sigreturn) - .long C_LABEL(sys_rt_sigaction), C_LABEL(sys_rt_sigprocmask) - .long C_LABEL(sys_rt_sigpending), C_LABEL(sys_rt_sigtimedwait) - .long C_LABEL(sys_rt_sigqueueinfo), C_LABEL(sys_rt_sigsuspend) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_getcwd), C_LABEL(sys_readv) - .long C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown) - .long C_LABEL(sys_fchmod), C_LABEL(sys_nis_syscall), C_LABEL(sys_setreuid) - .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate) - .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit) - .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_prctl) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) -/*150*/ .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_poll), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs) - .long C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_getdomainname), C_LABEL(sys_setdomainname) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_getdents), C_LABEL(sys_setsid) - .long C_LABEL(sys_fchdir), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_query_module) - .long C_LABEL(sys_setpgid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module) - .long C_LABEL(sys_personality), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask) -/*200*/ .long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat) - .long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_idle), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo) - .long C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_adjtimex), C_LABEL(sys_sigprocmask) - .long C_LABEL(sys_create_module), C_LABEL(sys_delete_module) - .long C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush) - .long C_LABEL(sys_sysfs), C_LABEL(sys_nis_syscall), C_LABEL(sys_setfsuid) - .long C_LABEL(sys_setfsgid), C_LABEL(sys_select), C_LABEL(sys_time) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall) - .long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek) - /* "We are the Knights of the Forest of Ni!!" */ - .long C_LABEL(sys_mlock) - .long C_LABEL(sys_munlock) - .long C_LABEL(sys_mlockall) -/*240*/ .long C_LABEL(sys_munlockall) - .long C_LABEL(sys_sched_setparam) - .long C_LABEL(sys_sched_getparam) - .long C_LABEL(sys_sched_setscheduler) - .long C_LABEL(sys_sched_getscheduler) -/*245*/ .long C_LABEL(sys_sched_yield) - .long C_LABEL(sys_sched_get_priority_max) - .long C_LABEL(sys_sched_get_priority_min) - .long C_LABEL(sys_sched_rr_get_interval) - .long C_LABEL(sys_nanosleep) -/*250*/ .long C_LABEL(sys_mremap) - .long C_LABEL(sys_sysctl) - .long C_LABEL(sys_getsid) - .long C_LABEL(sys_fdatasync) - .long C_LABEL(sys_nfsservctl) -/*255*/ .long C_LABEL(sys_aplib) - .long C_LABEL(sys_nis_syscall) + .globl sys_call_table +sys_call_table: +/*0*/ .long sys_nis_syscall, sys_exit, sys_fork, sys_read, sys_write +/*5*/ .long sys_open, sys_close, sys_wait4, sys_creat, sys_link +/*10*/ .long sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod +/*15*/ .long sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek +/*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid +/*25*/ .long sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause +/*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 +/*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 +/*65*/ .long sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall +/*70*/ .long sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect +/*75*/ .long sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups +/*80*/ .long sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall +/*85*/ .long sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall +/*90*/ .long sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall +/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*100*/ .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending +/*105*/ .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall +/*110*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*115*/ .long sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd +/*120*/ .long sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod +/*125*/ .long sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate +/*130*/ .long sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall +/*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 +/*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 +/*175*/ .long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*180*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module +/*185*/ .long sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname +/*190*/ .long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*195*/ .long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask +/*200*/ .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir +/*205*/ .long sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall +/*210*/ .long sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo +/*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex +/*220*/ .long sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid +/*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid +/*230*/ .long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall + /* "We are the Knights of the Forest of Ni!!" */ +/*235*/ .long sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall +/*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler +/*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep +/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl +/*255*/ .long sys_aplib, sys_nis_syscall /* Now the SunOS syscall table. */ .align 4 - .globl C_LABEL(sunos_sys_table) -C_LABEL(sunos_sys_table): -/*0*/ .long C_LABEL(sunos_indir), C_LABEL(sys_exit), C_LABEL(sys_fork) - .long C_LABEL(sunos_read), C_LABEL(sunos_write), C_LABEL(sunos_open) - .long C_LABEL(sys_close), C_LABEL(sunos_wait4), C_LABEL(sys_creat) - .long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv) - .long C_LABEL(sys_chdir), C_LABEL(sunos_nosys), C_LABEL(sys_mknod) - .long C_LABEL(sys_chmod), C_LABEL(sys_lchown), C_LABEL(sunos_brk) - .long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), C_LABEL(sunos_getpid) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sys_ptrace) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat) - .long C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup) - .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_getgid) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) -/*50*/ .long C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_mctl), C_LABEL(sunos_ioctl), C_LABEL(sys_reboot) - .long C_LABEL(sunos_nosys), C_LABEL(sys_symlink), C_LABEL(sys_readlink) - .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot) - .long C_LABEL(sys_newfstat), C_LABEL(sunos_nosys), C_LABEL(sys_getpagesize) - .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_sbrk), C_LABEL(sunos_sstk) - .long C_LABEL(sunos_mmap), C_LABEL(sunos_vadvise), C_LABEL(sys_munmap) - .long C_LABEL(sys_mprotect), C_LABEL(sunos_madvise), C_LABEL(sys_vhangup) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_mincore), C_LABEL(sys_getgroups) - .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sunos_setpgrp) - .long C_LABEL(sys_setitimer), C_LABEL(sunos_nosys), C_LABEL(sys_swapon) - .long C_LABEL(sys_getitimer), C_LABEL(sys_gethostname), C_LABEL(sys_sethostname) - .long C_LABEL(sunos_getdtablesize), C_LABEL(sys_dup2), C_LABEL(sunos_nop) - .long C_LABEL(sys_fcntl), C_LABEL(sunos_select), C_LABEL(sunos_nop) - .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sunos_socket) - .long C_LABEL(sys_connect), C_LABEL(sunos_accept) -/*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sunos_send), C_LABEL(sunos_recv) - .long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sunos_setsockopt) - .long C_LABEL(sys_listen), C_LABEL(sunos_nosys), C_LABEL(sunos_sigaction) - .long C_LABEL(sunos_sigblock), C_LABEL(sunos_sigsetmask), C_LABEL(sys_sigpause) - .long C_LABEL(sys_sigstack), C_LABEL(sys_recvmsg), C_LABEL(sys_sendmsg) - .long C_LABEL(sunos_nosys), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage) - .long C_LABEL(sunos_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sunos_readv) - .long C_LABEL(sunos_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown) - .long C_LABEL(sys_fchmod), C_LABEL(sys_recvfrom), C_LABEL(sys_setreuid) - .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate) - .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sunos_nosys) - .long C_LABEL(sys_sendto), C_LABEL(sys_shutdown), C_LABEL(sys_socketpair) - .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes) - .long C_LABEL(sys_sigreturn), C_LABEL(sunos_nosys), C_LABEL(sys_getpeername) - .long C_LABEL(sunos_gethostid), C_LABEL(sunos_nosys), C_LABEL(sys_getrlimit) - .long C_LABEL(sys_setrlimit), C_LABEL(sunos_killpg), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) -/*150*/ .long C_LABEL(sys_getsockname), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sys_poll), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_getdirentries), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs) - .long C_LABEL(sys_umount), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sys_getdomainname), C_LABEL(sys_setdomainname) - .long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys) - .long C_LABEL(sunos_msgsys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid) - .long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sys_sigpending), C_LABEL(sunos_nosys) - .long C_LABEL(sys_setpgid), C_LABEL(sunos_pathconf), C_LABEL(sunos_fpathconf) - .long C_LABEL(sunos_sysconf), C_LABEL(sunos_uname), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) -/*200*/ .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) -/*250*/ .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sys_aplib) + .globl sunos_sys_table +sunos_sys_table: +/*0*/ .long sunos_indir, sys_exit, sys_fork + .long sunos_read, sunos_write, sunos_open + .long sys_close, sunos_wait4, sys_creat + .long sys_link, sys_unlink, sunos_execv + .long sys_chdir, sunos_nosys, sys_mknod + .long sys_chmod, sys_lchown, sunos_brk + .long sunos_nosys, sys_lseek, sunos_getpid + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_getuid, sunos_nosys, sys_ptrace + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sys_access, sunos_nosys, sunos_nosys + .long sys_sync, sys_kill, sys_newstat + .long sunos_nosys, sys_newlstat, sys_dup + .long sys_pipe, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_getgid + .long sunos_nosys, sunos_nosys +/*50*/ .long sunos_nosys, sys_acct, sunos_nosys + .long sunos_mctl, sunos_ioctl, sys_reboot + .long sunos_nosys, sys_symlink, sys_readlink + .long sys_execve, sys_umask, sys_chroot + .long sys_newfstat, sunos_nosys, sys_getpagesize + .long sys_msync, sys_vfork, sunos_nosys + .long sunos_nosys, sunos_sbrk, sunos_sstk + .long sunos_mmap, sunos_vadvise, sys_munmap + .long sys_mprotect, sunos_madvise, sys_vhangup + .long sunos_nosys, sunos_mincore, sys_getgroups + .long sys_setgroups, sys_getpgrp, sunos_setpgrp + .long sys_setitimer, sunos_nosys, sys_swapon + .long sys_getitimer, sys_gethostname, sys_sethostname + .long sunos_getdtablesize, sys_dup2, sunos_nop + .long sys_fcntl, sunos_select, sunos_nop + .long sys_fsync, sys_setpriority, sunos_socket + .long sys_connect, sunos_accept +/*100*/ .long sys_getpriority, sunos_send, sunos_recv + .long sunos_nosys, sys_bind, sunos_setsockopt + .long sys_listen, sunos_nosys, sunos_sigaction + .long sunos_sigblock, sunos_sigsetmask, sys_sigpause + .long sys_sigstack, sys_recvmsg, sys_sendmsg + .long sunos_nosys, sys_gettimeofday, sys_getrusage + .long sunos_getsockopt, sunos_nosys, sunos_readv + .long sunos_writev, sys_settimeofday, sys_fchown + .long sys_fchmod, sys_recvfrom, sys_setreuid + .long sys_setregid, sys_rename, sys_truncate + .long sys_ftruncate, sys_flock, sunos_nosys + .long sys_sendto, sys_shutdown, sys_socketpair + .long sys_mkdir, sys_rmdir, sys_utimes + .long sys_sigreturn, sunos_nosys, sys_getpeername + .long sunos_gethostid, sunos_nosys, sys_getrlimit + .long sys_setrlimit, sunos_killpg, sunos_nosys + .long sunos_nosys, sunos_nosys +/*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_getdomainname, sys_setdomainname + .long sunos_nosys, sys_quotactl, sunos_nosys + .long sunos_mount, sys_ustat, sunos_semsys + .long sunos_msgsys, sunos_shmsys, sunos_audit + .long sunos_nosys, sunos_getdents, sys_setsid + .long sys_fchdir, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sys_sigpending, sunos_nosys + .long sys_setpgid, sunos_pathconf, sunos_fpathconf + .long sunos_sysconf, sunos_uname, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys +/*200*/ .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys +/*250*/ .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sys_aplib diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index dba16891c..eac95ec98 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.33 1998/07/28 16:52:48 jj Exp $ +/* $Id: time.c,v 1.39 1998/09/29 09:46:15 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,9 @@ * Chris Davis (cdavis@cois.on.ca) 03/27/1998 * Added support for the intersil on the sun4/4200 * + * Gleb Raiko (rajko@mech.math.msu.su) 08/18/1998 + * Support for MicroSPARC-IIep, PCI CPU. + * * This file handles the Sparc specific time handling details. */ #include <linux/config.h> @@ -19,6 +22,7 @@ #include <linux/interrupt.h> #include <linux/timex.h> #include <linux/init.h> +#include <linux/pci.h> #include <asm/oplib.h> #include <asm/segment.h> @@ -36,6 +40,7 @@ enum sparc_clock_type sp_clock_typ; struct mostek48t02 *mstk48t02_regs = 0; struct mostek48t08 *mstk48t08_regs = 0; static int set_rtc_mmss(unsigned long); +static void sbus_do_settimeofday(struct timeval *tv); #ifdef CONFIG_SUN4 struct intersil *intersil_clock; @@ -71,10 +76,13 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) static long last_rtc_update=0; #ifdef CONFIG_SUN4 - int temp; - intersil_read_intr(intersil_clock, temp); - /* re-enable the irq */ - enable_pil_irq(10); + if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) || + (idprom->id_machtype == (SM_SUN4 | SM_4_110))) { + int temp; + intersil_read_intr(intersil_clock, temp); + /* re-enable the irq */ + enable_pil_irq(10); + } #endif clear_clock_irq(); @@ -83,11 +91,12 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* Determine when to update the Mostek clock. */ if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) + xtime.tv_usec < 500000 + (tick >> 1)) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } } /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. @@ -316,7 +325,7 @@ static __inline__ void clock_probe(void) kick_start_clock(); } -__initfunc(void time_init(void)) +__initfunc(void sbus_time_init(void)) { unsigned int year, mon, day, hour, min, sec; struct mostek48t02 *mregs; @@ -327,6 +336,8 @@ __initfunc(void time_init(void)) #endif do_get_fast_time = do_gettimeofday; + BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM); + btfixup(); #if CONFIG_AP1000 init_timers(timer_interrupt); @@ -344,7 +355,6 @@ __initfunc(void time_init(void)) #ifdef CONFIG_SUN4 if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) { #endif - mregs = mstk48t02_regs; if(!mregs) { prom_printf("Something wrong, clock regs not mapped yet.\n"); @@ -397,7 +407,19 @@ __initfunc(void time_init(void)) __sti(); } -static __inline__ unsigned long do_gettimeoffset(void) +__initfunc(void time_init(void)) +{ +#ifdef CONFIG_PCI + extern void pci_time_init(void); + if (pci_present()) { + pci_time_init(); + return; + } +#endif + sbus_time_init(); +} + +extern __inline__ unsigned long do_gettimeoffset(void) { unsigned long offset = 0; unsigned int count; @@ -459,6 +481,11 @@ void do_gettimeofday(struct timeval *tv) void do_settimeofday(struct timeval *tv) { + bus_do_settimeofday(tv); +} + +static void sbus_do_settimeofday(struct timeval *tv) +{ cli(); #if !CONFIG_AP1000 tv->tv_usec -= do_gettimeoffset(); diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c index 015d05357..86d632409 100644 --- a/arch/sparc/kernel/traps.c +++ b/arch/sparc/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.56 1998/04/06 16:08:32 jj Exp $ +/* $Id: traps.c,v 1.57 1998/09/17 11:04:51 jj Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -242,8 +242,8 @@ extern int do_mathemu(struct pt_regs *, struct task_struct *); void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { - static calls = 0; - int ret; + static int calls = 0; + int ret = 0; #ifndef __SMP__ struct task_struct *fpt = last_task_used_math; #else diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S index 526bf86bd..253c358fe 100644 --- a/arch/sparc/lib/bitops.S +++ b/arch/sparc/lib/bitops.S @@ -26,12 +26,26 @@ ___set_bit: wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ld [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ld [%g1], %g7 or %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + st %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f st %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: @@ -48,12 +62,26 @@ ___clear_bit: wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ld [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ld [%g1], %g7 andn %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + st %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f st %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: @@ -70,12 +98,26 @@ ___change_bit: wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ld [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ld [%g1], %g7 xor %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + st %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f st %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: @@ -92,12 +134,26 @@ ___set_le_bit: wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ldub [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ldub [%g1], %g7 or %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + stb %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f stb %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: @@ -113,12 +169,26 @@ ___clear_le_bit: wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ldub [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ldub [%g1], %g7 andn %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + stb %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f stb %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: diff --git a/arch/sparc/lib/copy_user.S b/arch/sparc/lib/copy_user.S index fceaf7a4b..728cbf9bd 100644 --- a/arch/sparc/lib/copy_user.S +++ b/arch/sparc/lib/copy_user.S @@ -3,7 +3,7 @@ * Copyright(C) 1995 Linus Torvalds * Copyright(C) 1996 David S. Miller * Copyright(C) 1996 Eddie C. Dost - * Copyright(C) 1996 Jakub Jelinek + * Copyright(C) 1996,1998 Jakub Jelinek * * derived from: * e-mail between David and Eddie. @@ -13,13 +13,14 @@ #include <asm/cprefix.h> #include <asm/ptrace.h> +#include <asm/asmmacro.h> #define EX(x,y,a,b,z) \ 98: x,y; \ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ -99: retl; \ - a, b, %o0; \ +99: ba fixupretl; \ + a, b, %g3; \ .section __ex_table,z##alloc; \ .align 4; \ .word 98b, 99b; \ @@ -31,8 +32,8 @@ .section .fixup,z##alloc,z##execinstr; \ .align 4; \ 99: c, d, e; \ - retl; \ - a, b, %o0; \ + ba fixupretl; \ + a, b, %g3; \ .section __ex_table,z##alloc; \ .align 4; \ .word 98b, 99b; \ @@ -340,7 +341,7 @@ short_aligned_end: andcc %o2, 4, %g0 EXO2(ld [%o1 + 0x00], %g2,#) - EX(ld [%o1 + 0x04], %g3, sub %o2, 4,#) + EXO2(ld [%o1 + 0x04], %g3,#) add %o1, 8, %o1 EXO2(st %g2, [%o0 + 0x00],#) EX(st %g3, [%o0 + 0x04], sub %o2, 4,#) @@ -352,16 +353,32 @@ short_aligned_end: .section .fixup,#alloc,#execinstr .align 4 97: - retl - mov %o2, %o0 + mov %o2, %g3 +fixupretl: + GET_PAGE_OFFSET(g1) + cmp %o0, %g1 + blu 1f + cmp %o1, %g1 + bgeu 1f + nop + save %sp, -64, %sp + mov %i0, %o0 + call __bzero + mov %g3, %o1 + restore +1: retl + mov %g3, %o0 + /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */ 50: /* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK * happens. This is derived from the amount ldd reads, st stores, etc. * x = g2 % 12; - * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4) + * g3 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? 0 : (x - 4) * 4); + * o0 += (g2 / 12) * 32; */ cmp %g2, 12 + add %o0, %g7, %o0 bcs 1f cmp %g2, 24 bcs 2f @@ -370,84 +387,97 @@ short_aligned_end: nop sub %g2, 12, %g2 sub %g7, 32, %g7 -3: - sub %g2, 12, %g2 +3: sub %g2, 12, %g2 sub %g7, 32, %g7 -2: - sub %g2, 12, %g2 +2: sub %g2, 12, %g2 sub %g7, 32, %g7 -1: - cmp %g2, 4 - bcs,a 1f - sll %g2, 3, %g2 +1: cmp %g2, 4 + bcs,a 60f + clr %g2 sub %g2, 4, %g2 sll %g2, 2, %g2 -1: - and %g1, 0x7f, %o0 - add %o0, %g7, %o0 - retl - sub %o0, %g2, %o0 +60: and %g1, 0x7f, %g3 + sub %o0, %g7, %o0 + add %g3, %g7, %g3 + ba fixupretl + sub %g3, %g2, %g3 51: /* i = 41 - g2; j = i % 6; - * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8; + * g3 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : 16; + * o0 -= (i / 6) * 16 + 16; */ neg %g2 and %g1, 0xf, %g1 add %g2, 41, %g2 -1: - cmp %g2, 6 + add %o0, %g1, %o0 +1: cmp %g2, 6 bcs,a 2f cmp %g2, 4 add %g1, 16, %g1 b 1b sub %g2, 6, %g2 -2: - bcs,a 3f - inc %g2 - sub %g2, 3, %g2 - b 2f - sll %g2, 3, %g2 -3: +2: bcc,a 2f + mov 16, %g2 + inc %g2 sll %g2, 2, %g2 -2: - retl - add %g1, %g2, %o0 +2: add %g1, %g2, %g3 + ba fixupretl + sub %o0, %g3, %o0 52: -/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */ - and %g2, 0xfffffff8, %g4 +/* g3 = g1 + g7 - (g2 / 8) * 32 + (g2 & 4) ? (g2 & 3) * 8 : 0; + o0 += (g2 / 8) * 32 */ + andn %g2, 7, %g4 + add %o0, %g7, %o0 + andcc %g2, 4, %g0 and %g2, 3, %g2 sll %g4, 2, %g4 sll %g2, 3, %g2 - add %g2, %g4, %g2 - b,a 1b + bne 60b + sub %g7, %g4, %g7 + ba 60b + clr %g2 53: -/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */ +/* g3 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 4) ? (g2 & 3) * 2 : 0; + o0 += (g2 & 8) */ and %g2, 3, %g4 - and %g2, 0xfffffff8, %g2 + andcc %g2, 4, %g0 + and %g2, 8, %g2 sll %g4, 1, %g4 + be 1f + add %o0, %g2, %o0 add %g2, %g4, %g2 - and %o2, 0xf, %o0 - add %o0, %o3, %o0 - retl - sub %o0, %g2, %o0 +1: and %o2, 0xf, %g3 + add %g3, %o3, %g3 + ba fixupretl + sub %g3, %g2, %g3 54: -/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */ +/* g3 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 2) ? (g2 & 1) : 0; + o0 += (g2 / 4) * 2 */ srl %g2, 2, %o4 - and %g2, 1, %o1 - sll %o4, 1, %o4 + and %g2, 1, %o5 + srl %g2, 1, %g2 + add %o4, %o4, %o4 + and %o5, %g2, %o5 and %o2, 0xf, %o2 - sub %o3, %o1, %o3 + add %o0, %o4, %o0 + sub %o3, %o5, %o3 sub %o2, %o4, %o2 - retl - add %o2, %o3, %o0 + ba fixupretl + add %o2, %o3, %g3 55: -/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */ +/* i = 27 - g2; + g3 = (o2 & 1) + i / 4 * 2 + !(i & 3); + o0 -= i / 4 * 2 + 1 */ neg %g2 and %o2, 1, %o2 add %g2, 27, %g2 - srl %g2, 2, %o1 - and %g2, 1, %g2 - sll %o1, 1, %o1 - add %o2, %g2, %o0 - retl - add %o0, %o1, %o0 + srl %g2, 2, %o5 + andcc %g2, 3, %g0 + mov 1, %g2 + add %o5, %o5, %o5 + be,a 1f + clr %g2 +1: add %g2, %o5, %g3 + sub %o0, %g3, %o0 + ba fixupretl + add %g3, %o2, %g3 diff --git a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c index 006cba5a8..8f0941ebf 100644 --- a/arch/sparc/lib/debuglocks.c +++ b/arch/sparc/lib/debuglocks.c @@ -1,7 +1,8 @@ -/* $Id: debuglocks.c,v 1.1 1997/05/08 18:13:34 davem Exp $ +/* $Id: debuglocks.c,v 1.5 1998/10/14 09:19:04 jj Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) */ #include <linux/kernel.h> @@ -22,75 +23,56 @@ * number of the owner in the lowest two bits. */ -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("spin_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; } +#define STORE_CALLER(A) __asm__ __volatile__("mov %%i7, %0" : "=r" (A)); -void _spin_lock(spinlock_t *lock) +static inline void show(char *str, spinlock_t *lock, unsigned long caller) { - unsigned long caller; - unsigned long val; int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); -again: - __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); - if(val) { - while(lock->lock) { - STUCK; - barrier(); - } - goto again; - } - lock->owner_pc = (cpu & 3) | (caller & ~3); + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, + lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); } -int _spin_trylock(spinlock_t *lock) +static inline void show_read(char *str, rwlock_t *lock, unsigned long caller) { - unsigned long val; - unsigned long caller; int cpu = smp_processor_id(); - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); - __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); - if(!val) { - /* We got it, record our identity for debugging. */ - lock->owner_pc = (cpu & 3) | (caller & ~3); - } - return val == 0; + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str, + lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); } -void _spin_unlock(spinlock_t *lock) +static inline void show_write(char *str, rwlock_t *lock, unsigned long caller) { - lock->owner_pc = 0; - __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory"); + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx) reader[0]=%08lx reader[1]=%08lx reader[2]=%08lx reader[3]=%08lx\n", + str, lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3, + lock->reader_pc[0], + lock->reader_pc[1], + lock->reader_pc[2], + lock->reader_pc[3]); } #undef INIT_STUCK #define INIT_STUCK 100000000 -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; } - -void _spin_lock_irq(spinlock_t *lock) +void _do_spin_lock(spinlock_t *lock, char *str) { unsigned long caller; unsigned long val; int cpu = smp_processor_id(); int stuck = INIT_STUCK; - __cli(); - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + STORE_CALLER(caller); + again: __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); if(val) { while(lock->lock) { - STUCK; + if (!--stuck) { + show(str, lock, caller); + stuck = INIT_STUCK; + } barrier(); } goto again; @@ -98,362 +80,126 @@ again: lock->owner_pc = (cpu & 3) | (caller & ~3); } -void _spin_unlock_irq(spinlock_t *lock) -{ - lock->owner_pc = 0; - __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory"); - __sti(); -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; } - -/* Caller macro does __save_and_cli(flags) for us. */ -void _spin_lock_irqsave(spinlock_t *lock) +int _spin_trylock(spinlock_t *lock) { - unsigned long caller; unsigned long val; + unsigned long caller; int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); -again: + STORE_CALLER(caller); + __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock))); - if(val) { - while(lock->lock) { - STUCK; - barrier(); - } - goto again; + if(!val) { + /* We got it, record our identity for debugging. */ + lock->owner_pc = (cpu & 3) | (caller & ~3); } - lock->owner_pc = (cpu & 3) | (caller & ~3); + return val == 0; } -void _spin_unlock_irqrestore(spinlock_t *lock) +void _do_spin_unlock(spinlock_t *lock) { lock->owner_pc = 0; - __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory"); + barrier(); + lock->lock = 0; } #undef INIT_STUCK #define INIT_STUCK 100000000 -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("read_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } - -void _read_lock(rwlock_t *rw) +void _do_read_lock(rwlock_t *rw, char *str) { - unsigned long flags; unsigned long caller; unsigned long val; int cpu = smp_processor_id(); int stuck = INIT_STUCK; - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); - __save_and_cli(flags); -wlock_again: - __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff) { - STUCK; - barrier(); - } - goto wlock_again; - } -clock_again: - __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff00) { - STUCK; - barrier(); - } - goto clock_again; - } - (*((unsigned short *)&rw->lock))++; - barrier(); - (*(((unsigned short *)&rw->lock)+1)) = 0; - __restore_flags(flags); -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("read_unlock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } - -void _read_unlock(rwlock_t *rw) -{ - unsigned long flags, val, caller; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); - __save_and_cli(flags); -clock_again: - __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff00) { - STUCK; - barrier(); - } - goto clock_again; - } - (*((unsigned short *)&rw->lock))--; - barrier(); - (*(((unsigned char *)&rw->lock)+2))=0; - __restore_flags(flags); -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("write_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } + STORE_CALLER(caller); -void _write_lock(rwlock_t *rw) -{ - unsigned long flags, val, caller; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); - __save_and_cli(flags); wlock_again: __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); if(val) { while(rw->lock & 0xff) { - STUCK; + if (!--stuck) { + show_read(str, rw, caller); + stuck = INIT_STUCK; + } barrier(); } goto wlock_again; } - rw->owner_pc = (cpu & 3) | (caller & ~3); - while(rw->lock & ~0xff) { - STUCK; - barrier(); - } -} -void _write_unlock(rwlock_t *rw) -{ - rw->owner_pc = 0; + rw->reader_pc[cpu] = caller; barrier(); - rw->lock = 0; + rw->lock++; } #undef INIT_STUCK #define INIT_STUCK 100000000 -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("read_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } - -void _read_lock_irq(rwlock_t *rw) +void _do_read_unlock(rwlock_t *rw, char *str) { unsigned long caller; unsigned long val; int cpu = smp_processor_id(); int stuck = INIT_STUCK; - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); - __cli(); -wlock_again: - __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff) { - STUCK; - barrier(); - } - goto wlock_again; - } -clock_again: - __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff00) { - STUCK; - barrier(); - } - goto clock_again; - } - (*((unsigned short *)&rw->lock))++; - barrier(); - (*(((unsigned short *)&rw->lock)+1)) = 0; -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 + STORE_CALLER(caller); -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("read_unlock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } - -void _read_unlock_irq(rwlock_t *rw) -{ - unsigned long val, caller; - int stuck = INIT_STUCK; - int cpu = smp_processor_id(); - - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); -clock_again: - __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff00) { - STUCK; - barrier(); - } - goto clock_again; - } - (*((unsigned short *)&rw->lock))--; - barrier(); - (*(((unsigned char *)&rw->lock)+2))=0; - __sti(); -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("write_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } - -void _write_lock_irq(rwlock_t *rw) -{ - unsigned long val, caller; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); - __cli(); wlock_again: __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); if(val) { while(rw->lock & 0xff) { - STUCK; + if (!--stuck) { + show_read(str, rw, caller); + stuck = INIT_STUCK; + } barrier(); } goto wlock_again; } - rw->owner_pc = (cpu & 3) | (caller & ~3); - while(rw->lock & ~0xff) { - STUCK; - barrier(); - } -} -void _write_unlock_irq(rwlock_t *rw) -{ - rw->owner_pc = 0; + rw->reader_pc[cpu] = 0; barrier(); - rw->lock = 0; - __sti(); + rw->lock -= 0x1ff; } #undef INIT_STUCK #define INIT_STUCK 100000000 -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("read_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } - -/* Caller does __save_and_cli(flags) for us. */ -void _read_lock_irqsave(rwlock_t *rw) +void _do_write_lock(rwlock_t *rw, char *str) { unsigned long caller; unsigned long val; int cpu = smp_processor_id(); int stuck = INIT_STUCK; - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); + STORE_CALLER(caller); + wlock_again: __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); if(val) { - while(rw->lock & 0xff) { - STUCK; +wlock_wait: + while(rw->lock) { + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } barrier(); } goto wlock_again; } -clock_again: - __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff00) { - STUCK; - barrier(); - } - goto clock_again; - } - (*((unsigned short *)&rw->lock))++; - barrier(); - (*(((unsigned short *)&rw->lock)+1)) = 0; -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("read_unlock_irqrestore(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } -void _read_unlock_irqrestore(rwlock_t *rw) -{ - unsigned long val, caller; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); -clock_again: - __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff00) { - STUCK; - barrier(); - } - goto clock_again; + if (rw->lock & ~0xff) { + *(((unsigned char *)&rw->lock)+3) = 0; + barrier(); + goto wlock_wait; } - (*((unsigned short *)&rw->lock))--; - barrier(); - (*(((unsigned char *)&rw->lock)+2))=0; -} - -#undef INIT_STUCK -#define INIT_STUCK 100000000 - -#undef STUCK -#define STUCK \ -if(!--stuck) { printk("write_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; } - -/* Caller does __save_and_cli(flags) for us. */ -void _write_lock_irqsave(rwlock_t *rw) -{ - unsigned long val, caller; - int cpu = smp_processor_id(); - int stuck = INIT_STUCK; - __asm__ __volatile__("mov %%i7, %0" : "=r" (caller)); -wlock_again: - __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff) { - STUCK; - barrier(); - } - goto wlock_again; - } + barrier(); rw->owner_pc = (cpu & 3) | (caller & ~3); - while(rw->lock & ~0xff) { - STUCK; - barrier(); - } } -void _write_unlock_irqrestore(rwlock_t *rw) +void _do_write_unlock(rwlock_t *rw) { rw->owner_pc = 0; barrier(); diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S index 8d634704f..102541b18 100644 --- a/arch/sparc/lib/locks.S +++ b/arch/sparc/lib/locks.S @@ -1,7 +1,9 @@ -/* $Id: locks.S,v 1.13 1998/07/30 11:29:28 davem Exp $ +/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $ * locks.S: SMP low-level lock primitives on Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ #include <asm/cprefix.h> @@ -43,52 +45,48 @@ ___rw_read_enter_spin_on_wlock: ldstub [%g1 + 3], %g2 b ___rw_read_enter_spin_on_wlock ldub [%g1 + 3], %g2 +___rw_read_exit_spin_on_wlock: + orcc %g2, 0x0, %g0 + be,a ___rw_read_exit + ldstub [%g1 + 3], %g2 + b ___rw_read_exit_spin_on_wlock + ldub [%g1 + 3], %g2 ___rw_write_enter_spin_on_wlock: orcc %g2, 0x0, %g0 be,a ___rw_write_enter ldstub [%g1 + 3], %g2 b ___rw_write_enter_spin_on_wlock - ldub [%g1 + 3], %g2 + ld [%g1], %g2 .globl ___rw_read_enter ___rw_read_enter: orcc %g2, 0x0, %g0 bne,a ___rw_read_enter_spin_on_wlock ldub [%g1 + 3], %g2 -1: - ldstub [%g1 + 2], %g7 - orcc %g7, 0x0, %g0 - bne 1b - ldsh [%g1], %g2 + ld [%g1], %g2 add %g2, 1, %g2 - sth %g2, [%g1] - sth %g0, [%g1 + 2] + st %g2, [%g1] retl mov %g4, %o7 - /* We must be careful here to not blow away wlock. */ .globl ___rw_read_exit -___rw_read_exit_spin: - ldstub [%g1 + 2], %g2 ___rw_read_exit: orcc %g2, 0x0, %g0 - bne ___rw_read_exit_spin - ldsh [%g1], %g7 - sub %g7, 1, %g7 - sth %g7, [%g1] - stb %g0, [%g1 + 2] + bne,a ___rw_read_exit_spin_on_wlock + ldub [%g1 + 3], %g2 + ld [%g1], %g2 + sub %g2, 0x1ff, %g2 + st %g2, [%g1] retl mov %g4, %o7 .globl ___rw_write_enter ___rw_write_enter: orcc %g2, 0x0, %g0 - bne,a ___rw_write_enter_spin_on_wlock - ldub [%g1 + 3], %g2 - ld [%g1], %g2 -1: - andncc %g2, 0xff, %g0 - bne,a 1b + bne ___rw_write_enter_spin_on_wlock ld [%g1], %g2 + andncc %g2, 0xff, %g0 + bne,a ___rw_write_enter_spin_on_wlock + stb %g0, [%g1 + 3] retl mov %g4, %o7 diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 929b2a6f0..a9e51c67f 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.31 1998/07/26 03:02:45 davem Exp $ +# $Id: Makefile,v 1.32 1998/08/16 16:02:25 ecd Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -12,7 +12,7 @@ O_OBJS := fault.o init.o loadmmu.o generic.o asyncd.o extable.o btfixup.o ifeq ($(CONFIG_SUN4),y) O_OBJS += nosrmmu.o else -O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o turbosparc.o +O_OBJS += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o endif ifdef SMP O_OBJS += nosun4c.o @@ -25,9 +25,6 @@ include $(TOPDIR)/Rules.make hypersparc.o: hypersparc.S $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S -turbosparc.o: turbosparc.S - $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o turbosparc.o turbosparc.S - viking.o: viking.S $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S diff --git a/arch/sparc/mm/asyncd.c b/arch/sparc/mm/asyncd.c index 908501dc9..666bf8429 100644 --- a/arch/sparc/mm/asyncd.c +++ b/arch/sparc/mm/asyncd.c @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.11 1997/12/14 23:24:34 ecd Exp $ +/* $Id: asyncd.c,v 1.12 1998/09/13 04:30:30 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index 88d85004c..3c8ffbfae 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.94 1998/05/01 16:00:27 jj Exp $ +/* $Id: fault.c,v 1.96 1998/11/08 11:13:56 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -149,7 +149,9 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk, (unsigned long) tsk->mm->context); printk(KERN_ALERT "tsk->mm->pgd = %08lx\n", (unsigned long) tsk->mm->pgd); + lock_kernel(); die_if_kernel("Oops", regs); + unlock_kernel(); } asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, @@ -196,11 +198,11 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, unsigned int fixup; unsigned long g2; int from_user = !(regs->psr & PSR_PS); - lock_kernel(); - down(&mm->mmap_sem); + if(text_fault) address = regs->pc; + down(&mm->mmap_sem); /* The kernel referencing a bad kernel pointer can lock up * a sun4c machine completely, so we must attempt recovery. */ @@ -229,9 +231,10 @@ good_area: if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(current, vma, address, write); + if (!handle_mm_fault(current, vma, address, write)) + goto do_sigbus; up(&mm->mmap_sem); - goto out; + return; /* * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first.. @@ -239,7 +242,7 @@ good_area: bad_area: up(&mm->mmap_sem); /* Is this in ex_table? */ - +do_kernel_fault: g2 = regs->u_regs[UREG_G2]; if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) { if (fixup > 10) { /* Values below are reserved for other things */ @@ -263,7 +266,7 @@ bad_area: regs->u_regs[UREG_G2] = g2; regs->pc = fixup; regs->npc = regs->pc + 4; - goto out; + return; } } if(from_user) { @@ -274,11 +277,18 @@ bad_area: tsk->tss.sig_address = address; tsk->tss.sig_desc = SUBSIG_NOMAPPING; force_sig(SIGSEGV, tsk); - goto out; + return; } unhandled_fault (address, tsk, regs); -out: - unlock_kernel(); + return; + +do_sigbus: + up(&mm->mmap_sem); + tsk->tss.sig_address = address; + tsk->tss.sig_desc = SUBSIG_MISCERROR; + force_sig(SIGBUS, tsk); + if (! from_user) + goto do_kernel_fault; } asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write, @@ -372,7 +382,8 @@ good_area: else if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; - handle_mm_fault(current, vma, address, write); + if (!handle_mm_fault(current, vma, address, write)) + goto do_sigbus; up(&mm->mmap_sem); return; bad_area: @@ -385,6 +396,12 @@ bad_area: tsk->tss.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, tsk, 1); return; + +do_sigbus: + up(&mm->mmap_sem); + tsk->tss.sig_address = address; + tsk->tss.sig_desc = SUBSIG_MISCERROR; + force_sig(SIGBUS, tsk); } void window_overflow_fault(void) diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c index 4ad1810e3..ea94a8f60 100644 --- a/arch/sparc/mm/generic.c +++ b/arch/sparc/mm/generic.c @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.5 1996/12/18 06:43:23 tridge Exp $ +/* $Id: generic.c,v 1.6 1998/10/27 23:28:00 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -41,10 +41,11 @@ static inline void forget_pte(pte_t page) unsigned long addr = pte_page(page); if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr))) return; - free_page(addr); - if (current->mm->rss <= 0) - return; - current->mm->rss--; + /* + * free_page() used to be able to clear swap cache + * entries. We may now have to do it manually. + */ + free_page_and_swap_cache(addr); return; } swap_free(pte_val(page)); diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index eef01666d..391a4dedb 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.59 1998/03/27 06:59:57 davem Exp $ +/* $Id: init.c,v 1.60 1998/09/13 04:30:31 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index 41bd72671..6cd8c9b7c 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c @@ -1,4 +1,4 @@ -/* $Id: io-unit.c,v 1.11 1998/04/13 07:26:37 davem Exp $ +/* $Id: io-unit.c,v 1.13 1998/11/08 11:13:57 davem Exp $ * io-unit.c: IO-UNIT specific routines for memory management. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -231,3 +231,51 @@ __initfunc(void ld_mmu_iounit(void)) BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM); #endif } + +__u32 iounit_map_dma_init(struct linux_sbus *sbus, int size) +{ + int i, j, k, npages; + unsigned long rotor, scan, limit; + unsigned long flags; + __u32 ret; + struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; + + npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT; + i = 0x0213; + spin_lock_irqsave(&iounit->lock, flags); +next: j = (i & 15); + rotor = iounit->rotor[j - 1]; + limit = iounit->limit[j]; + scan = rotor; +nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan); + if (scan + npages > limit) { + if (limit != rotor) { + limit = rotor; + scan = iounit->limit[j - 1]; + goto nexti; + } + i >>= 4; + if (!(i & 15)) + panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size); + goto next; + } + for (k = 1, scan++; k < npages; k++) + if (test_bit(scan++, iounit->bmap)) + goto nexti; + iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1]; + scan -= npages; + ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT); + for (k = 0; k < npages; k++, scan++) + set_bit(scan, iounit->bmap); + spin_unlock_irqrestore(&iounit->lock, flags); + return ret; +} + +__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct linux_sbus *sbus) +{ + int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT; + struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu; + + iounit->page_table[scan] = MKIOPTE(mmu_v2p(((unsigned long)addr) & PAGE_MASK)); + return vaddr + (((unsigned long)addr) & ~PAGE_MASK); +} diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 97bd5be37..69d40fa09 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.173 1998/08/04 20:48:57 davem Exp $ +/* $Id: srmmu.c,v 1.175 1998/08/28 18:57:31 zaitcev Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1997,7 +1997,7 @@ static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long ad static void srmmu_destroy_context(struct mm_struct *mm) { - if(mm->context != NO_CONTEXT && mm->count == 1) { + if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { flush_cache_mm(mm); ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); flush_tlb_mm(mm); @@ -2071,7 +2071,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma, static void hypersparc_destroy_context(struct mm_struct *mm) { - if(mm->context != NO_CONTEXT && mm->count == 1) { + if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { ctxd_t *ctxp; /* HyperSparc is copy-back, any data for this @@ -2399,10 +2399,93 @@ __initfunc(static void init_swift(void)) poke_srmmu = poke_swift; } -/* turbosparc.S */ -extern void turbosparc_flush_cache_all(void); -extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); -extern void turbosparc_flush_page_for_dma(unsigned long page); +static void turbosparc_flush_cache_all(void) +{ + flush_user_windows(); + turbosparc_idflash_clear(); +} + +static void turbosparc_flush_cache_mm(struct mm_struct *mm) +{ + FLUSH_BEGIN(mm) + flush_user_windows(); + turbosparc_idflash_clear(); + FLUSH_END +} + +static void turbosparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + FLUSH_BEGIN(mm) + flush_user_windows(); + turbosparc_idflash_clear(); + FLUSH_END +} + +static void turbosparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page) +{ + FLUSH_BEGIN(vma->vm_mm) + flush_user_windows(); + if (vma->vm_flags & VM_EXEC) + turbosparc_flush_icache(); + turbosparc_flush_dcache(); + FLUSH_END +} + +/* TurboSparc is copy-back, if we turn it on, but this does not work. */ +static void turbosparc_flush_page_to_ram(unsigned long page) +{ +#ifdef TURBOSPARC_WRITEBACK + volatile unsigned long clear; + + if (srmmu_hwprobe(page)) + turbosparc_flush_page_cache(page); + clear = srmmu_get_fstatus(); +#endif +} + +static void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) +{ +} + +static void turbosparc_flush_page_for_dma(unsigned long page) +{ + turbosparc_flush_dcache(); +} + +static void turbosparc_flush_chunk(unsigned long chunk) +{ +} + +static void turbosparc_flush_tlb_all(void) +{ + srmmu_flush_whole_tlb(); + module_stats.invall++; +} + +static void turbosparc_flush_tlb_mm(struct mm_struct *mm) +{ + FLUSH_BEGIN(mm) + srmmu_flush_whole_tlb(); + module_stats.invmm++; + FLUSH_END +} + +static void turbosparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + FLUSH_BEGIN(mm) + srmmu_flush_whole_tlb(); + module_stats.invrnge++; + FLUSH_END +} + +static void turbosparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + FLUSH_BEGIN(vma->vm_mm) + srmmu_flush_whole_tlb(); + module_stats.invpg++; + FLUSH_END +} + __initfunc(static void poke_turbosparc(void)) { @@ -2420,7 +2503,7 @@ __initfunc(static void poke_turbosparc(void)) #ifdef TURBOSPARC_WRITEBACK ccreg |= (TURBOSPARC_SNENABLE); /* Do DVMA snooping in Dcache */ ccreg &= ~(TURBOSPARC_uS2 | TURBOSPARC_WTENABLE); - /* Write-back D-cache, emulate VLSI + /* Write-back D-cache, emulate VLSI * abortion number three, not number one */ #else /* For now let's play safe, optimize later */ @@ -2428,7 +2511,8 @@ __initfunc(static void poke_turbosparc(void)) /* Do DVMA snooping in Dcache, Write-thru D-cache */ ccreg &= ~(TURBOSPARC_uS2); /* Emulate VLSI abortion number three, not number one */ -#endif +#endif + switch (ccreg & 7) { case 0: /* No SE cache */ case 7: /* Test mode */ @@ -2449,22 +2533,17 @@ __initfunc(static void init_turbosparc(void)) srmmu_modtype = TurboSparc; BTFIXUPSET_CALL(flush_cache_all, turbosparc_flush_cache_all, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_cache_mm, hypersparc_flush_cache_mm, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_cache_page, hypersparc_flush_cache_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_cache_range, hypersparc_flush_cache_range, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_mm, turbosparc_flush_cache_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_page, turbosparc_flush_cache_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_range, turbosparc_flush_cache_range, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_all, hypersparc_flush_tlb_all, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_mm, hypersparc_flush_tlb_mm, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_page, hypersparc_flush_tlb_page, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_tlb_range, hypersparc_flush_tlb_range, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_all, turbosparc_flush_tlb_all, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_mm, turbosparc_flush_tlb_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_page, turbosparc_flush_tlb_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_range, turbosparc_flush_tlb_range, BTFIXUPCALL_NORM); -#ifdef TURBOSPARC_WRITEBACK - BTFIXUPSET_CALL(flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM); - BTFIXUPSET_CALL(flush_chunk, hypersparc_flush_chunk, BTFIXUPCALL_NORM); -#else - BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP); - BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP); -#endif + BTFIXUPSET_CALL(flush_page_to_ram, turbosparc_flush_page_to_ram, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_chunk, turbosparc_flush_chunk, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP); BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NOP); diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c index 448881608..fa8105d57 100644 --- a/arch/sparc/mm/sun4c.c +++ b/arch/sparc/mm/sun4c.c @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.166 1998/08/04 20:49:05 davem Exp $ +/* $Id: sun4c.c,v 1.171 1998/09/21 05:05:41 jj Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -400,7 +400,9 @@ void sun4c_complete_all_stores(void) _unused = sun4c_get_context(); sun4c_set_context(_unused); +#ifdef CONFIG_SUN_AUXIO _unused = *AUXREG; +#endif } /* Bootup utility functions. */ @@ -622,9 +624,8 @@ __initfunc(static void sun4c_probe_mmu(void)) break; case (SM_SUN4|SM_4_470): - prom_printf("No support for 4400 yet\n"); - prom_halt(); - num_segmaps = 1024; + /* should be 1024 segmaps. when it get fixed */ + num_segmaps = 256; num_contexts = 64; break; default: @@ -755,13 +756,15 @@ static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on, ~bits_off); } -/* the 4/260 dies real hard on the prom_putsegment line. - not sure why, but it seems to work without it cgd */ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end) { unsigned long vaddr; unsigned char pseg, ctx; -#ifndef CONFIG_SUN4 +#ifdef CONFIG_SUN4 + /* sun4/110 and 260 have no kadb. */ + if((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && + (idprom->id_machtype != (SM_SUN4 | SM_4_110))) { +#endif for(vaddr = KADB_DEBUGGER_BEGVM; vaddr < LINUX_OPPROM_ENDVM; vaddr += SUN4C_REAL_PGDIR_SIZE) { @@ -773,6 +776,8 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end) fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0); } } +#ifdef CONFIG_SUN4 + } #endif for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) { pseg = sun4c_get_segmap(vaddr); @@ -2142,7 +2147,7 @@ static void sun4c_destroy_context_hw(struct mm_struct *mm) { struct ctx_list *ctx_old; - if(mm->context != NO_CONTEXT && mm->count == 1) { + if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context); ctx_old = ctx_list_pool + mm->context; remove_from_ctx_list(ctx_old); @@ -2205,7 +2210,7 @@ static void sun4c_destroy_context_sw(struct mm_struct *mm) { struct ctx_list *ctx_old; - if(mm->context != NO_CONTEXT && mm->count == 1) { + if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) { sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context); ctx_old = ctx_list_pool + mm->context; remove_from_ctx_list(ctx_old); diff --git a/arch/sparc/mm/turbosparc.S b/arch/sparc/mm/turbosparc.S deleted file mode 100644 index df580a85c..000000000 --- a/arch/sparc/mm/turbosparc.S +++ /dev/null @@ -1,48 +0,0 @@ -/* $Id: turbosparc.S,v 1.3 1998/05/04 12:41:29 ralf Exp $ - * turbosparc.S: High speed TurboSparc mmu/cache operations. - * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -#include <asm/ptrace.h> -#include <asm/psr.h> -#include <asm/asi.h> -#include <asm/page.h> -#include <asm/pgtsrmmu.h> - -#define WINDOW_FLUSH(tmp1, tmp2) \ - mov 0, tmp1; \ -98: ld [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2; \ - orcc %g0, tmp2, %g0; \ - add tmp1, 1, tmp1; \ - bne 98b; \ - save %sp, -64, %sp; \ -99: subcc tmp1, 1, tmp1; \ - bne 99b; \ - restore %g0, %g0, %g0; - - .text - .align 4 - - .globl turbosparc_flush_cache_all - .globl turbosparc_flush_sig_insns - .globl turbosparc_flush_page_for_dma - -turbosparc_flush_cache_all: - WINDOW_FLUSH(%g4, %g5) - sethi %hi(vac_cache_size), %g4 - ld [%g4 + %lo(vac_cache_size)], %g5 - sethi %hi(vac_line_size), %g1 - ld [%g1 + %lo(vac_line_size)], %g2 -1: - subcc %g5, %g2, %g5 - bne 1b - sta %g0, [%g5] ASI_M_DATAC_TAG - retl - sta %g0, [%g0] ASI_M_IC_FLCLEAR - -turbosparc_flush_sig_insns: -turbosparc_flush_page_for_dma: - retl - nop diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c index 3bbc7ade0..4a1a42309 100644 --- a/arch/sparc/prom/console.c +++ b/arch/sparc/prom/console.c @@ -1,8 +1,9 @@ -/* $Id: console.c,v 1.17 1998/03/09 14:04:21 jj Exp $ +/* $Id: console.c,v 1.20 1998/09/21 05:05:50 jj Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Pete Zaitcev <zaitcev@metabyte.com> */ #include <linux/config.h> @@ -17,6 +18,9 @@ extern void restore_current(void); +static char con_name_jmc[] = "/obio/su@"; /* "/obio/su@0,3002f8"; */ +#define CON_SIZE_JMC (sizeof(con_name_jmc)) + /* Non blocking get character from console input device, returns -1 * if no input was taken. This can be used for polling. */ @@ -83,7 +87,6 @@ prom_nbputchar(char c) i = 0; } #endif - break; default: i = -1; @@ -139,9 +142,14 @@ prom_query_input_device() restore_flags(flags); if(prom_node_has_property(st_p, "keyboard")) return PROMDEV_IKBD; - prom_getproperty(st_p, "device_type", propb, sizeof(propb)); + if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) { + if(strncmp(propb, "keyboard", sizeof("serial")) == 0) + return PROMDEV_IKBD; + } + if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) { if(strncmp(propb, "serial", sizeof("serial"))) return PROMDEV_I_UNK; + } prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb)); p = propb; while(*p) p++; p -= 2; @@ -154,7 +162,7 @@ prom_query_input_device() return PROMDEV_I_UNK; case PROM_AP1000: return PROMDEV_I_UNK; - }; + } } /* Query for output device type */ @@ -190,9 +198,12 @@ prom_query_output_device() return PROMDEV_OSCREEN; } if(prom_vers == PROM_V3) { - if(strncmp("serial", propb, sizeof("serial"))) + if(propl >= 0 && + strncmp("serial", propb, sizeof("serial")) != 0) return PROMDEV_O_UNK; prom_getproperty(prom_root_node, "stdout-path", propb, sizeof(propb)); + if(strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0) + return PROMDEV_OTTYA; p = propb; while(*p) p++; p -= 2; if(p[0]==':') { @@ -201,9 +212,7 @@ prom_query_output_device() else if(p[1] == 'b') return PROMDEV_OTTYB; } - return PROMDEV_O_UNK; } else { - /* This works on SS-2 (an early OpenFirmware) still. */ switch(*romvec->pv_stdin) { case PROMDEV_TTYA: return PROMDEV_OTTYA; case PROMDEV_TTYB: return PROMDEV_OTTYB; @@ -212,7 +221,6 @@ prom_query_output_device() break; case PROM_AP1000: default: - return PROMDEV_I_UNK; - }; + } return PROMDEV_O_UNK; } diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c index 1256aacec..2e79057d8 100644 --- a/arch/sparc/prom/tree.c +++ b/arch/sparc/prom/tree.c @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.24 1998/03/09 14:04:29 jj Exp $ +/* $Id: tree.c,v 1.25 1998/09/17 11:04:58 jj Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/ctype.h> #include <asm/openprom.h> #include <asm/oplib.h> @@ -257,29 +258,49 @@ char * prom_nextprop(int node, char *oprop, char *buffer) int prom_finddevice(char *name) { - int topnd = prom_getchild(prom_root_node); - int srch; - - if(name[0] == '/') - name++; - if(sparc_cpu_model == sun4d) { - if(!strcmp(name, "sbus")) - name = "sbi"; - if((srch = prom_searchsiblings(topnd, "io-unit")) == 0 || - (srch = prom_getchild(srch)) == 0 || - (srch = prom_searchsiblings(srch, name)) == 0) { - prom_printf("%s prom node not found.\n", name); - prom_halt(); - } - } else if((srch = prom_searchsiblings(topnd, name)) == 0) { - if((srch = prom_searchsiblings(topnd, "iommu")) == 0 || - (srch = prom_getchild(srch)) == 0 || - (srch = prom_searchsiblings(srch, name)) == 0) { - prom_printf("Cannot find node %s\n", name); - prom_halt(); + char nbuf[128]; + char *s = name, *d; + int node = prom_root_node, node2; + unsigned int which_io, phys_addr; + struct linux_prom_registers reg[PROMREG_MAX]; + + while (*s++) { + if (!*s) return node; /* path '.../' is legal */ + node = prom_getchild(node); + + for (d = nbuf; *s != 0 && *s != '@' && *s != '/';) + *d++ = *s++; + *d = 0; + + node = prom_searchsiblings(node, nbuf); + if (!node) + return 0; + + if (*s == '@') { + if (isxdigit(s[1]) && s[2] == ',') { + which_io = simple_strtoul(s+1, NULL, 16); + phys_addr = simple_strtoul(s+3, &d, 16); + if (d != s + 3 && (!*d || *d == '/') + && d <= s + 3 + 8) { + node2 = node; + while (node2 && node2 != -1) { + if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) { + if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) { + node = node2; + break; + } + } + node2 = prom_getsibling(node2); + if (!node2 || node2 == -1) + break; + node2 = prom_searchsiblings(prom_getsibling(node2), nbuf); + } + } + } + while (*s != 0 && *s != '/') s++; } } - return srch; + return node; } int prom_node_has_property(int node, char *prop) diff --git a/arch/sparc/vmlinux.lds b/arch/sparc/vmlinux.lds index cbfc9fb3c..13e4d7202 100644 --- a/arch/sparc/vmlinux.lds +++ b/arch/sparc/vmlinux.lds @@ -22,7 +22,9 @@ SECTIONS .data1 : { *(.data1) } _edata = .; PROVIDE (edata = .); + __start___fixup = .; .fixup : { *(.fixup) } + __stop___fixup = .; __start___ex_table = .; __ex_table : { *(__ex_table) } __stop___ex_table = .; diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index d8cc0f76e..01d44a3fb 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -1,26 +1,40 @@ -# $Id: Makefile,v 1.27 1998/07/27 07:36:16 davem Exp $ +# $Id: Makefile,v 1.33 1998/10/19 07:04:02 jj Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the # 64-bit Sparc. # -# Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) +# Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) +# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) # # If the solaris /bin/sh wasn't so broken, I wouldn't need the following # line... SHELL =/bin/bash -CC = sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include +CC := sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include + +CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| \)' > /dev/null; then echo y; else echo n; fi) +IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi) +NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) + +ifneq ($(CC_HAS_ARGS),y) +MAKEOVERRIDES := $(shell echo "$(MAKEOVERRIDES)" | sed 's CC=$(CC) CC=$(CC)\\\ -D__KERNEL__\\\ -I$(TOPDIR)/include ') +override CC := $(CC) -D__KERNEL__ -I$(TOPDIR)/include +endif + +ifneq ($(NEW_GAS),y) AS = sparc64-linux-as LD = sparc64-linux-ld NM = sparc64-linux-nm AR = sparc64-linux-ar RANLIB = sparc64-linux-ranlib +else +AS := $(AS) -64 +LD := $(LD) -m elf64_sparc +endif ELFTOAOUT = elftoaout -IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi) - # # Uncomment the first CFLAGS if you are doing kgdb source level # debugging of the kernel to get the proper debugging information. @@ -30,10 +44,20 @@ ifneq ($(IS_EGCS),y) CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare else - CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mcmodel=medlow \ + CFLAGS := $(CFLAGS) -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare endif +# Uncomment this to get spinlock/rwlock debugging on SMP. +# DEBUG_SPINLOCK = 1 + +ifdef SMP + ifdef DEBUG_SPINLOCK + CFLAGS += -DSPIN_LOCK_DEBUG + AFLAGS += -DSPIN_LOCK_DEBUG + endif +endif + LINKFLAGS = -T arch/sparc64/vmlinux.lds HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index 2caead01d..103767d64 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.55 1998/08/03 15:28:38 davem Exp $ +# $Id: config.in,v 1.58 1998/11/16 04:47:30 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -51,14 +51,15 @@ else define_bool CONFIG_SUN_CONSOLE y define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y - define_bool CONFIG_PCI y - define_bool CONFIG_PCI_CONSOLE y + bool 'PCI support' CONFIG_PCI source drivers/sbus/char/Config.in source drivers/sbus/audio/Config.in fi tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS -bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC +if [ "$CONFIG_PCI" = "y" ]; then + bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC +fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT @@ -223,7 +224,10 @@ if [ "$CONFIG_NET" = "y" ]; then tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 - tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX +# Turned off until updated 3c59x.c driver +# gets approved by Linus... --DAVEM +# +# tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX fi # bool 'FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then @@ -246,5 +250,5 @@ mainmenu_option next_comment comment 'Kernel hacking' bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ -bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP +#bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP endmenu diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 35f1219fd..3b743920f 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -27,6 +27,7 @@ CONFIG_VT_CONSOLE=y CONFIG_PROM_CONSOLE=y CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_MATROX is not set CONFIG_FB_SBUS=y CONFIG_FB_CREATOR=y CONFIG_FB_CGSIX=y @@ -55,7 +56,6 @@ CONFIG_SUN_CONSOLE=y CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y -CONFIG_PCI_CONSOLE=y # # Misc Linux/SPARC drivers @@ -73,6 +73,8 @@ CONFIG_OBP_FLASH=m # CONFIG_SPARCAUDIO is not set # CONFIG_SPARCAUDIO_AMD7930 is not set # CONFIG_SPARCAUDIO_CS4231 is not set +# CONFIG_SPARCAUDIO_DBRI is not set +# CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m CONFIG_PCI_OLD_PROC=y CONFIG_NET=y @@ -86,12 +88,13 @@ CONFIG_BINFMT_ELF32=y CONFIG_BINFMT_MISC=m CONFIG_BINFMT_JAVA=m CONFIG_SOLARIS_EMUL=m -CONFIG_PARPORT=y -CONFIG_PARPORT_AX=y +CONFIG_PARPORT=m +CONFIG_PARPORT_AX=m +CONFIG_PARPORT_LOWLEVEL_MODULE=y # CONFIG_PARPORT_OTHER is not set -CONFIG_PRINTER=y +CONFIG_PRINTER=m CONFIG_PRINTER_READBACK=y -CONFIG_ENVCTRL=y +CONFIG_ENVCTRL=m # # Floppy, IDE, and other block devices @@ -105,7 +108,7 @@ CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_IDE=y CONFIG_BLK_DEV_IDEDISK=y CONFIG_BLK_DEV_IDECD=y @@ -122,11 +125,9 @@ CONFIG_BLK_DEV_CMD646=y # Networking options # CONFIG_PACKET=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -# CONFIG_NETLINK_DEV is not set +# CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y +# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -136,8 +137,7 @@ CONFIG_INET=y # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -CONFIG_IP_ALIAS=y -# CONFIG_ARPD is not set +# CONFIG_IP_ALIAS is not set # CONFIG_SYN_COOKIES is not set # @@ -165,18 +165,7 @@ CONFIG_ATALK=m # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set # CONFIG_CPU_IS_SLOW is not set -CONFIG_NET_SCHED=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_CSZ=m -CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -# CONFIG_NET_QOS is not set -# CONFIG_NET_CLS is not set +# CONFIG_NET_SCHED is not set # # SCSI support @@ -210,7 +199,7 @@ CONFIG_SCSI_AIC7XXX=y # CONFIG_AIC7XXX_PROC_STATS is not set CONFIG_AIC7XXX_RESET_DELAY=5 CONFIG_SCSI_NCR53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=10 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set @@ -249,8 +238,7 @@ CONFIG_SUNLANCE=y CONFIG_HAPPYMEAL=y CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m -CONFIG_DE4X5=y -CONFIG_VORTEX=m +CONFIG_DE4X5=m # # Filesystems @@ -258,18 +246,19 @@ CONFIG_VORTEX=m # CONFIG_QUOTA is not set CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y +CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=m CONFIG_PROC_FS=y CONFIG_NFS_FS=y CONFIG_NFSD=m +# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set +CONFIG_CODA_FS=m CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m @@ -292,7 +281,7 @@ CONFIG_BSD_DISKLABEL=y CONFIG_SMD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_ADFS_FS is not set -# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set # CONFIG_MAC_PARTITION is not set CONFIG_NLS=y @@ -335,4 +324,3 @@ CONFIG_NLS=y # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set -# CONFIG_EC_FLUSH_TRAP is not set diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index ac61935c8..4d1b1eb35 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.38 1998/07/26 03:02:47 davem Exp $ +# $Id: Makefile,v 1.41 1998/10/11 06:58:14 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -20,9 +20,13 @@ O_OBJS := process.o setup.o cpu.o idprom.o \ traps.o devices.o auxio.o ioport.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o sys_sunos32.o sunos_ioctl32.o \ - central.o psycho.o ebus.o + central.o psycho.o OX_OBJS := sparc64_ksyms.o +ifdef CONFIG_PCI + O_OBJS += ebus.o +endif + ifdef SMP O_OBJS += smp.o trampoline.o endif @@ -48,6 +52,12 @@ head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \ # binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c +ifneq ($(IS_EGCS),y) + CMODEL_CFLAG := -mmedlow +else + CMODEL_CFLAG := -mcmodel=medlow +endif + check_asm: dummy @echo "/* Automatically generated. Do not edit. */" > asm_offsets.h @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h @@ -70,7 +80,7 @@ check_asm: dummy @rm -f tmp.[ci] #$(CC) -o check_asm check_asm.c # <hack> Until we can do this natively, a hack has to take place - $(CC) -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c + $(CC) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s @rm -f check_asm.s # </hack> @@ -79,6 +89,8 @@ check_asm: dummy @echo "" >> asm_offsets.h @echo "#else /* __SMP__ */" >> asm_offsets.h @echo "" >> asm_offsets.h + @echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h + @echo "" >> asm_offsets.h @echo "#include <linux/sched.h>" > tmp.c $(CC) -D__SMP__ -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @@ -94,12 +106,37 @@ check_asm: dummy @rm -f tmp.[ci] #$(CC) -D__SMP__ -o check_asm check_asm.c # <hack> Until we can do this natively, a hack has to take place - $(CC) -D__SMP__ -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c + $(CC) -D__SMP__ $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c + $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s + @rm -f check_asm.s + # </hack> + ./check_asm >> asm_offsets.h + @rm -f check_asm check_asm.c + @echo "" >> asm_offsets.h + @echo "#else /* SPIN_LOCK_DEBUG */" >> asm_offsets.h + @echo "" >> asm_offsets.h + @echo "#include <linux/sched.h>" > tmp.c + $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i + @echo "/* Automatically generated. Do not edit. */" > check_asm.c + @echo "#include <linux/sched.h>" >> check_asm.c + @echo 'struct task_struct _task;' >> check_asm.c + @echo 'struct mm_struct _mm;' >> check_asm.c + @echo 'struct thread_struct _thread;' >> check_asm.c + @echo 'int main(void) {' >> check_asm.c + $(SH) ./check_asm.sh task tmp.i check_asm.c + $(SH) ./check_asm.sh mm tmp.i check_asm.c + $(SH) ./check_asm.sh thread tmp.i check_asm.c + @echo 'return 0; }' >> check_asm.c + @rm -f tmp.[ci] + #$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c + # <hack> Until we can do this natively, a hack has to take place + $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s @rm -f check_asm.s # </hack> ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c + @echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h @echo "" >> asm_offsets.h @echo "#endif /* __SMP__ */" >> asm_offsets.h @echo "" >> asm_offsets.h diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index b0dd675b0..dc898e300 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -91,7 +91,7 @@ do_aout32_core_dump(long signr, struct pt_regs * regs) # define START_DATA(u) (u.u_tsize) # define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1)) - if (!current->dumpable || current->mm->count != 1) + if (!current->dumpable || atomic_read(¤t->mm->count) != 1) return 0; current->dumpable = 0; @@ -106,7 +106,7 @@ do_aout32_core_dump(long signr, struct pt_regs * regs) #else corefile[4] = '\0'; #endif - dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC, 0600); + dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); if (IS_ERR(dentry)) { dentry = NULL; goto end_coredump; @@ -201,7 +201,8 @@ aout32_core_dump(long signr, struct pt_regs * regs) * memory and creates the pointer tables from them, and puts their * addresses on the "stack", returning the new stack pointer value. */ -#define A(x) ((unsigned long)x) +#define A(__x) ((unsigned long)(__x)) + static u32 *create_aout32_tables(char * p, struct linux_binprm * bprm) { u32 *argv, *envp; diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index ef41e3f7a..f0c36d1a7 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -1,19 +1,133 @@ -/* binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. +/* + * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. * + * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) */ #define ELF_ARCH EM_SPARC #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB; +/* For the most part we present code dumps in the format + * Solaris does. + */ +typedef unsigned int elf_greg_t; +#define ELF_NGREG 38 +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +/* Format is: + * G0 --> G7 + * O0 --> O7 + * L0 --> L7 + * I0 --> I7 + * PSR, PC, nPC, Y, WIM, TBR + */ +#include <asm/psrcompat.h> +#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ +do { unsigned int *dest = &(__elf_regs[0]); \ + struct pt_regs *src = (__pt_regs); \ + unsigned int *sp; \ + int i; \ + for(i = 0; i < 16; i++) \ + dest[i] = (unsigned int) src->u_regs[i];\ + /* Don't try this at home kids... */ \ + set_fs(USER_DS); \ + sp = (unsigned int *) (src->u_regs[14] & \ + 0x00000000fffffffc); \ + for(i = 0; i < 16; i++) \ + __get_user(dest[i+16], &sp[i]); \ + set_fs(KERNEL_DS); \ + dest[32] = tstate_to_psr(src->tstate); \ + dest[33] = (unsigned int) src->tpc; \ + dest[34] = (unsigned int) src->tnpc; \ + dest[35] = src->y; \ + dest[36] = dest[37] = 0; /* XXX */ \ +} while(0); + +typedef struct { + union { + unsigned int pr_regs[32]; + unsigned long pr_dregs[16]; + } pr_fr; + unsigned int __unused; + unsigned int pr_fsr; + unsigned char pr_qcnt; + unsigned char pr_q_entrysize; + unsigned char pr_en; + unsigned int pr_q[64]; +} elf_fpregset_t; + +/* UltraSparc extensions. Still unused, but will be eventually. */ +typedef struct { + unsigned int pr_type; + unsigned int pr_align; + union { + struct { + union { + unsigned int pr_regs[32]; + unsigned long pr_dregs[16]; + long double pr_qregs[8]; + } pr_xfr; + } pr_v8p; + unsigned int pr_xfsr; + unsigned int pr_fprs; + unsigned int pr_xg[8]; + unsigned int pr_xo[8]; + unsigned long pr_tstate; + unsigned int pr_filler[8]; + } pr_un; +} elf_xregset_t; + #define elf_check_arch(x) (((x) == EM_SPARC) || ((x) == EM_SPARC32PLUS)) -#define ELF_ET_DYN_BASE 0x60000000 +#define ELF_ET_DYN_BASE 0x08000000 #include <asm/processor.h> #include <linux/module.h> #include <linux/config.h> +#include <linux/elfcore.h> + +struct timeval32 +{ + int tv_sec, tv_usec; +}; + +#define elf_prstatus elf_prstatus32 +struct elf_prstatus32 +{ + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + unsigned int pr_sigpend; /* Set of pending signals */ + unsigned int pr_sighold; /* Set of held signals */ + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct timeval32 pr_utime; /* User time */ + struct timeval32 pr_stime; /* System time */ + struct timeval32 pr_cutime; /* Cumulative user time */ + struct timeval32 pr_cstime; /* Cumulative system time */ + elf_gregset_t pr_reg; /* GP registers */ + int pr_fpvalid; /* True if math co-processor being used. */ +}; + +#define elf_prpsinfo elf_prpsinfo32 +struct elf_prpsinfo32 +{ + char pr_state; /* numeric process state */ + char pr_sname; /* char for pr_state */ + char pr_zomb; /* zombie */ + char pr_nice; /* nice val */ + unsigned int pr_flag; /* flags */ + u16 pr_uid; + u16 pr_gid; + pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* filename of executable */ + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ +}; #define elf_addr_t u32 #define elf_caddr_t u32 diff --git a/arch/sparc64/kernel/check_asm.sh b/arch/sparc64/kernel/check_asm.sh index 2d2fbd224..fd56d4e3b 100644 --- a/arch/sparc64/kernel/check_asm.sh +++ b/arch/sparc64/kernel/check_asm.sh @@ -1,3 +1,4 @@ #!/bin/sh sed -n -e '/struct[ ]*'$1'_struct[ ]*{/,/};/p' < $2 | sed '/struct[ ]*'$1'_struct[ ]*{/d;/:[0-9]*[ ]*;/d;/^[ ]*$/d;/};/d;s/^[ ]*//;s/volatile[ ]*//;s/\(unsigned\|signed\|struct\)[ ]*//;s/\(\[\|__attribute__\).*;[ ]*$//;s/;[ ]*$//;s/^[^ ]*[ ]*//;s/,/\ /g' | sed 's/^[ *]*//;s/[ ]*$//;s/^.*$/printf ("#define AOFF_'$1'_\0 0x%08x\\n#define ASIZ_'$1'_\0 0x%08x\\n", ((char *)\&_'$1'.\0) - ((char *)\&_'$1'), sizeof(_'$1'.\0));/' >> $3 +echo "printf (\"#define ASIZ_$1\\t0x%08x\\n\", sizeof(_$1));" >> $3 diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S index b3d0a1eb7..6207101fd 100644 --- a/arch/sparc64/kernel/dtlb_backend.S +++ b/arch/sparc64/kernel/dtlb_backend.S @@ -1,4 +1,4 @@ -/* $Id: dtlb_backend.S,v 1.4 1998/06/15 16:59:34 jj Exp $ +/* $Id: dtlb_backend.S,v 1.6 1998/09/24 03:21:32 davem Exp $ * dtlb_backend.S: Back end to DTLB miss replacement strategy. * This is included directly into the trap table. * diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 70465afbd..e60a5dc62 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.29 1998/07/01 15:39:44 jj Exp $ +/* $Id: ebus.c,v 1.33 1998/09/21 05:06:03 jj Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -31,7 +31,6 @@ struct linux_ebus *ebus_chain = 0; extern void prom_ebus_ranges_init(struct linux_ebus *); extern void prom_ebus_intmap_init(struct linux_ebus *); -extern void pci_console_init(void); #ifdef CONFIG_SUN_OPENPROMIO extern int openprom_init(void); @@ -227,7 +226,6 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) } } -extern void sun4u_start_timers(void); extern void clock_probe(void); __initfunc(void ebus_init(void)) @@ -367,10 +365,6 @@ __initfunc(void ebus_init(void)) ++num_ebus; } -#ifndef CONFIG_FB - pci_console_init(); -#endif - #ifdef CONFIG_SUN_OPENPROMIO openprom_init(); #endif @@ -389,6 +383,5 @@ __initfunc(void ebus_init(void)) #ifdef CONFIG_OBP_FLASH flash_init(); #endif - sun4u_start_timers(); clock_probe(); } diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 774839af6..7c0d80eb4 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.87 1998/07/29 16:32:28 jj Exp $ +/* $Id: entry.S,v 1.91 1998/10/07 01:27:08 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -373,17 +373,112 @@ netbsd_syscall: retl nop + /* These next few routines must be sure to clear the + * SFSR FaultValid bit so that the fast tlb data protection + * handler does not flush the wrong context and lock up the + * box. + */ + .globl __do_data_access_exception + .globl __do_data_access_exception_tl1 +__do_data_access_exception_tl1: + rdpr %pstate, %g4 + wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate + rdpr %tl, %g3 + cmp %g3, 1 + mov TLB_SFSR, %g3 + mov DMMU_SFAR, %g5 + ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR + ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR + stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit + membar #Sync + bgu,pn %icc, winfix_dax + rdpr %tpc, %g3 + sethi %hi(109f), %g7 + ba,pt %xcc, etraptl1 + or %g7, %lo(109f), %g7 ! Merge in below +__do_data_access_exception: + rdpr %pstate, %g4 + wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate + mov TLB_SFSR, %g3 + mov DMMU_SFAR, %g5 + ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR + ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR + stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit + membar #Sync + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call data_access_exception + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + + .globl __do_instruction_access_exception + .globl __do_instruction_access_exception_tl1 +__do_instruction_access_exception_tl1: + rdpr %pstate, %g4 + wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate + mov TLB_SFSR, %g3 + mov DMMU_SFAR, %g5 + ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR + ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR + stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit + membar #Sync + sethi %hi(109f), %g7 + ba,pt %xcc, etraptl1 + or %g7, %lo(109f), %g7 ! Merge in below +__do_instruction_access_exception: + rdpr %pstate, %g4 + wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate + mov TLB_SFSR, %g3 + mov DMMU_SFAR, %g5 + ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR + ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR + stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit + membar #Sync + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call instruction_access_exception + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + + .globl __do_privact +__do_privact: + mov TLB_SFSR, %g3 + stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit + membar #Sync + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + call do_privact + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + .globl do_mna do_mna: rdpr %tl, %g3 cmp %g3, 1 - bgu,a,pn %icc, winfix_mna - rdpr %tpc, %g3 + + /* Setup %g4/%g5 now as they are used in the + * winfixup code. + */ + mov TLB_SFSR, %g3 mov DMMU_SFAR, %g4 - mov TLB_SFSR, %g5 - sethi %hi(109f), %g7 ldxa [%g4] ASI_DMMU, %g4 - ldxa [%g5] ASI_DMMU, %g5 + ldxa [%g3] ASI_DMMU, %g5 + stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit + membar #Sync + bgu,pn %icc, winfix_dax + rdpr %tpc, %g3 + +1: sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 mov %l4, %o1 @@ -395,11 +490,13 @@ do_mna: .globl do_lddfmna do_lddfmna: - mov DMMU_SFAR, %g4 - mov TLB_SFSR, %g5 sethi %hi(109f), %g7 + mov TLB_SFSR, %g4 + ldxa [%g4] ASI_DMMU, %g5 + stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit + membar #Sync + mov DMMU_SFAR, %g4 ldxa [%g4] ASI_DMMU, %g4 - ldxa [%g5] ASI_DMMU, %g5 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 mov %l4, %o1 @@ -411,11 +508,13 @@ do_lddfmna: .globl do_stdfmna do_stdfmna: - mov DMMU_SFAR, %g4 - mov TLB_SFSR, %g5 sethi %hi(109f), %g7 + mov TLB_SFSR, %g4 + ldxa [%g4] ASI_DMMU, %g5 + stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit + membar #Sync + mov DMMU_SFAR, %g4 ldxa [%g4] ASI_DMMU, %g4 - ldxa [%g5] ASI_DMMU, %g5 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 mov %l4, %o1 @@ -631,7 +730,7 @@ sys_clone: flushw mov %l5, %o7 ret_from_syscall: /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in - * %o7 for us. + * %o7 for us. Check performance counter stuff too. */ andn %o7, 0x100, %o7 sth %o7, [%g6 + AOFF_task_tss + AOFF_thread_flags] @@ -640,7 +739,13 @@ ret_from_syscall: membar #StoreStore | #LoadStore stb %g0, [%o4 + %lo(scheduler_lock)] #endif - b,pt %xcc, ret_sys_call + andcc %o7, 0x200, %g0 + be,pt %icc, 1f + nop + ldx [%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7 + wr %g0, %o7, %pcr + wr %g0, %g0, %pic +1: b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 sparc_exit: rdpr %otherwin, %g1 rdpr %pstate, %g2 diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index f1e9c62fd..8c92688f1 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.53 1998/06/15 16:59:35 jj Exp $ +/* $Id: head.S,v 1.54 1998/10/06 20:48:30 ecd Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -380,6 +380,9 @@ setup_tba: or %g5, %lo(ivector_to_mask), %g1 /* IVECTOR table */ mov 0x40, %g2 /* INTR data 0 register */ + /* Kill PROM timer */ + wr %g0, 0, %tick_cmpr + /* Ok, we're done setting up all the state our trap mechanims needs, * now get back into normal globals and let the PROM know what is up. */ diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 51fbd6ce5..42f3de3b8 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.48 1998/08/03 23:58:04 davem Exp $ +/* $Id: ioctl32.c,v 1.55 1998/11/17 07:43:17 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -34,12 +34,14 @@ #include <linux/tty.h> #include <linux/vt_kern.h> #include <linux/fb.h> +#include <linux/ext2_fs.h> #include <scsi/scsi.h> /* Ugly hack. */ #undef __KERNEL__ #include <scsi/scsi_ioctl.h> #define __KERNEL__ +#include <scsi/sg.h> #include <asm/types.h> #include <asm/uaccess.h> @@ -51,16 +53,28 @@ #include <asm/envctrl.h> #include <asm/audioio.h> -/* As gcc will warn about casting u32 to some ptr, we have to cast it to - * unsigned long first, and that's what is A() for. - * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) - * or instead of just (void *)x, which will produce warnings. - */ -#define A(x) ((unsigned long)x) +#include <linux/soundcard.h> + +/* Use this to get at 32-bit user passed pointers. + See sys_sparc32.c for description about these. */ +#define A(__x) ((unsigned long)(__x)) +#define AA(__x) \ +({ unsigned long __ret; \ + __asm__ ("srl %0, 0, %0" \ + : "=r" (__ret) \ + : "0" (__x)); \ + __ret; \ +}) + +/* Aiee. Someone does not find a difference between int and long */ +#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) +#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) +#define EXT2_IOC32_GETVERSION _IOR('v', 1, int) +#define EXT2_IOC32_SETVERSION _IOW('v', 2, int) extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); -static int w_long(unsigned int fd, unsigned int cmd, u32 arg) +static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); int err; @@ -69,35 +83,47 @@ static int w_long(unsigned int fd, unsigned int cmd, u32 arg) set_fs (KERNEL_DS); err = sys_ioctl(fd, cmd, (unsigned long)&val); set_fs (old_fs); - if (!err && put_user(val, (u32 *)A(arg))) + if (!err && put_user(val, (u32 *)arg)) return -EFAULT; return err; } -static int rw_long(unsigned int fd, unsigned int cmd, u32 arg) +static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); int err; unsigned long val; - if(get_user(val, (u32 *)A(arg))) + if(get_user(val, (u32 *)arg)) return -EFAULT; set_fs (KERNEL_DS); err = sys_ioctl(fd, cmd, (unsigned long)&val); set_fs (old_fs); - if (!err && put_user(val, (u32 *)A(arg))) + if (!err && put_user(val, (u32 *)arg)) return -EFAULT; return err; } + +static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* These are just misnamed, they actually get/put from/to user an int */ + switch (cmd) { + case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; + case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; + case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; + case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; + } + return sys_ioctl(fd, cmd, arg); +} struct timeval32 { int tv_sec; int tv_usec; }; -static int do_siocgstamp(unsigned int fd, unsigned int cmd, u32 arg) +static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct timeval32 *up = (struct timeval32 *)A(arg); + struct timeval32 *up = (struct timeval32 *)arg; struct timeval ktv; mm_segment_t old_fs = get_fs(); int err; @@ -106,10 +132,8 @@ static int do_siocgstamp(unsigned int fd, unsigned int cmd, u32 arg) err = sys_ioctl(fd, cmd, (unsigned long)&ktv); set_fs(old_fs); if(!err) { - if(!access_ok(VERIFY_WRITE, up, sizeof(*up)) || - __put_user(ktv.tv_sec, &up->tv_sec) || - __put_user(ktv.tv_usec, &up->tv_usec)) - err = -EFAULT; + err = put_user(ktv.tv_sec, &up->tv_sec); + err |= __put_user(ktv.tv_usec, &up->tv_usec); } return err; } @@ -149,7 +173,7 @@ struct ifconf32 { __kernel_caddr_t32 ifcbuf; }; -static inline int dev_ifconf(unsigned int fd, u32 arg) +static inline int dev_ifconf(unsigned int fd, unsigned long arg) { struct ifconf32 ifc32; struct ifconf ifc; @@ -159,7 +183,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg) unsigned int i, j; int err; - if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32))) + if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32))) return -EFAULT; if(ifc32.ifcbuf == 0) { @@ -199,7 +223,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg) ifc32.ifc_len = i; else ifc32.ifc_len = i - sizeof (struct ifreq32); - if (copy_to_user((struct ifconf32 *)A(arg), &ifc32, sizeof(struct ifconf32))) + if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32))) err = -EFAULT; } } @@ -208,7 +232,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg) return err; } -static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) +static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ifreq ifr; mm_segment_t old_fs; @@ -216,26 +240,27 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) switch (cmd) { case SIOCSIFMAP: - if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) || - __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) || - __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) || - __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) || - __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) || - __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) || - __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port))) + err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name)); + err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); + err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); + err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); + err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); + err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); + err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); + if (err) return -EFAULT; break; case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: - if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32))) + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) return -EFAULT; ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); if (!ifr.ifr_data) return -EAGAIN; break; default: - if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32))) + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) return -EFAULT; break; } @@ -255,7 +280,7 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: case SIOCGIFNETMASK: - if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32))) + if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32))) return -EFAULT; break; case SIOCGPPPSTATS: @@ -265,7 +290,7 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) u32 data; int len; - __get_user(data, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_data)); + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); if(cmd == SIOCGPPPVER) len = strlen(PPP_VERSION) + 1; else if(cmd == SIOCGPPPCSTATS) @@ -278,14 +303,13 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) break; } case SIOCGIFMAP: - if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) || - __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) || - __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) || - __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) || - __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) || - __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) || - __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port))) - return -EFAULT; + err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name)); + err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); + err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); + err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); + err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); + err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); + err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); break; } } @@ -311,7 +335,7 @@ struct rtentry32 { }; -static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct rtentry r; char devname[16]; @@ -319,19 +343,20 @@ static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg) int ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) || - __get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) || - __get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) || - __get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) || - __get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) || - __get_user (r.rt_irtt, &(((struct rtentry32 *)A(arg))->rt_irtt)) || - __get_user (rtdev, &(((struct rtentry32 *)A(arg))->rt_dev)) || - (rtdev && copy_from_user (devname, (char *)A(rtdev), 15))) - return -EFAULT; + ret = copy_from_user (&r.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); + ret |= __get_user (r.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); + ret |= __get_user (r.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); + ret |= __get_user (r.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); + ret |= __get_user (r.rt_window, &(((struct rtentry32 *)arg)->rt_window)); + ret |= __get_user (r.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); + ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); if (rtdev) { + ret |= copy_from_user (devname, (char *)A(rtdev), 15); r.rt_dev = devname; devname[15] = 0; } else r.rt_dev = 0; + if (ret) + return -EFAULT; set_fs (KERNEL_DS); ret = sys_ioctl (fd, cmd, (long)&r); set_fs (old_fs); @@ -345,7 +370,7 @@ struct hd_geometry32 { u32 start; }; -static inline int hdio_getgeo(unsigned int fd, u32 arg) +static inline int hdio_getgeo(unsigned int fd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct hd_geometry geo; @@ -355,9 +380,8 @@ static inline int hdio_getgeo(unsigned int fd, u32 arg) err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); set_fs (old_fs); if (!err) { - if (copy_to_user ((struct hd_geometry32 *)A(arg), &geo, 4) || - __put_user (geo.start, &(((struct hd_geometry32 *)A(arg))->start))) - return -EFAULT; + err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4); + err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start)); } return err; } @@ -373,7 +397,7 @@ struct fbcmap32 { #define FBIOPUTCMAP32 _IOW('F', 3, struct fbcmap32) #define FBIOGETCMAP32 _IOW('F', 4, struct fbcmap32) -static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg) +static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, unsigned long arg) { struct fbcmap f; int ret; @@ -381,19 +405,21 @@ static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg) u32 r, g, b; mm_segment_t old_fs = get_fs(); - if (get_user(f.index, &(((struct fbcmap32 *)A(arg))->index)) || - __get_user(f.count, &(((struct fbcmap32 *)A(arg))->count)) || - __get_user(r, &(((struct fbcmap32 *)A(arg))->red)) || - __get_user(g, &(((struct fbcmap32 *)A(arg))->green)) || - __get_user(b, &(((struct fbcmap32 *)A(arg))->blue))) + ret = get_user(f.index, &(((struct fbcmap32 *)arg)->index)); + ret |= __get_user(f.count, &(((struct fbcmap32 *)arg)->count)); + ret |= __get_user(r, &(((struct fbcmap32 *)arg)->red)); + ret |= __get_user(g, &(((struct fbcmap32 *)arg)->green)); + ret |= __get_user(b, &(((struct fbcmap32 *)arg)->blue)); + if (ret) return -EFAULT; if ((f.index < 0) || (f.index > 255)) return -EINVAL; if (f.index + f.count > 256) f.count = 256 - f.index; if (cmd == FBIOPUTCMAP32) { - if (copy_from_user (red, (char *)A(r), f.count) || - copy_from_user (green, (char *)A(g), f.count) || - copy_from_user (blue, (char *)A(b), f.count)) + ret = copy_from_user (red, (char *)A(r), f.count); + ret |= copy_from_user (green, (char *)A(g), f.count); + ret |= copy_from_user (blue, (char *)A(b), f.count); + if (ret) return -EFAULT; } f.red = red; f.green = green; f.blue = blue; @@ -401,10 +427,9 @@ static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg) ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP_SPARC : FBIOGETCMAP_SPARC, (long)&f); set_fs (old_fs); if (!ret && cmd == FBIOGETCMAP32) { - if (copy_to_user ((char *)A(r), red, f.count) || - copy_to_user ((char *)A(g), green, f.count) || - copy_to_user ((char *)A(b), blue, f.count)) - return -EFAULT; + ret = copy_to_user ((char *)A(r), red, f.count); + ret |= copy_to_user ((char *)A(g), green, f.count); + ret |= copy_to_user ((char *)A(b), blue, f.count); } return ret; } @@ -423,7 +448,7 @@ struct fbcursor32 { #define FBIOSCURSOR32 _IOW('F', 24, struct fbcursor32) #define FBIOGCURSOR32 _IOW('F', 25, struct fbcursor32) -static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg) +static inline int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg) { struct fbcursor f; int ret; @@ -433,29 +458,32 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg) u32 m, i; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&f, (struct fbcursor32 *)A(arg), 2 * sizeof (short) + 2 * sizeof(struct fbcurpos)) || - __get_user(f.size.fbx, &(((struct fbcursor32 *)A(arg))->size.fbx)) || - __get_user(f.size.fby, &(((struct fbcursor32 *)A(arg))->size.fby)) || - __get_user(f.cmap.index, &(((struct fbcursor32 *)A(arg))->cmap.index)) || - __get_user(f.cmap.count, &(((struct fbcursor32 *)A(arg))->cmap.count)) || - __get_user(r, &(((struct fbcursor32 *)A(arg))->cmap.red)) || - __get_user(g, &(((struct fbcursor32 *)A(arg))->cmap.green)) || - __get_user(b, &(((struct fbcursor32 *)A(arg))->cmap.blue)) || - __get_user(m, &(((struct fbcursor32 *)A(arg))->mask)) || - __get_user(i, &(((struct fbcursor32 *)A(arg))->image))) + ret = copy_from_user (&f, (struct fbcursor32 *)arg, 2 * sizeof (short) + 2 * sizeof(struct fbcurpos)); + ret |= __get_user(f.size.fbx, &(((struct fbcursor32 *)arg)->size.fbx)); + ret |= __get_user(f.size.fby, &(((struct fbcursor32 *)arg)->size.fby)); + ret |= __get_user(f.cmap.index, &(((struct fbcursor32 *)arg)->cmap.index)); + ret |= __get_user(f.cmap.count, &(((struct fbcursor32 *)arg)->cmap.count)); + ret |= __get_user(r, &(((struct fbcursor32 *)arg)->cmap.red)); + ret |= __get_user(g, &(((struct fbcursor32 *)arg)->cmap.green)); + ret |= __get_user(b, &(((struct fbcursor32 *)arg)->cmap.blue)); + ret |= __get_user(m, &(((struct fbcursor32 *)arg)->mask)); + ret |= __get_user(i, &(((struct fbcursor32 *)arg)->image)); + if (ret) return -EFAULT; if (f.set & FB_CUR_SETCMAP) { if ((uint) f.size.fby > 32) return -EINVAL; - if (copy_from_user (mask, (char *)A(m), f.size.fby * 4) || - copy_from_user (image, (char *)A(i), f.size.fby * 4)) + ret = copy_from_user (mask, (char *)A(m), f.size.fby * 4); + ret |= copy_from_user (image, (char *)A(i), f.size.fby * 4); + if (ret) return -EFAULT; f.image = image; f.mask = mask; } if (f.set & FB_CUR_SETCMAP) { - if (copy_from_user (red, (char *)A(r), 2) || - copy_from_user (green, (char *)A(g), 2) || - copy_from_user (blue, (char *)A(b), 2)) + ret = copy_from_user (red, (char *)A(r), 2); + ret |= copy_from_user (green, (char *)A(g), 2); + ret |= copy_from_user (blue, (char *)A(b), 2); + if (ret) return -EFAULT; f.cmap.red = red; f.cmap.green = green; f.cmap.blue = blue; } @@ -491,7 +519,7 @@ struct fb_cmap32 { __kernel_caddr_t32 transp; }; -static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); u32 red = 0, green = 0, blue = 0, transp = 0; @@ -500,6 +528,7 @@ static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) void *karg; int err = 0; + memset(&cmap, 0, sizeof(cmap)); switch (cmd) { case FBIOGET_FSCREENINFO: karg = &fix; @@ -507,120 +536,91 @@ static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) case FBIOGETCMAP: case FBIOPUTCMAP: karg = &cmap; - if (__get_user(cmap.start, &((struct fb_cmap32 *)A(arg))->start) || - __get_user(cmap.len, &((struct fb_cmap32 *)A(arg))->len) || - __get_user(red, &((struct fb_cmap32 *)A(arg))->red) || - __get_user(green, &((struct fb_cmap32 *)A(arg))->green) || - __get_user(blue, &((struct fb_cmap32 *)A(arg))->blue) || - __get_user(transp, &((struct fb_cmap32 *)A(arg))->transp)) - return -EFAULT; + err = __get_user(cmap.start, &((struct fb_cmap32 *)arg)->start); + err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len); + err |= __get_user(red, &((struct fb_cmap32 *)arg)->red); + err |= __get_user(green, &((struct fb_cmap32 *)arg)->green); + err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue); + err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp); + if (err) + goto out; + err = -ENOMEM; cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); if (!cmap.red) - return -ENOMEM; + goto out; cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.green) { - kfree(cmap.red); - return -ENOMEM; - } + if (!cmap.green) + goto out; cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.blue) { - kfree(cmap.red); - kfree(cmap.green); - return -ENOMEM; - } + if (!cmap.blue) + goto out; if (transp) { cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.transp) { - kfree(cmap.red); - kfree(cmap.green); - kfree(cmap.blue); - return -ENOMEM; - } - } else { + if (!cmap.transp) + goto out; + } else cmap.transp = NULL; - } + if (cmd == FBIOGETCMAP) break; - if (__copy_from_user(cmap.red, (char *)A(((struct fb_cmap32 *)A(arg))->red), - cmap.len * sizeof(__u16)) || - __copy_from_user(cmap.green, (char *)A(((struct fb_cmap32 *)A(arg))->green), - cmap.len * sizeof(__u16)) || - __copy_from_user(cmap.blue, (char *)A(((struct fb_cmap32 *)A(arg))->blue), - cmap.len * sizeof(__u16)) || - (cmap.transp && - __copy_from_user(cmap.transp, (char *)A(((struct fb_cmap32 *)A(arg))->transp), - cmap.len * sizeof(__u16)))) { - kfree(cmap.red); - kfree(cmap.green); - kfree(cmap.blue); - if (cmap.transp) - kfree(cmap.transp); - return -EFAULT; - } + err = __copy_from_user(cmap.red, (char *)A(red), cmap.len * sizeof(__u16)); + err |= __copy_from_user(cmap.green, (char *)A(green), cmap.len * sizeof(__u16)); + err |= __copy_from_user(cmap.blue, (char *)A(blue), cmap.len * sizeof(__u16)); + if (cmap.transp) err |= __copy_from_user(cmap.transp, (char *)A(transp), cmap.len * sizeof(__u16)); + if (err) + goto out; break; default: - printk("%s: Unknown fb ioctl cmd fd(%d) cmd(%08x) arg(%08x)\n", - __FUNCTION__, fd, cmd, arg); + do { + static int count = 0; + if (++count <= 20) + printk("%s: Unknown fb ioctl cmd fd(%d) " + "cmd(%08x) arg(%08lx)\n", + __FUNCTION__, fd, cmd, arg); + } while(0); return -ENOSYS; } set_fs(KERNEL_DS); err = sys_ioctl(fd, cmd, (unsigned long)karg); set_fs(old_fs); if (err) - return err; + goto out; switch (cmd) { case FBIOGET_FSCREENINFO: - if (__copy_to_user((char *)((struct fb_fix_screeninfo32 *)A(arg))->id, - (char *)fix.id, sizeof(fix.id)) || - __put_user((__u32)(unsigned long)fix.smem_start, - &((struct fb_fix_screeninfo32 *)A(arg))->smem_start) || - __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)A(arg))->smem_len) || - __put_user(fix.type, &((struct fb_fix_screeninfo32 *)A(arg))->type) || - __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)A(arg))->type_aux) || - __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)A(arg))->visual) || - __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)A(arg))->xpanstep) || - __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)A(arg))->ypanstep) || - __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)A(arg))->ywrapstep) || - __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)A(arg))->line_length) || - __put_user((__u32)(unsigned long)fix.mmio_start, - &((struct fb_fix_screeninfo32 *)A(arg))->mmio_start) || - __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)A(arg))->mmio_len) || - __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)A(arg))->accel) || - __copy_to_user((char *)((struct fb_fix_screeninfo32 *)A(arg))->reserved, - (char *)fix.reserved, sizeof(fix.reserved))) - return -EFAULT; + err = __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->id, (char *)fix.id, sizeof(fix.id)); + err |= __put_user((__u32)(unsigned long)fix.smem_start, &((struct fb_fix_screeninfo32 *)arg)->smem_start); + err |= __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)arg)->smem_len); + err |= __put_user(fix.type, &((struct fb_fix_screeninfo32 *)arg)->type); + err |= __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)arg)->type_aux); + err |= __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)arg)->visual); + err |= __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)arg)->xpanstep); + err |= __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)arg)->ypanstep); + err |= __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)arg)->ywrapstep); + err |= __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)arg)->line_length); + err |= __put_user((__u32)(unsigned long)fix.mmio_start, &((struct fb_fix_screeninfo32 *)arg)->mmio_start); + err |= __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)arg)->mmio_len); + err |= __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)arg)->accel); + err |= __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->reserved, (char *)fix.reserved, sizeof(fix.reserved)); break; case FBIOGETCMAP: - if (__copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->red), cmap.red, - cmap.len * sizeof(__u16)) || - __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->green), cmap.blue, - cmap.len * sizeof(__u16)) || - __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->blue), cmap.blue, - cmap.len * sizeof(__u16)) || - (cmap.transp && - __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->transp), cmap.transp, - cmap.len * sizeof(__u16)))) { - kfree(cmap.red); - kfree(cmap.green); - kfree(cmap.blue); - if (cmap.transp) - kfree(cmap.transp); - return -EFAULT; - } - /* fall through */ - case FBIOPUTCMAP: - kfree(cmap.red); - kfree(cmap.green); - kfree(cmap.blue); + err = __copy_to_user((char *)A(red), cmap.red, cmap.len * sizeof(__u16)); + err |= __copy_to_user((char *)A(green), cmap.blue, cmap.len * sizeof(__u16)); + err |= __copy_to_user((char *)A(blue), cmap.blue, cmap.len * sizeof(__u16)); if (cmap.transp) - kfree(cmap.transp); + err |= __copy_to_user((char *)A(transp), cmap.transp, cmap.len * sizeof(__u16)); + break; + case FBIOPUTCMAP: break; } - return 0; +out: if (cmap.red) kfree(cmap.red); + if (cmap.green) kfree(cmap.green); + if (cmap.blue) kfree(cmap.blue); + if (cmap.transp) kfree(cmap.transp); + return err; } -static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); unsigned long kval; @@ -632,7 +632,7 @@ static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) set_fs(old_fs); if(error == 0) { - uvp = (unsigned int *)A(arg); + uvp = (unsigned int *)arg; if(put_user(kval, uvp)) error = -EFAULT; } @@ -744,10 +744,10 @@ static struct { #define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0])) -static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); - void *karg; + void *karg = NULL; unsigned int kcmd = 0; int i, err; @@ -771,19 +771,18 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) return -ENOMEM; if (cmd == FDGETPRM32) break; - if (__get_user(f->size, &((struct floppy_struct32 *)A(arg))->size) || - __get_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) || - __get_user(f->head, &((struct floppy_struct32 *)A(arg))->head) || - __get_user(f->track, &((struct floppy_struct32 *)A(arg))->track) || - __get_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) || - __get_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) || - __get_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) || - __get_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) || - __get_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) || - __get_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) { - kfree(karg); - return -EFAULT; - } + err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size); + err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect); + err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head); + err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track); + err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); + err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap); + err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate); + err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); + err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); + err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); + if (err) + goto out; break; } case FDSETDRVPRM32: @@ -796,28 +795,27 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) return -ENOMEM; if (cmd == FDGETDRVPRM32) break; - if (__get_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) || - __get_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) || - __get_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) || - __get_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) || - __get_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) || - __get_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) || - __get_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) || - __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) || - __get_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) || - __get_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) || - __get_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) || - __get_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) || - __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) || - __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)A(arg))->max_errors, sizeof(f->max_errors)) || - __get_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) || - __get_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) || - __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)A(arg))->autodetect, sizeof(f->autodetect)) || - __get_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) || - __get_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) { - kfree(karg); - return -EFAULT; - } + err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); + err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); + err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); + err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); + err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); + err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); + err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); + err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); + err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); + err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); + err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); + err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); + err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); + err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors)); + err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); + err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); + err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect)); + err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); + err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); + if (err) + goto out; break; } case FDGETDRVSTAT32: @@ -842,56 +840,48 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) set_fs (KERNEL_DS); err = sys_ioctl (fd, kcmd, (unsigned long)karg); set_fs (old_fs); - if (err) { - kfree(karg); - return err; - } + if (err) + goto out; switch (cmd) { case FDGETPRM32: { struct floppy_struct *f = karg; - if (__put_user(f->size, &((struct floppy_struct32 *)A(arg))->size) || - __put_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) || - __put_user(f->head, &((struct floppy_struct32 *)A(arg))->head) || - __put_user(f->track, &((struct floppy_struct32 *)A(arg))->track) || - __put_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) || - __put_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) || - __put_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) || - __put_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) || - __put_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) || - __put_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) { - kfree(karg); - return -EFAULT; - } + err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size); + err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect); + err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head); + err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track); + err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); + err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap); + err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate); + err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); + err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); + err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); break; } case FDGETDRVPRM32: { struct floppy_drive_params *f = karg; - if (__put_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) || - __put_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) || - __put_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) || - __put_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) || - __put_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) || - __put_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) || - __put_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) || - __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) || - __put_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) || - __put_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) || - __put_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) || - __put_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) || - __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) || - __copy_to_user(&((struct floppy_drive_params32 *)A(arg))->max_errors, &f->max_errors, sizeof(f->max_errors)) || - __put_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) || - __put_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) || - __copy_to_user(((struct floppy_drive_params32 *)A(arg))->autodetect, f->autodetect, sizeof(f->autodetect)) || - __put_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) || - __put_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) { - kfree(karg); - return -EFAULT; - } + err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); + err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); + err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); + err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); + err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); + err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); + err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); + err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); + err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); + err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); + err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); + err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); + err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); + err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors)); + err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); + err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); + err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect)); + err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); + err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); break; } case FDGETDRVSTAT32: @@ -899,66 +889,57 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { struct floppy_drive_struct *f = karg; - if (__put_user(f->flags, &((struct floppy_drive_struct32 *)A(arg))->flags) || - __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)A(arg))->spinup_date) || - __put_user(f->select_date, &((struct floppy_drive_struct32 *)A(arg))->select_date) || - __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)A(arg))->first_read_date) || - __put_user(f->probed_format, &((struct floppy_drive_struct32 *)A(arg))->probed_format) || - __put_user(f->track, &((struct floppy_drive_struct32 *)A(arg))->track) || - __put_user(f->maxblock, &((struct floppy_drive_struct32 *)A(arg))->maxblock) || - __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)A(arg))->maxtrack) || - __put_user(f->generation, &((struct floppy_drive_struct32 *)A(arg))->generation) || - __put_user(f->keep_data, &((struct floppy_drive_struct32 *)A(arg))->keep_data) || - __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)A(arg))->fd_ref) || - __put_user(f->fd_device, &((struct floppy_drive_struct32 *)A(arg))->fd_device) || - __put_user(f->last_checked, &((struct floppy_drive_struct32 *)A(arg))->last_checked) || - __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)A(arg))->dmabuf) || - __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)A(arg))->bufblocks)) { - kfree(karg); - return -EFAULT; - } + err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags); + err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date); + err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date); + err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date); + err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format); + err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track); + err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock); + err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack); + err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation); + err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data); + err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref); + err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device); + err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked); + err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf); + err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks); break; } case FDGETFDCSTAT32: { struct floppy_fdc_state *f = karg; - if (__put_user(f->spec1, &((struct floppy_fdc_state32 *)A(arg))->spec1) || - __put_user(f->spec2, &((struct floppy_fdc_state32 *)A(arg))->spec2) || - __put_user(f->dtr, &((struct floppy_fdc_state32 *)A(arg))->dtr) || - __put_user(f->version, &((struct floppy_fdc_state32 *)A(arg))->version) || - __put_user(f->dor, &((struct floppy_fdc_state32 *)A(arg))->dor) || - __put_user(f->address, &((struct floppy_fdc_state32 *)A(arg))->address) || - __copy_to_user((char *)&((struct floppy_fdc_state32 *)A(arg))->address - + sizeof(((struct floppy_fdc_state32 *)A(arg))->address), - (char *)&f->address + sizeof(f->address), sizeof(int)) || - __put_user(f->driver_version, &((struct floppy_fdc_state32 *)A(arg))->driver_version) || - __copy_to_user(((struct floppy_fdc_state32 *)A(arg))->track, f->track, sizeof(f->track))) { - kfree(karg); - return -EFAULT; - } + err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1); + err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2); + err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr); + err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version); + err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor); + err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address); + err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address + + sizeof(((struct floppy_fdc_state32 *)arg)->address), + (char *)&f->address + sizeof(f->address), sizeof(int)); + err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version); + err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track)); break; } case FDWERRORGET32: { struct floppy_write_errors *f = karg; - if (__put_user(f->write_errors, &((struct floppy_write_errors32 *)A(arg))->write_errors) || - __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)A(arg))->first_error_sector) || - __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)A(arg))->first_error_generation) || - __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)A(arg))->last_error_sector) || - __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)A(arg))->last_error_generation) || - __put_user(f->badness, &((struct floppy_write_errors32 *)A(arg))->badness)) { - kfree(karg); - return -EFAULT; - } + err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors); + err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector); + err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation); + err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector); + err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation); + err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness); break; } default: break; } - kfree(karg); - return 0; +out: if (karg) kfree(karg); + return err; } struct ppp_option_data32 { @@ -974,7 +955,7 @@ struct ppp_idle32 { }; #define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) -static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct ppp_option_data32 data32; @@ -991,7 +972,7 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) karg = &idle; break; case PPPIOCSCOMPRESS32: - if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32))) + if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32))) return -EFAULT; data.ptr = kmalloc (data32.length, GFP_KERNEL); if (!data.ptr) @@ -1006,8 +987,13 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) karg = &data; break; default: - printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); + do { + static int count = 0; + if (++count <= 20) + printk("ppp_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while(0); return -EINVAL; } set_fs (KERNEL_DS); @@ -1019,7 +1005,7 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) return err; idle32.xmit_idle = idle.xmit_idle; idle32.recv_idle = idle.recv_idle; - if (copy_to_user((struct ppp_idle32 *)A(arg), &idle32, sizeof(struct ppp_idle32))) + if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32))) return -EFAULT; break; case PPPIOCSCOMPRESS32: @@ -1072,7 +1058,7 @@ struct mtconfiginfo32 { #define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32) #define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32) -static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct mtconfiginfo info; @@ -1098,21 +1084,26 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) case MTIOCSETCONFIG32: kcmd = MTIOCSETCONFIG; karg = &info; - if (__get_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) || - __get_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) || - __get_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) || - __get_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) || - __get_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) || - __get_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) || - __copy_from_user((char *)&info.debug + sizeof(info.debug), - (char *)&((struct mtconfiginfo32 *)A(arg))->debug - + sizeof(((struct mtconfiginfo32 *)A(arg))->debug), - sizeof(__u32))) + err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); + err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); + err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); + err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); + err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port); + err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); + err |= __copy_from_user((char *)&info.debug + sizeof(info.debug), + (char *)&((struct mtconfiginfo32 *)arg)->debug + + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32)); + if (err) return -EFAULT; break; default: - printk("mt_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); + do { + static int count = 0; + if (++count <= 20) + printk("mt_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while(0); return -EINVAL; } set_fs (KERNEL_DS); @@ -1122,35 +1113,33 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) return err; switch (cmd) { case MTIOCPOS32: - if (__put_user(pos.mt_blkno, &((struct mtpos32 *)A(arg))->mt_blkno)) + if (__put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno)) return -EFAULT; break; case MTIOCGET32: - if (__put_user(get.mt_type, &((struct mtget32 *)A(arg))->mt_type) || - __put_user(get.mt_resid, &((struct mtget32 *)A(arg))->mt_resid) || - __put_user(get.mt_dsreg, &((struct mtget32 *)A(arg))->mt_dsreg) || - __put_user(get.mt_gstat, &((struct mtget32 *)A(arg))->mt_gstat) || - __put_user(get.mt_erreg, &((struct mtget32 *)A(arg))->mt_erreg) || - __put_user(get.mt_fileno, &((struct mtget32 *)A(arg))->mt_fileno) || - __put_user(get.mt_blkno, &((struct mtget32 *)A(arg))->mt_blkno)) - return -EFAULT; + err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type); + err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid); + err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg); + err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat); + err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg); + err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno); + err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno); break; case MTIOCGETCONFIG32: - if (__put_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) || - __put_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) || - __put_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) || - __put_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) || - __put_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) || - __put_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) || - __copy_to_user((char *)&((struct mtconfiginfo32 *)A(arg))->debug - + sizeof(((struct mtconfiginfo32 *)A(arg))->debug), - (char *)&info.debug + sizeof(info.debug), sizeof(__u32))) - return -EFAULT; + err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); + err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); + err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); + err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); + err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port); + err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); + err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug + + sizeof(((struct mtconfiginfo32 *)arg)->debug), + (char *)&info.debug + sizeof(info.debug), sizeof(__u32)); break; case MTIOCSETCONFIG32: break; } - return 0; + return err; } struct cdrom_read32 { @@ -1166,7 +1155,7 @@ struct cdrom_read_audio32 { __kernel_caddr_t32 buf; }; -static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct cdrom_read cdread; @@ -1182,9 +1171,10 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) case CDROMREADRAW: case CDROMREADCOOKED: karg = &cdread; - if (__get_user(cdread.cdread_lba, &((struct cdrom_read32 *)A(arg))->cdread_lba) || - __get_user(addr, &((struct cdrom_read32 *)A(arg))->cdread_bufaddr) || - __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)A(arg))->cdread_buflen)) + err = __get_user(cdread.cdread_lba, &((struct cdrom_read32 *)arg)->cdread_lba); + err |= __get_user(addr, &((struct cdrom_read32 *)arg)->cdread_bufaddr); + err |= __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)arg)->cdread_buflen); + if (err) return -EFAULT; data = kmalloc(cdread.cdread_buflen, GFP_KERNEL); if (!data) @@ -1193,10 +1183,11 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) break; case CDROMREADAUDIO: karg = &cdreadaudio; - if (copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)A(arg))->addr, sizeof(cdreadaudio.addr)) || - __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)A(arg))->addr_format) || - __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)A(arg))->nframes) || - __get_user(addr, &((struct cdrom_read_audio32 *)A(arg))->buf)) + err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr)); + err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format); + err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes); + err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf); + if (err) return -EFAULT; data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL); if (!data) @@ -1204,38 +1195,35 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) cdreadaudio.buf = data; break; default: - printk("cdrom_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); + do { + static int count = 0; + if (++count <= 20) + printk("cdrom_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while(0); return -EINVAL; } set_fs (KERNEL_DS); err = sys_ioctl (fd, cmd, (unsigned long)karg); set_fs (old_fs); - if (err) { - if (data) kfree(data); - return err; - } + if (err) + goto out; switch (cmd) { case CDROMREADMODE2: case CDROMREADMODE1: case CDROMREADRAW: case CDROMREADCOOKED: - if (copy_to_user((char *)A(addr), data, cdread.cdread_buflen)) { - kfree(data); - return -EFAULT; - } + err = copy_to_user((char *)A(addr), data, cdread.cdread_buflen); break; case CDROMREADAUDIO: - if (copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352)) { - kfree(data); - return -EFAULT; - } + err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352); break; default: break; } - if (data) kfree(data); - return 0; +out: if (data) kfree(data); + return err; } struct loop_info32 { @@ -1253,7 +1241,7 @@ struct loop_info32 { char reserved[4]; }; -static int loop_status(unsigned int fd, unsigned int cmd, u32 arg) +static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct loop_info l; @@ -1261,12 +1249,13 @@ static int loop_status(unsigned int fd, unsigned int cmd, u32 arg) switch(cmd) { case LOOP_SET_STATUS: - if ((get_user(l.lo_number, &((struct loop_info32 *)A(arg))->lo_number) || - __get_user(l.lo_device, &((struct loop_info32 *)A(arg))->lo_device) || - __get_user(l.lo_inode, &((struct loop_info32 *)A(arg))->lo_inode) || - __get_user(l.lo_rdevice, &((struct loop_info32 *)A(arg))->lo_rdevice) || - __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)A(arg))->lo_offset, - 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset))) + err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); + err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); + err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); + err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); + err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset, + 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); + if (err) return -EFAULT; set_fs (KERNEL_DS); err = sys_ioctl (fd, cmd, (unsigned long)&l); @@ -1276,14 +1265,14 @@ static int loop_status(unsigned int fd, unsigned int cmd, u32 arg) set_fs (KERNEL_DS); err = sys_ioctl (fd, cmd, (unsigned long)&l); set_fs (old_fs); - if (!err && - (put_user(l.lo_number, &((struct loop_info32 *)A(arg))->lo_number) || - __put_user(l.lo_device, &((struct loop_info32 *)A(arg))->lo_device) || - __put_user(l.lo_inode, &((struct loop_info32 *)A(arg))->lo_inode) || - __put_user(l.lo_rdevice, &((struct loop_info32 *)A(arg))->lo_rdevice) || - __copy_to_user((char *)&((struct loop_info32 *)A(arg))->lo_offset, - (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset))) - err = -EFAULT; + if (!err) { + err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); + err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); + err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); + err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); + err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset, + (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); + } break; } return err; @@ -1422,7 +1411,7 @@ static int do_unimap_ioctl(struct file *file, int cmd, struct unimapdesc32 *user return 0; } -asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; int error = -EBADF; @@ -1433,7 +1422,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) goto out; if (!filp->f_op || !filp->f_op->ioctl) { - error = sys_ioctl (fd, cmd, (unsigned long)arg); + error = sys_ioctl (fd, cmd, arg); goto out; } switch (cmd) { @@ -1535,7 +1524,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case FDPOLLDRVSTAT32: case FDGETFDCSTAT32: case FDWERRORGET32: - error = fd_ioctl_trans(fd, cmd, (unsigned long)arg); + error = fd_ioctl_trans(fd, cmd, arg); goto out; case PPPIOCGIDLE32: @@ -1564,22 +1553,30 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) error = loop_status(fd, cmd, arg); goto out; - case AUTOFS_IOC_SETTIMEOUT: - error = rw_long(fd, cmd, arg); +#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) + case AUTOFS_IOC_SETTIMEOUT32: + error = rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); goto out; case PIO_FONTX: case GIO_FONTX: - error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)A(arg)); + error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)arg); goto out; case PIO_UNIMAP: case GIO_UNIMAP: - error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)A(arg)); + error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)arg); goto out; case KDFONTOP: - error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)A(arg)); + error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)arg); + goto out; + + case EXT2_IOC32_GETFLAGS: + case EXT2_IOC32_SETFLAGS: + case EXT2_IOC32_GETVERSION: + case EXT2_IOC32_SETVERSION: + error = do_ext2_ioctl(fd, cmd, arg); goto out; /* List here exlicitly which ioctl's are known to have @@ -1822,6 +1819,13 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case SIOCDRARP: case SIOCADDDLCI: case SIOCDELDLCI: + + /* SG stuff */ + case SG_SET_TIMEOUT: + case SG_GET_TIMEOUT: + case SG_EMULATED_HOST: + case SG_SET_TRANSFORM: + case SG_GET_TRANSFORM: /* PPP stuff */ case PPPIOCGFLAGS: @@ -1883,19 +1887,170 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case AUDIO_GETDEV_SUNOS: case AUDIO_FLUSH: + /* Big Q for sound/OSS */ + case SNDCTL_SEQ_RESET: + case SNDCTL_SEQ_SYNC: + case SNDCTL_SYNTH_INFO: + case SNDCTL_SEQ_CTRLRATE: + case SNDCTL_SEQ_GETOUTCOUNT: + case SNDCTL_SEQ_GETINCOUNT: + case SNDCTL_SEQ_PERCMODE: + case SNDCTL_FM_LOAD_INSTR: + case SNDCTL_SEQ_TESTMIDI: + case SNDCTL_SEQ_RESETSAMPLES: + case SNDCTL_SEQ_NRSYNTHS: + case SNDCTL_SEQ_NRMIDIS: + case SNDCTL_MIDI_INFO: + case SNDCTL_SEQ_THRESHOLD: + case SNDCTL_SYNTH_MEMAVL: + case SNDCTL_FM_4OP_ENABLE: + case SNDCTL_SEQ_PANIC: + case SNDCTL_SEQ_OUTOFBAND: + case SNDCTL_SEQ_GETTIME: + case SNDCTL_SYNTH_ID: + case SNDCTL_SYNTH_CONTROL: + case SNDCTL_SYNTH_REMOVESAMPLE: + + /* Big T for sound/OSS */ + case SNDCTL_TMR_TIMEBASE: + case SNDCTL_TMR_START: + case SNDCTL_TMR_STOP: + case SNDCTL_TMR_CONTINUE: + case SNDCTL_TMR_TEMPO: + case SNDCTL_TMR_SOURCE: + case SNDCTL_TMR_METRONOME: + case SNDCTL_TMR_SELECT: + + /* Little m for sound/OSS */ + case SNDCTL_MIDI_PRETIME: + case SNDCTL_MIDI_MPUMODE: + case SNDCTL_MIDI_MPUCMD: + + /* Big P for sound/OSS */ + case SNDCTL_DSP_RESET: + case SNDCTL_DSP_SYNC: + case SNDCTL_DSP_SPEED: + case SNDCTL_DSP_STEREO: + case SNDCTL_DSP_GETBLKSIZE: + case SNDCTL_DSP_CHANNELS: + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_POST: + case SNDCTL_DSP_SUBDIVIDE: + case SNDCTL_DSP_SETFRAGMENT: + case SNDCTL_DSP_GETFMTS: + case SNDCTL_DSP_SETFMT: + case SNDCTL_DSP_GETOSPACE: + case SNDCTL_DSP_GETISPACE: + case SNDCTL_DSP_NONBLOCK: + case SNDCTL_DSP_GETCAPS: + case SNDCTL_DSP_GETTRIGGER: + case SNDCTL_DSP_SETTRIGGER: + case SNDCTL_DSP_GETIPTR: + case SNDCTL_DSP_GETOPTR: + /* case SNDCTL_DSP_MAPINBUF: XXX needs translation */ + /* case SNDCTL_DSP_MAPOUTBUF: XXX needs translation */ + case SNDCTL_DSP_SETSYNCRO: + case SNDCTL_DSP_SETDUPLEX: + case SNDCTL_DSP_GETODELAY: + case SNDCTL_DSP_PROFILE: + + case SOUND_PCM_READ_RATE: + case SOUND_PCM_READ_CHANNELS: + case SOUND_PCM_READ_BITS: + case SOUND_PCM_READ_FILTER: + + /* Big C for sound/OSS */ + case SNDCTL_COPR_RESET: + case SNDCTL_COPR_LOAD: + case SNDCTL_COPR_RDATA: + case SNDCTL_COPR_RCODE: + case SNDCTL_COPR_WDATA: + case SNDCTL_COPR_WCODE: + case SNDCTL_COPR_RUN: + case SNDCTL_COPR_HALT: + case SNDCTL_COPR_SENDMSG: + case SNDCTL_COPR_RCVMSG: + + /* Big M for sound/OSS */ + case SOUND_MIXER_READ_VOLUME: + case SOUND_MIXER_READ_BASS: + case SOUND_MIXER_READ_TREBLE: + case SOUND_MIXER_READ_SYNTH: + case SOUND_MIXER_READ_PCM: + case SOUND_MIXER_READ_SPEAKER: + case SOUND_MIXER_READ_LINE: + case SOUND_MIXER_READ_MIC: + case SOUND_MIXER_READ_CD: + case SOUND_MIXER_READ_IMIX: + case SOUND_MIXER_READ_ALTPCM: + case SOUND_MIXER_READ_RECLEV: + case SOUND_MIXER_READ_IGAIN: + case SOUND_MIXER_READ_OGAIN: + case SOUND_MIXER_READ_LINE1: + case SOUND_MIXER_READ_LINE2: + case SOUND_MIXER_READ_LINE3: + case SOUND_MIXER_READ_MUTE: + /* case SOUND_MIXER_READ_ENHANCE: same value as READ_MUTE */ + /* case SOUND_MIXER_READ_LOUD: same value as READ_MUTE */ + case SOUND_MIXER_READ_RECSRC: + case SOUND_MIXER_READ_DEVMASK: + case SOUND_MIXER_READ_RECMASK: + case SOUND_MIXER_READ_STEREODEVS: + case SOUND_MIXER_READ_CAPS: + + case SOUND_MIXER_WRITE_VOLUME: + case SOUND_MIXER_WRITE_BASS: + case SOUND_MIXER_WRITE_TREBLE: + case SOUND_MIXER_WRITE_SYNTH: + case SOUND_MIXER_WRITE_PCM: + case SOUND_MIXER_WRITE_SPEAKER: + case SOUND_MIXER_WRITE_LINE: + case SOUND_MIXER_WRITE_MIC: + case SOUND_MIXER_WRITE_CD: + case SOUND_MIXER_WRITE_IMIX: + case SOUND_MIXER_WRITE_ALTPCM: + case SOUND_MIXER_WRITE_RECLEV: + case SOUND_MIXER_WRITE_IGAIN: + case SOUND_MIXER_WRITE_OGAIN: + case SOUND_MIXER_WRITE_LINE1: + case SOUND_MIXER_WRITE_LINE2: + case SOUND_MIXER_WRITE_LINE3: + case SOUND_MIXER_WRITE_MUTE: + /* case SOUND_MIXER_WRITE_ENHANCE: same value as WRITE_MUTE */ + /* case SOUND_MIXER_WRITE_LOUD: same value as WRITE_MUTE */ + case SOUND_MIXER_WRITE_RECSRC: + + case SOUND_MIXER_INFO: + case SOUND_OLD_MIXER_INFO: + case SOUND_MIXER_ACCESS: + case SOUND_MIXER_PRIVATE1: + case SOUND_MIXER_PRIVATE2: + case SOUND_MIXER_PRIVATE3: + case SOUND_MIXER_PRIVATE4: + case SOUND_MIXER_PRIVATE5: + case SOUND_MIXER_GETLEVELS: + case SOUND_MIXER_SETLEVELS: + + case OSS_GETVERSION: + /* AUTOFS */ case AUTOFS_IOC_READY: case AUTOFS_IOC_FAIL: case AUTOFS_IOC_CATATONIC: case AUTOFS_IOC_PROTOVER: case AUTOFS_IOC_EXPIRE: - - error = sys_ioctl (fd, cmd, (unsigned long)arg); + + error = sys_ioctl (fd, cmd, arg); goto out; default: - printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); + do { + static int count = 0; + if (++count <= 20) + printk("sys32_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while(0); error = -EINVAL; break; } diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index eaa7ad7d4..d8707261f 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.61 1998/08/02 14:51:38 ecd Exp $ +/* $Id: irq.c,v 1.66 1998/10/21 15:02:25 ecd Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -15,6 +15,7 @@ #include <linux/malloc.h> #include <linux/random.h> /* XXX ADD add_foo_randomness() calls... -DaveM */ #include <linux/init.h> +#include <linux/delay.h> #include <asm/ptrace.h> #include <asm/processor.h> @@ -208,7 +209,7 @@ unsigned char psycho_ino_to_pil[] = { 13, /* Audio Record */ 14, /* Audio Playback */ 15, /* PowerFail */ - 9, /* Keyboard/Mouse/Serial */ + 3, /* second SCSI */ 11, /* Floppy */ 2, /* Spare Hardware */ 9, /* Keyboard */ @@ -573,22 +574,18 @@ out: restore_flags(flags); } -/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu - * structure for cache reasons. +/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it + * lives in the per-cpu structure for cache reasons. */ #ifndef __SMP__ unsigned int local_irq_count; -#endif - -#ifndef __SMP__ -int __sparc64_bh_counter = 0; +unsigned int local_bh_count; #define irq_enter(cpu, irq) (local_irq_count++) #define irq_exit(cpu, irq) (local_irq_count--) - #else - -atomic_t __sparc64_bh_counter = ATOMIC_INIT(0); +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; @@ -596,136 +593,163 @@ unsigned char global_irq_holder = NO_PROC_ID; /* This protects IRQ's. */ spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; -/* This protects BH software state (masks, things like that). */ -spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; - /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); -static unsigned long previous_irqholder; +#define irq_enter(cpu, irq) \ +do { hardirq_enter(cpu); \ + spin_unlock_wait(&global_irq_lock); \ +} while(0) +#define irq_exit(cpu, irq) hardirq_exit(cpu) -#undef INIT_STUCK -#define INIT_STUCK 100000000 +static void show(char * str) +{ + int cpu = smp_processor_id(); -#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; } + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [%d %d]\n", + atomic_read(&global_irq_count), + cpu_data[0].irq_count, cpu_data[1].irq_count); + printk("bh: %d [%d %d]\n", + (spin_is_locked(&global_bh_count) ? 1 : 0), + cpu_data[0].bh_count, cpu_data[1].bh_count); +} + +#define MAXCOUNT 100000000 -static inline void wait_on_irq(int cpu, unsigned long where) +static inline void wait_on_bh(void) { - int stuck = INIT_STUCK; - int local_count = local_irq_count; + int count = MAXCOUNT; + do { + if(!--count) { + show("wait_on_bh"); + count = 0; + } + membar("#LoadLoad"); + } while(spin_is_locked(&global_bh_count)); +} + +#define SYNC_OTHER_ULTRAS(x) udelay(x+1) - while(local_count != atomic_read(&global_irq_count)) { - atomic_sub(local_count, &global_irq_count); - spin_unlock(&global_irq_lock); +static inline void wait_on_irq(int cpu) +{ + int count = MAXCOUNT; + for(;;) { + membar("#LoadLoad"); + if (!atomic_read (&global_irq_count)) { + if (local_bh_count || ! spin_is_locked(&global_bh_count)) + break; + } + spin_unlock (&global_irq_lock); + membar("#StoreLoad | #StoreStore"); for(;;) { - STUCK; - membar("#StoreLoad | #LoadLoad"); + if (!--count) { + show("wait_on_irq"); + count = ~0; + } + __sti(); + SYNC_OTHER_ULTRAS(cpu); + __cli(); if (atomic_read(&global_irq_count)) continue; - if (*((volatile unsigned char *)&global_irq_lock)) + if (spin_is_locked (&global_irq_lock)) + continue; + if (!local_bh_count && spin_is_locked (&global_bh_count)) continue; - membar("#LoadLoad | #LoadStore"); if (spin_trylock(&global_irq_lock)) break; } - atomic_add(local_count, &global_irq_count); } } -#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;} +void synchronize_bh(void) +{ + if (spin_is_locked (&global_bh_count) && !in_interrupt()) + wait_on_bh(); +} -static inline void get_irqlock(int cpu, unsigned long where) +void synchronize_irq(void) { - int stuck = INIT_STUCK; + if (atomic_read(&global_irq_count)) { + cli(); + sti(); + } +} - if (!spin_trylock(&global_irq_lock)) { - membar("#StoreLoad | #LoadLoad"); +static inline void get_irqlock(int cpu) +{ + if (! spin_trylock(&global_irq_lock)) { if ((unsigned char) cpu == global_irq_holder) return; do { - do { - STUCK; + while (spin_is_locked (&global_irq_lock)) membar("#LoadLoad"); - } while(*((volatile unsigned char *)&global_irq_lock)); - } while (!spin_trylock(&global_irq_lock)); + } while(! spin_trylock(&global_irq_lock)); } - wait_on_irq(cpu, where); + wait_on_irq(cpu); global_irq_holder = cpu; - previous_irqholder = where; } void __global_cli(void) { - int cpu = smp_processor_id(); - unsigned long where; + unsigned long flags; - __asm__ __volatile__("mov %%i7, %0" : "=r" (where)); - __cli(); - get_irqlock(cpu, where); + __save_flags(flags); + if(flags == 0) { + int cpu = smp_processor_id(); + __cli(); + if (! local_irq_count) + get_irqlock(cpu); + } } void __global_sti(void) { - release_irqlock(smp_processor_id()); + int cpu = smp_processor_id(); + + if (! local_irq_count) + release_irqlock(cpu); __sti(); } -void __global_restore_flags(unsigned long flags) +unsigned long __global_save_flags(void) { - if (flags & 1) { - __global_cli(); - } else { - if (global_irq_holder == (unsigned char) smp_processor_id()) { - global_irq_holder = NO_PROC_ID; - spin_unlock(&global_irq_lock); - } - if (!(flags & 2)) - __sti(); + unsigned long flags, local_enabled, retval; + + __save_flags(flags); + local_enabled = ((flags == 0) ? 1 : 0); + retval = 2 + local_enabled; + if (! local_irq_count) { + if (local_enabled) + retval = 1; + if (global_irq_holder == (unsigned char) smp_processor_id()) + retval = 0; } + return retval; } -#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;} - -void irq_enter(int cpu, int irq) +void __global_restore_flags(unsigned long flags) { - int stuck = INIT_STUCK; - - hardirq_enter(cpu); - while (*((volatile unsigned char *)&global_irq_lock)) { - if ((unsigned char) cpu == global_irq_holder) - printk("irq_enter: Frosted Lucky Charms, " - "they're magically delicious!\n"); - STUCK; - membar("#LoadLoad"); + switch (flags) { + case 0: + __global_cli(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + { + unsigned long pc; + __asm__ __volatile__("mov %%i7, %0" : "=r" (pc)); + printk("global_restore_flags: Bogon flags(%016lx) caller %016lx\n", + flags, pc); } -} - -void irq_exit(int cpu, int irq) -{ - hardirq_exit(cpu); - release_irqlock(cpu); -} - -void synchronize_irq(void) -{ - int local_count = local_irq_count; - unsigned long flags; - - if (local_count != atomic_read(&global_irq_count)) { - save_and_cli(flags); - restore_flags(flags); } } @@ -787,7 +811,7 @@ void handler_irq(int irq, struct pt_regs *regs) /* * Check for TICK_INT on level 14 softint. */ - if ((irq == 14) && get_softint() & (1UL << 0)) + if ((irq == 14) && (get_softint() & (1UL << 0))) irq = 0; #endif clear_softint(1 << irq); @@ -1004,12 +1028,15 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *), /* Called from smp_commence, when we know how many cpus are in the system * and can have device IRQ's directed at them. */ +/* #define SMP_IRQ_VERBOSE */ void distribute_irqs(void) { unsigned long flags; int cpu, level; +#ifdef SMP_IRQ_VERBOSE printk("SMP: redistributing interrupts...\n"); +#endif save_and_cli(flags); cpu = 0; for(level = 0; level < NR_IRQS; level++) { @@ -1020,16 +1047,18 @@ void distribute_irqs(void) struct ino_bucket *bucket = (struct ino_bucket *)p->mask; unsigned int *imap = __imap(bucket); unsigned int val; - unsigned long tid = __cpu_logical_map[cpu] << 9; + unsigned long tid = __cpu_logical_map[cpu] << 26; val = *imap; *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); +#ifdef SMP_IRQ_VERBOSE printk("SMP: Redirecting IGN[%x] INO[%x] " "to cpu %d [%s]\n", (val & SYSIO_IMAP_IGN) >> 6, (val & SYSIO_IMAP_INO), cpu, p->name); +#endif cpu++; if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1) @@ -1114,12 +1143,17 @@ void enable_prom_timer(void) __initfunc(void init_IRQ(void)) { - int i; + static int called = 0; + + if (called == 0) { + int i; - map_prom_timers(); - kill_prom_timer(); - for(i = 0; i < NUM_IVECS; i++) - ivector_to_mask[i] = 0; + called = 1; + map_prom_timers(); + kill_prom_timer(); + for(i = 0; i < NUM_IVECS; i++) + ivector_to_mask[i] = 0; + } /* We need to clear any IRQ's pending in the soft interrupt * registers, a spurious one could be left around from the diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 373d122c3..c5c7061f7 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.70 1998/08/04 20:49:15 davem Exp $ +/* $Id: process.c,v 1.82 1998/10/19 21:52:23 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -71,13 +71,16 @@ asmlinkage int cpu_idle(void) { current->priority = 0; while(1) { + struct task_struct *p; + check_pgt_cache(); run_task_queue(&tq_scheduler); - barrier(); current->counter = 0; - if(current->need_resched) + if (current->need_resched != 0 || + ((p = init_task.next_run) != NULL && + (p->processor == smp_processor_id() || + (p->tss.flags & SPARC_FLAG_NEWCHILD) != 0))) schedule(); - barrier(); } } @@ -386,12 +389,32 @@ void exit_thread(void) else current->tss.utraps[0]--; } + + /* Turn off performance counters if on. */ + if (current->tss.flags & SPARC_FLAG_PERFCTR) { + current->tss.user_cntd0 = + current->tss.user_cntd1 = NULL; + current->tss.pcr_reg = 0; + current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + write_pcr(0); + } } void flush_thread(void) { + if (!(current->tss.flags & SPARC_FLAG_KTHREAD)) + flush_user_windows(); current->tss.w_saved = 0; + /* Turn off performance counters if on. */ + if (current->tss.flags & SPARC_FLAG_PERFCTR) { + current->tss.user_cntd0 = + current->tss.user_cntd1 = NULL; + current->tss.pcr_reg = 0; + current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + write_pcr(0); + } + /* No new signal delivery by default. */ current->tss.new_signal = 0; current->tss.fpsaved[0] = 0; @@ -399,22 +422,24 @@ void flush_thread(void) /* Now, this task is no longer a kernel thread. */ current->tss.current_ds = USER_DS; if(current->tss.flags & SPARC_FLAG_KTHREAD) { - extern spinlock_t scheduler_lock; - current->tss.flags &= ~SPARC_FLAG_KTHREAD; /* exec_mmap() set context to NO_CONTEXT, here is * where we grab a new one. */ - spin_lock(&scheduler_lock); - get_mmu_context(current); - spin_unlock(&scheduler_lock); + current->mm->cpu_vm_mask = 0; + activate_context(current); + current->mm->cpu_vm_mask = (1UL<<smp_processor_id()); } if (current->tss.flags & SPARC_FLAG_32BIT) - __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r"(TSB_REG), "i"(ASI_DMMU)); + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* no outputs */ + : "r"(TSB_REG), "i"(ASI_DMMU)); + __cli(); current->tss.ctx = current->mm->context & 0x3ff; spitfire_set_secondary_context (current->tss.ctx); __asm__ __volatile__("flush %g6"); + __sti(); } /* It's a bit more tricky when 64-bit tasks are involved... */ @@ -518,7 +543,6 @@ void fault_in_user_windows(struct pt_regs *regs) current->tss.w_saved = 0; return; barf: - lock_kernel(); do_exit(SIGILL); } @@ -546,7 +570,19 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP; p->tss.fpsaved[0] = 0; + p->mm->segments = (void *) 0; if(regs->tstate & TSTATE_PRIV) { + /* Special case, if we are spawning a kernel thread from + * a userspace task (via KMOD, NFS, or similar) we must + * disable performance counters in the child because the + * address space and protection realm are changing. + */ + if (current->tss.flags & SPARC_FLAG_PERFCTR) { + p->tss.user_cntd0 = + p->tss.user_cntd1 = NULL; + p->tss.pcr_reg = 0; + p->tss.flags &= ~(SPARC_FLAG_PERFCTR); + } p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp; p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD); p->tss.current_ds = KERNEL_DS; @@ -592,7 +628,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, */ void dump_thread(struct pt_regs * regs, struct user * dump) { -#if 0 +#if 1 + /* Only should be used for SunOS and ancient a.out + * SparcLinux binaries... Fixme some day when bored. + * But for now at least plug the security hole :-) + */ + memset(dump, 0, sizeof(struct user)); +#else unsigned long first_stack_page; dump->magic = SUNOS_CORE_MAGIC; dump->len = sizeof(struct user); @@ -616,13 +658,69 @@ void dump_thread(struct pt_regs * regs, struct user * dump) #endif } +typedef struct { + union { + unsigned int pr_regs[32]; + unsigned long pr_dregs[16]; + } pr_fr; + unsigned int __unused; + unsigned int pr_fsr; + unsigned char pr_qcnt; + unsigned char pr_q_entrysize; + unsigned char pr_en; + unsigned int pr_q[64]; +} elf_fpregset_t32; + /* * fill in the fpu structure for a core dump. */ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) { - /* Currently we report that we couldn't dump the fpu structure */ - return 0; + unsigned long *kfpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); + unsigned long fprs = current->tss.fpsaved[0]; + + if ((current->tss.flags & SPARC_FLAG_32BIT) != 0) { + elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs; + + if (fprs & FPRS_DL) + memcpy(&fpregs32->pr_fr.pr_regs[0], kfpregs, + sizeof(unsigned int) * 32); + else + memset(&fpregs32->pr_fr.pr_regs[0], 0, + sizeof(unsigned int) * 32); + fpregs32->pr_qcnt = 0; + fpregs32->pr_q_entrysize = 8; + memset(&fpregs32->pr_q[0], 0, + (sizeof(unsigned int) * 64)); + if (fprs & FPRS_FEF) { + fpregs32->pr_fsr = (unsigned int) current->tss.xfsr[0]; + fpregs32->pr_en = 1; + } else { + fpregs32->pr_fsr = 0; + fpregs32->pr_en = 0; + } + } else { + if(fprs & FPRS_DL) + memcpy(&fpregs->pr_regs[0], kfpregs, + sizeof(unsigned int) * 32); + else + memset(&fpregs->pr_regs[0], 0, + sizeof(unsigned int) * 32); + if(fprs & FPRS_DU) + memcpy(&fpregs->pr_regs[16], kfpregs+16, + sizeof(unsigned int) * 32); + else + memset(&fpregs->pr_regs[16], 0, + sizeof(unsigned int) * 32); + if(fprs & FPRS_FEF) { + fpregs->pr_fsr = current->tss.xfsr[0]; + fpregs->pr_gsr = current->tss.gsr[0]; + } else { + fpregs->pr_fsr = fpregs->pr_gsr = 0; + } + fpregs->pr_fprs = fprs; + } + return 1; } /* diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c index 32d9b13c1..96b1ac2e9 100644 --- a/arch/sparc64/kernel/psycho.c +++ b/arch/sparc64/kernel/psycho.c @@ -1,4 +1,4 @@ -/* $Id: psycho.c,v 1.63 1998/08/02 05:55:42 ecd Exp $ +/* $Id: psycho.c,v 1.66 1998/11/02 22:27:45 davem Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) @@ -75,7 +75,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, #include <asm/uaccess.h> struct linux_psycho *psycho_root = NULL; -struct linux_psycho **psycho_index_map; int linux_num_psycho = 0; static struct linux_pbm_info *bus2pbm[256]; @@ -534,18 +533,6 @@ __initfunc(void pcibios_init(void)) if(!node) break; } - - /* Last minute sanity check. */ - if(psycho_root == NULL && SBus_chain == NULL) { - prom_printf("Fatal error, neither SBUS nor PCI bus found.\n"); - prom_halt(); - } - - psycho_index_map = kmalloc(sizeof(struct linux_psycho *) * linux_num_psycho, - GFP_ATOMIC); - - for (psycho = psycho_root; psycho; psycho = psycho->next) - psycho_index_map[psycho->index] = psycho; } int pcibios_present(void) @@ -1419,9 +1406,9 @@ __initfunc(static void fixup_regs(struct pci_dev *pdev, dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device); for(preg = 0; preg < 6; preg++) { if(pdev->base_address[preg] != 0) - prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]); + dprintf("%d[%016lx] ", preg, pdev->base_address[preg]); } - prom_printf("\n"); + dprintf("\n"); #endif } @@ -1652,17 +1639,8 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev, return; } - /* See if we find a matching interrupt-map entry. */ - if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) { - pdev->irq = psycho_irq_build(pbm, pdev, - (pbm->parent->upa_portid << 6) - | prom_irq); -#ifdef FIXUP_IRQ_DEBUG - dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]", - prom_irq, pdev->irq); -#endif /* See if fully specified already (ie. for onboard devices like hme) */ - } else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) { + if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) { pdev->irq = psycho_irq_build(pbm, pdev, prom_irq); #ifdef FIXUP_IRQ_DEBUG dprintf("fully specified prom_irq[%x] pdev->irq[%x]", @@ -1677,6 +1655,15 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev, dprintf("partially specified prom_irq[%x] pdev->irq[%x]", prom_irq, pdev->irq); #endif + /* See if we find a matching interrupt-map entry. */ + } else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) { + pdev->irq = psycho_irq_build(pbm, pdev, + (pbm->parent->upa_portid << 6) + | prom_irq); +#ifdef FIXUP_IRQ_DEBUG + dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]", + prom_irq, pdev->irq); +#endif } else { unsigned int bus, slot, line; @@ -1943,8 +1930,8 @@ static inline int out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn) { return ((pbm->parent == 0) || - ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 4) || - ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 6) || + ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) || + ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) || (pci_probe_enable == 0)); } diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 07ee212a3..4063a1e86 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -43,6 +43,12 @@ static pte_t *get_page(struct task_struct * tsk, repeat: pgdir = pgd_offset(vma->vm_mm, addr); + + /* Seems non-intuitive but the page copy/clear routines always + * check current's value. + */ + current->mm->segments = (void *) (addr & PAGE_SIZE); + if (pgd_none(*pgdir)) { handle_mm_fault(tsk, vma, addr, write); goto repeat; @@ -574,7 +580,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } #endif - if(!(child = find_task_by_pid(pid))) { + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + read_unlock(&tasklist_lock); + + if(!child) { pt_error_return(regs, ESRCH); goto out; } @@ -604,9 +614,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } child->flags |= PF_PTRACED; 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); } send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); @@ -781,11 +795,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) cregs->tnpc = npc; } cregs->y = y; - for(i = 1; i < 16; i++) + for(i = 1; i < 16; i++) { if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { pt_error_return(regs, EFAULT); goto out; } + } pt_succ_return(regs, 0); goto out; } @@ -814,11 +829,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) cregs->tnpc = tnpc; } cregs->y = y; - for(i = 1; i < 16; i++) + for(i = 1; i < 16; i++) { if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { pt_error_return(regs, EFAULT); goto out; } + } pt_succ_return(regs, 0); goto out; } @@ -1055,23 +1071,29 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_succ_return(regs, 0); goto out; } - wake_up_process(child); child->exit_code = SIGKILL; + wake_up_process(child); pt_succ_return(regs, 0); goto out; } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ + unsigned long flags; + if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); goto out; } child->flags &= ~(PF_PTRACED|PF_TRACESYS); - wake_up_process(child); child->exit_code = data; + + write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); + + wake_up_process(child); pt_succ_return(regs, 0); goto out; } diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 85732960f..a3137ee50 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.39 1998/07/26 03:02:49 davem Exp $ +/* $Id: rtrap.S,v 1.45 1998/11/09 15:33:29 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -46,13 +46,15 @@ rtrap: sethi %hi(bh_active), %l2 ldub [%l6 + %o0], %l2 sub %l5, 2, %l5 add %g6, AOFF_task_tss + AOFF_thread_gsr, %o1 - andcc %l2, FPRS_FEF, %g0 + andcc %l2, (FPRS_FEF|FPRS_DU), %g0 be,pt %icc, 2f and %l2, FPRS_DL, %l6 + andcc %l2, FPRS_FEF, %g0 + be,pn %icc, 5f + sll %o0, 3, %o5 rd %fprs, %g5 wr %g5, FPRS_FEF, %fprs ldub [%o1 + %o0], %g5 - sll %o0, 3, %o5 add %g6, AOFF_task_tss + AOFF_thread_xfsr, %o1 membar #StoreLoad | #LoadLoad sll %o0, 8, %o2 @@ -130,21 +132,56 @@ to_user: ldx [%g6 + AOFF_task_need_resched], %l0 nop lduw [%g6 + AOFF_task_sigpending], %l0 check_signal: brz,a,pt %l0, check_user_wins - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + nop clr %o0 mov %l5, %o2 mov %l6, %o3 call do_signal add %sp, STACK_BIAS + REGWIN_SZ, %o1 - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 clr %l6 -check_user_wins:brz,pt %o2, 1f + + /* We must not take any traps between here and the actual + * return to user-space. If we do we risk having windows + * saved to the thread struct between the test and the + * actual return from trap. --DaveM + */ +check_user_wins: + wrpr %l7, 0x0, %pstate + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + brz,pt %o2, 1f sethi %hi(TSTATE_PEF), %l6 + wrpr %l7, PSTATE_IE, %pstate call fault_in_user_windows add %sp, STACK_BIAS + REGWIN_SZ, %o0 + /* It is OK to leave interrupts on now because if + * fault_in_user_windows has returned it has left us + * with a clean user stack state. + */ +1: +#if 0 + call rtrap_check + add %sp, STACK_BIAS + REGWIN_SZ, %o0 +#endif + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l5 + andcc %l5, 0x200, %g0 + be,pt %xcc, 1f + nop -1: andcc %l1, %l6, %g0 + /* Don't forget to preserve user window invariants. */ + wrpr %l7, PSTATE_IE, %pstate + call update_perfctrs + nop + wrpr %l7, 0x0, %pstate + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + brz,pt %o2, 1f + sethi %hi(TSTATE_PEF), %l6 + wrpr %l7, PSTATE_IE, %pstate + call fault_in_user_windows + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + +1: + andcc %l1, %l6, %g0 be,pt %xcc, rt_continue stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only @@ -155,4 +192,16 @@ check_user_wins:brz,pt %o2, 1f ba,pt %xcc, rt_continue+4 lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 +5: wr %g0, FPRS_FEF, %fprs + membar #StoreLoad | #LoadLoad + sll %o0, 8, %o2 + add %g6, AOFF_task_fpregs+0x80, %o3 + add %g6, AOFF_task_fpregs+0xc0, %o4 + ldda [%o3 + %o2] ASI_BLK_P, %f32 + ldda [%o4 + %o2] ASI_BLK_P, %f48 +1: membar #Sync + wr %g0, FPRS_DU, %fprs + ba,pt %xcc, rt_continue + stb %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] + #undef PTREGS_OFF diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index de0124f52..570322eec 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.30 1998/07/24 09:50:08 jj Exp $ +/* $Id: setup.c,v 1.37 1998/10/14 15:49:09 ecd Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -56,46 +56,213 @@ struct screen_info screen_info = { 16 /* orig-video-points */ }; -unsigned int phys_bytes_of_ram, end_of_phys_memory; - /* Typing sync at the prom prompt calls the function pointed to by * the sync callback which I set to the following function. * This should sync all filesystems and return, for now it just * prints out pretty messages and returns. */ -extern unsigned long sparc64_ttable_tl0; #if CONFIG_SUN_CONSOLE void (*prom_palette)(int); #endif asmlinkage void sys_sync(void); /* it's really int */ +static void +prom_console_write(struct console *con, const char *s, unsigned n) +{ + prom_printf("%s", s); +} + +static struct console prom_console = { + "prom", + prom_console_write, + NULL, + NULL, + NULL, + NULL, + NULL, + CON_CONSDEV | CON_ENABLED, + -1, + 0, + NULL +}; + +#define PROM_TRUE -1 +#define PROM_FALSE 0 + /* Pretty sick eh? */ -void prom_sync_me(long *args) +int prom_callback(long *args) { - unsigned long prom_tba, flags; + struct console *cons, *saved_console = NULL; + unsigned long flags; + char *cmd; - save_and_cli(flags); - __asm__ __volatile__("flushw; rdpr %%tba, %0\n\t" : "=r" (prom_tba)); - __asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0)); + if (!args) + return -1; + if (!(cmd = (char *)args[0])) + return -1; -#ifdef CONFIG_SUN_CONSOLE - if (prom_palette) - prom_palette (1); -#endif - prom_printf("PROM SYNC COMMAND...\n"); - show_free_areas(); - if(current->pid != 0) { - sti(); - sys_sync(); - cli(); + save_and_cli(flags); + cons = console_drivers; + while (cons) { + unregister_console(cons); + cons->flags &= ~(CON_PRINTBUFFER); + cons->next = saved_console; + saved_console = cons; + cons = console_drivers; } - prom_printf("Returning to prom\n"); + register_console(&prom_console); + if (!strcmp(cmd, "sync")) { + prom_printf("PROM `%s' command...\n", cmd); + show_free_areas(); + if(current->pid != 0) { + sti(); + sys_sync(); + cli(); + } + args[2] = 0; + args[args[1] + 3] = -1; + prom_printf("Returning to PROM\n"); + } else if (!strcmp(cmd, "va>tte-data")) { + unsigned long ctx, va; + unsigned long tte = 0; + long res = PROM_FALSE; + + ctx = args[3]; + va = args[4]; + if (ctx) { + /* + * Find process owning ctx, lookup mapping. + */ + struct task_struct *p; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + for_each_task(p) + if (p->tss.ctx == ctx) + break; + if (p->tss.ctx != ctx) + goto done; + + pgdp = pgd_offset(p->mm, va); + if (pgd_none(*pgdp)) + goto done; + pmdp = pmd_offset(pgdp, va); + if (pmd_none(*pmdp)) + goto done; + ptep = pte_offset(pmdp, va); + if (!pte_present(*ptep)) + goto done; + tte = pte_val(*ptep); + res = PROM_TRUE; + goto done; + } - __asm__ __volatile__("flushw; wrpr %0, 0x0, %%tba\n\t" : : "r" (prom_tba)); - restore_flags(flags); + if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) { + /* + * Locked down tlb entry 63. + */ + tte = spitfire_get_dtlb_data(63); + res = PROM_TRUE; + goto done; + } + + if (va < PGDIR_SIZE) { + /* + * vmalloc or prom_inherited mapping. + */ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + pgdp = pgd_offset_k(va); + if (pgd_none(*pgdp)) + goto done; + pmdp = pmd_offset(pgdp, va); + if (pmd_none(*pmdp)) + goto done; + ptep = pte_offset(pmdp, va); + if (!pte_present(*ptep)) + goto done; + tte = pte_val(*ptep); + res = PROM_TRUE; + goto done; + } + + if (va < PAGE_OFFSET) { + /* + * No mappings here. + */ + goto done; + } + + if (va & (1UL << 40)) { + /* + * I/O page. + */ - return; + tte = (__pa(va) & _PAGE_PADDR) | + _PAGE_VALID | _PAGE_SZ4MB | + _PAGE_E | _PAGE_P | _PAGE_W; + res = PROM_TRUE; + goto done; + } + + /* + * Normal page. + */ + tte = (__pa(va) & _PAGE_PADDR) | + _PAGE_VALID | _PAGE_SZ4MB | + _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W; + res = PROM_TRUE; + + done: + if (res == PROM_TRUE) { + args[2] = 3; + args[args[1] + 3] = 0; + args[args[1] + 4] = res; + args[args[1] + 5] = tte; + } else { + args[2] = 2; + args[args[1] + 3] = 0; + args[args[1] + 4] = res; + } + } else if (!strcmp(cmd, ".soft1")) { + unsigned long tte; + + tte = args[3]; + prom_printf("%lx:\"%s%s%s%s%s\" ", + (tte & _PAGE_SOFT) >> 7, + tte & _PAGE_MODIFIED ? "M" : "-", + tte & _PAGE_ACCESSED ? "A" : "-", + tte & _PAGE_READ ? "W" : "-", + tte & _PAGE_WRITE ? "R" : "-", + tte & _PAGE_PRESENT ? "P" : "-"); + + args[2] = 2; + args[args[1] + 3] = 0; + args[args[1] + 4] = PROM_TRUE; + } else if (!strcmp(cmd, ".soft2")) { + unsigned long tte; + + tte = args[3]; + prom_printf("%lx ", (tte & _PAGE_SOFT2) >> 50); + + args[2] = 2; + args[args[1] + 3] = 0; + args[args[1] + 4] = PROM_TRUE; + } else { + prom_printf("unknown PROM `%s' command...\n", cmd); + } + unregister_console(&prom_console); + while (saved_console) { + cons = saved_console; + saved_console = cons->next; + register_console(cons); + } + restore_flags(flags); + return 0; } extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */ @@ -235,8 +402,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 int ramdisk_image; +extern unsigned int ramdisk_size; #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 @@ -252,39 +419,13 @@ static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; extern struct consw sun_serial_con; -#ifdef PROM_DEBUG_CONSOLE -static void -prom_console_write(struct console *con, const char *s, unsigned n) -{ - prom_printf("%s", s); -} - -static struct console prom_console = { - "prom", - prom_console_write, - NULL, - NULL, - NULL, - NULL, - NULL, - CON_PRINTBUFFER, - -1, - 0, - NULL -}; -#endif - __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { extern int serial_console; /* in console.c, of course */ - unsigned long lowest_paddr; + unsigned long lowest_paddr, end_of_phys_memory = 0; int total, i; -#ifdef PROM_DEBUG_CONSOLE - register_console(&prom_console); -#endif - /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); strcpy(saved_command_line, *cmdline_p); @@ -318,7 +459,13 @@ __initfunc(void setup_arch(char **cmdline_p, } } } - prom_setsync(prom_sync_me); + prom_setcallback(prom_callback); + prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; " + "' linux-va>tte-data to va>tte-data"); + prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; " + "' linux-.soft1 to .soft1"); + prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; " + "' linux-.soft2 to .soft2"); /* In paging_init() we tip off this value to see if we need * to change init_mm.pgd to point to the real alias mapping. diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 004e0e81e..91dc7224d 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.30 1998/07/30 11:29:34 davem Exp $ +/* $Id: signal.c,v 1.38 1998/10/16 03:19:04 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -39,6 +39,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 */ /* {set, get}context() needed for 64-bit SparcLinux userland. */ asmlinkage void sparc64_set_context(struct pt_regs *regs) @@ -49,16 +51,17 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) unsigned long pc, npc, tstate; unsigned long fp, i7; unsigned char fenab; + int err; - __asm__ __volatile__("flushw"); + flush_user_windows(); if(tp->w_saved || (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || (!__access_ok((unsigned long)ucp, sizeof(*ucp)))) goto do_sigsegv; - grp = &ucp->uc_mcontext.mc_gregs; - __get_user(pc, &((*grp)[MC_PC])); - __get_user(npc, &((*grp)[MC_NPC])); - if((pc | npc) & 3) + grp = &ucp->uc_mcontext.mc_gregs; + err = __get_user(pc, &((*grp)[MC_PC])); + err |= __get_user(npc, &((*grp)[MC_NPC])); + if(err || ((pc | npc) & 3)) goto do_sigsegv; if(regs->u_regs[UREG_I1]) { sigset_t set; @@ -78,48 +81,57 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) } regs->tpc = pc; regs->tnpc = npc; - __get_user(regs->y, &((*grp)[MC_Y])); - __get_user(tstate, &((*grp)[MC_TSTATE])); + err |= __get_user(regs->y, &((*grp)[MC_Y])); + err |= __get_user(tstate, &((*grp)[MC_TSTATE])); regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC)); - __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1])); - __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2])); - __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3])); - __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4])); - __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5])); - __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6])); - __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7])); - __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0])); - __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1])); - __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2])); - __get_user(regs->u_regs[UREG_I3], (&(*grp)[MC_O3])); - __get_user(regs->u_regs[UREG_I4], (&(*grp)[MC_O4])); - __get_user(regs->u_regs[UREG_I5], (&(*grp)[MC_O5])); - __get_user(regs->u_regs[UREG_I6], (&(*grp)[MC_O6])); - __get_user(regs->u_regs[UREG_I7], (&(*grp)[MC_O7])); - - __get_user(fp, &(ucp->uc_mcontext.mc_fp)); - __get_user(i7, &(ucp->uc_mcontext.mc_i7)); - __put_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6]))); - __put_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7]))); - - __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); + err |= __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1])); + err |= __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2])); + err |= __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3])); + err |= __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4])); + err |= __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5])); + err |= __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6])); + err |= __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7])); + err |= __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0])); + err |= __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1])); + err |= __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2])); + err |= __get_user(regs->u_regs[UREG_I3], (&(*grp)[MC_O3])); + err |= __get_user(regs->u_regs[UREG_I4], (&(*grp)[MC_O4])); + err |= __get_user(regs->u_regs[UREG_I5], (&(*grp)[MC_O5])); + err |= __get_user(regs->u_regs[UREG_I6], (&(*grp)[MC_O6])); + err |= __get_user(regs->u_regs[UREG_I7], (&(*grp)[MC_O7])); + + err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp)); + err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7)); + err |= __put_user(fp, + (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6]))); + err |= __put_user(i7, + (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7]))); + + err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); if(fenab) { unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; fprs_write(0); - __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); + err |= __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); if (fprs & FPRS_DL) - copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs), - (sizeof(unsigned int) * 32)); + err |= copy_from_user(fpregs, + &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs), + (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) - copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16, - (sizeof(unsigned int) * 32)); - __get_user(current->tss.xfsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); - __get_user(current->tss.gsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); + err |= copy_from_user(fpregs+16, + ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16, + (sizeof(unsigned int) * 32)); + err |= __get_user(current->tss.xfsr[0], + &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); + err |= __get_user(current->tss.gsr[0], + &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); regs->tstate &= ~TSTATE_PEF; } + if (err) + goto do_sigsegv; + return; do_sigsegv: lock_kernel(); @@ -134,6 +146,7 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) mcontext_t *mcp; unsigned long fp, i7; unsigned char fenab; + int err; synchronize_user_stack(); if(tp->w_saved || clear_user(ucp, sizeof(*ucp))) @@ -152,52 +165,61 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) regs->tpc = regs->tnpc; regs->tnpc += 4; + err = 0; if (_NSIG_WORDS == 1) - __put_user(current->blocked.sig[0], (unsigned long *)&ucp->uc_sigmask); + err |= __put_user(current->blocked.sig[0], + (unsigned long *)&ucp->uc_sigmask); else - __copy_to_user(&ucp->uc_sigmask, ¤t->blocked, sizeof(sigset_t)); - - __put_user(regs->tstate, &((*grp)[MC_TSTATE])); - __put_user(regs->tpc, &((*grp)[MC_PC])); - __put_user(regs->tnpc, &((*grp)[MC_NPC])); - __put_user(regs->y, &((*grp)[MC_Y])); - __put_user(regs->u_regs[UREG_G1], &((*grp)[MC_G1])); - __put_user(regs->u_regs[UREG_G2], &((*grp)[MC_G2])); - __put_user(regs->u_regs[UREG_G3], &((*grp)[MC_G3])); - __put_user(regs->u_regs[UREG_G4], &((*grp)[MC_G4])); - __put_user(regs->u_regs[UREG_G5], &((*grp)[MC_G5])); - __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G6])); - __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G7])); - __put_user(regs->u_regs[UREG_I0], &((*grp)[MC_O0])); - __put_user(regs->u_regs[UREG_I1], &((*grp)[MC_O1])); - __put_user(regs->u_regs[UREG_I2], &((*grp)[MC_O2])); - __put_user(regs->u_regs[UREG_I3], &((*grp)[MC_O3])); - __put_user(regs->u_regs[UREG_I4], &((*grp)[MC_O4])); - __put_user(regs->u_regs[UREG_I5], &((*grp)[MC_O5])); - __put_user(regs->u_regs[UREG_I6], &((*grp)[MC_O6])); - __put_user(regs->u_regs[UREG_I7], &((*grp)[MC_O7])); - - __get_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6]))); - __get_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7]))); - __put_user(fp, &(mcp->mc_fp)); - __put_user(i7, &(mcp->mc_i7)); - - __put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab)); + err |= __copy_to_user(&ucp->uc_sigmask, ¤t->blocked, + sizeof(sigset_t)); + + err |= __put_user(regs->tstate, &((*grp)[MC_TSTATE])); + err |= __put_user(regs->tpc, &((*grp)[MC_PC])); + err |= __put_user(regs->tnpc, &((*grp)[MC_NPC])); + err |= __put_user(regs->y, &((*grp)[MC_Y])); + err |= __put_user(regs->u_regs[UREG_G1], &((*grp)[MC_G1])); + err |= __put_user(regs->u_regs[UREG_G2], &((*grp)[MC_G2])); + err |= __put_user(regs->u_regs[UREG_G3], &((*grp)[MC_G3])); + err |= __put_user(regs->u_regs[UREG_G4], &((*grp)[MC_G4])); + err |= __put_user(regs->u_regs[UREG_G5], &((*grp)[MC_G5])); + err |= __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G6])); + err |= __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G7])); + err |= __put_user(regs->u_regs[UREG_I0], &((*grp)[MC_O0])); + err |= __put_user(regs->u_regs[UREG_I1], &((*grp)[MC_O1])); + err |= __put_user(regs->u_regs[UREG_I2], &((*grp)[MC_O2])); + err |= __put_user(regs->u_regs[UREG_I3], &((*grp)[MC_O3])); + err |= __put_user(regs->u_regs[UREG_I4], &((*grp)[MC_O4])); + err |= __put_user(regs->u_regs[UREG_I5], &((*grp)[MC_O5])); + err |= __put_user(regs->u_regs[UREG_I6], &((*grp)[MC_O6])); + err |= __put_user(regs->u_regs[UREG_I7], &((*grp)[MC_O7])); + + err |= __get_user(fp, + (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6]))); + err |= __get_user(i7, + (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7]))); + err |= __put_user(fp, &(mcp->mc_fp)); + err |= __put_user(i7, &(mcp->mc_i7)); + + err |= __put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab)); if(fenab) { unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; fprs = current->tss.fpsaved[0]; if (fprs & FPRS_DL) - copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs, - (sizeof(unsigned int) * 32)); + err |= copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs, + (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) - copy_to_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16, - (sizeof(unsigned int) * 32)); - __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr)); - __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr)); - __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs)); + err |= copy_to_user( + ((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16, + (sizeof(unsigned int) * 32)); + err |= __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr)); + err |= __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr)); + err |= __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs)); } + if (err) + goto do_sigsegv; + return; do_sigsegv: lock_kernel(); @@ -474,22 +496,25 @@ static int invalid_frame_pointer(void *fp, int fplen) return 0; } -static inline void +static inline int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = (unsigned long *)(regs+1); unsigned long fprs; + int err = 0; fprs = current->tss.fpsaved[0]; if (fprs & FPRS_DL) - copy_to_user(&fpu->si_float_regs[0], fpregs, - (sizeof(unsigned int) * 32)); + err |= copy_to_user(&fpu->si_float_regs[0], fpregs, + (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) - copy_to_user(&fpu->si_float_regs[32], fpregs+16, - (sizeof(unsigned int) * 32)); - __put_user(current->tss.xfsr[0], &fpu->si_fsr); - __put_user(current->tss.gsr[0], &fpu->si_gsr); - __put_user(fprs, &fpu->si_fprs); + err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16, + (sizeof(unsigned int) * 32)); + err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr); + err |= __put_user(current->tss.gsr[0], &fpu->si_gsr); + err |= __put_user(fprs, &fpu->si_fprs); + + return err; } static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize) @@ -500,7 +525,8 @@ static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, u /* This is the X/Open sanctioned signal stack switching. */ if (ka->sa.sa_flags & SA_ONSTACK) { - if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) + if (!on_sig_stack(sp) && + !((current->sas_ss_sp + current->sas_ss_size) & 7)) sp = current->sas_ss_sp + current->sas_ss_size; } return (void *)(sp - framesize); @@ -511,7 +537,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset) { struct new_signal_frame *sf; - int sigframe_size; + int sigframe_size, err; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -534,22 +560,25 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, } /* 2. Save the current process state */ - copy_to_user(&sf->info.si_regs, regs, sizeof (*regs)); + err = copy_to_user(&sf->info.si_regs, regs, sizeof (*regs)); if (current->tss.fpsaved[0] & FPRS_FEF) { - save_fpu_state(regs, &sf->fpu_state); - __put_user((u64)&sf->fpu_state, &sf->fpu_save); + err |= save_fpu_state(regs, &sf->fpu_state); + err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { - __put_user(0, &sf->fpu_save); + err |= __put_user(0, &sf->fpu_save); } - __put_user(oldset->sig[0], &sf->info.si_mask); + err |= __put_user(oldset->sig[0], &sf->info.si_mask); if (_NSIG_WORDS > 1) - __copy_to_user(sf->extramask, &oldset->sig[1], sizeof(sf->extramask)); + err |= __copy_to_user(sf->extramask, &oldset->sig[1], + sizeof(sf->extramask)); - copy_in_user((u64 *)sf, - (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), - sizeof(struct reg_window)); + err |= copy_in_user((u64 *)sf, + (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), + sizeof(struct reg_window)); + if (err) + goto sigsegv; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; @@ -572,8 +601,13 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */ + /* mov __NR_sigreturn, %g1 */ + err |= __put_user(0x821020d8, &sf->insns[0]); + + /* t 0x6d */ + err |= __put_user(0x91d0206d, &sf->insns[1]); + if (err) + goto sigsegv; if(pte_present(*ptep)) { unsigned long page = pte_page(*ptep); @@ -590,6 +624,9 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, sigill: lock_kernel(); do_exit(SIGILL); +sigsegv: + lock_kernel(); + do_exit(SIGSEGV); } static inline void @@ -597,7 +634,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset, siginfo_t *info) { struct rt_signal_frame *sf; - int sigframe_size; + int sigframe_size, err; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -619,27 +656,29 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, } /* 2. Save the current process state */ - copy_to_user(&sf->regs, regs, sizeof (*regs)); + err = copy_to_user(&sf->regs, regs, sizeof (*regs)); if (current->tss.fpsaved[0] & FPRS_FEF) { - save_fpu_state(regs, &sf->fpu_state); - __put_user((u64)&sf->fpu_state, &sf->fpu_save); + err |= save_fpu_state(regs, &sf->fpu_state); + err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { - __put_user(0, &sf->fpu_save); + err |= __put_user(0, &sf->fpu_save); } /* Setup sigaltstack */ - __put_user(current->sas_ss_sp, &sf->stack.ss_sp); - __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); - __put_user(current->sas_ss_size, &sf->stack.ss_size); + err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); + err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); - copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); + err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); - copy_in_user((u64 *)sf, - (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), - sizeof(struct reg_window)); + err |= copy_in_user((u64 *)sf, + (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), + sizeof(struct reg_window)); - copy_to_user(&sf->info, info, sizeof(siginfo_t)); + err |= copy_to_user(&sf->info, info, sizeof(siginfo_t)); + if (err) + goto sigsegv; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; @@ -662,8 +701,13 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); - __put_user(0x82102065, &sf->insns[0]); /* mov __NR_rt_sigreturn, %g1 */ - __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */ + /* mov __NR_rt_sigreturn, %g1 */ + err |= __put_user(0x82102065, &sf->insns[0]); + + /* t 0x6d */ + err |= __put_user(0x91d0206d, &sf->insns[1]); + if (err) + goto sigsegv; if(pte_present(*ptep)) { unsigned long page = pte_page(*ptep); @@ -680,6 +724,9 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, sigill: lock_kernel(); do_exit(SIGILL); +sigsegv: + lock_kernel(); + do_exit(SIGSEGV); } static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, @@ -721,6 +768,60 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, } } +#ifdef DEBUG_SIGNALS_MAPS + +#define MAPS_LINE_FORMAT "%016lx-%016lx %s %016lx %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. @@ -824,9 +925,26 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, unlock_kernel(); } #ifdef DEBUG_SIGNALS - /* Very useful to debug dynamic linker problems */ - printk ("Sig ILL going...\n"); + /* Very useful to debug the dynamic linker */ + printk ("Sig %d going...\n", (int)signr); show_regs (regs); +#ifdef DEBUG_SIGNALS_TRACE + { + struct reg_window *rw = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + unsigned long ins[8]; + + while(rw && + !(((unsigned long) rw) & 0x3)) { + copy_from_user(ins, &rw->ins[0], sizeof(ins)); + printk("Caller[%016lx](%016lx,%016lx,%016lx,%016lx,%016lx,%016lx)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]); + rw = (struct reg_window *)(unsigned long)(ins[6] + STACK_BIAS); + } + } +#endif +#ifdef DEBUG_SIGNALS_MAPS + printk("Maps:\n"); + read_maps(); +#endif #endif /* fall through */ default: diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index b62ab65ff..d425132fd 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.41 1998/07/30 11:29:32 davem Exp $ +/* $Id: signal32.c,v 1.47 1998/10/13 09:07:40 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -39,6 +39,7 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs, /* #define DEBUG_SIGNALS 1 */ /* #define DEBUG_SIGNALS_TRACE 1 */ /* #define DEBUG_SIGNALS_MAPS 1 */ +/* #define DEBUG_SIGNALS_TLB 1 */ /* Signal frames: the original one (compatible with SunOS): * @@ -75,6 +76,9 @@ struct new_signal_frame32 { /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; unsigned extramask[_NSIG_WORDS32 - 1]; + unsigned extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */ + /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */ + siginfo_extra_v8plus_t v8plus; __siginfo_fpu_t fpu_state; }; @@ -86,6 +90,9 @@ struct rt_signal_frame32 { /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; stack_t32 stack; + unsigned extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */ + /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */ + siginfo_extra_v8plus_t v8plus; __siginfo_fpu_t fpu_state; }; @@ -208,7 +215,7 @@ void do_new_sigreturn32(struct pt_regs *regs) unsigned pc, npc, fpu_save; sigset_t set; unsigned seta[_NSIG_WORDS32]; - int err; + int err, i; regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP]; @@ -231,24 +238,18 @@ void do_new_sigreturn32(struct pt_regs *regs) err = __get_user(regs->y, &sf->info.si_regs.y); err |= __get_user(psr, &sf->info.si_regs.psr); - err |= __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]); - err |= __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]); - err |= __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]); - err |= __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]); - err |= __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]); - err |= __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]); - err |= __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]); - err |= __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]); - err |= __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]); - err |= __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]); - err |= __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]); - err |= __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]); - err |= __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]); - err |= __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]); - err |= __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]); + for (i = UREG_G1; i <= UREG_I7; i++) + err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); + if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) { + err |= __get_user(i, &sf->v8plus.g_upper[0]); + if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) { + for (i = UREG_G1; i <= UREG_I7; i++) + err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + } + } /* User can only change condition codes in %tstate. */ - regs->tstate &= ~(TSTATE_ICC); + regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); err |= __get_user(fpu_save, &sf->fpu_save); @@ -270,8 +271,9 @@ void do_new_sigreturn32(struct pt_regs *regs) recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); return; + segv: - send_sig(SIGSEGV, current, 1); + do_exit(SIGSEGV); } asmlinkage void do_sigreturn32(struct pt_regs *regs) @@ -326,11 +328,12 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) err |= __get_user(psr, &scptr->sigc_psr); if (err) goto segv; - regs->tstate &= ~(TSTATE_ICC); + regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); return; + segv: - send_sig(SIGSEGV, current, 1); + do_exit(SIGSEGV); } asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) @@ -341,7 +344,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) sigset_t set; sigset_t32 seta; stack_t st; - int err; + int err, i; synchronize_user_stack(); regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; @@ -364,25 +367,19 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) /* 2. Restore the state */ err = __get_user(regs->y, &sf->regs.y); err |= __get_user(psr, &sf->regs.psr); - - err |= __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]); - err |= __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]); - err |= __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]); - err |= __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]); - err |= __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]); - err |= __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]); - err |= __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]); - err |= __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]); - err |= __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]); - err |= __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]); - err |= __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]); - err |= __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]); - err |= __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]); - err |= __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]); - err |= __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]); + + for (i = UREG_G1; i <= UREG_I7; i++) + err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]); + if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) { + err |= __get_user(i, &sf->v8plus.g_upper[0]); + if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) { + for (i = UREG_G1; i <= UREG_I7; i++) + err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + } + } /* User can only change condition codes in %tstate. */ - regs->tstate &= ~(TSTATE_ICC); + regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); err |= __get_user(fpu_save, &sf->fpu_save); @@ -412,7 +409,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) spin_unlock_irq(¤t->sigmask_lock); return; segv: - send_sig(SIGSEGV, current, 1); + do_exit(SIGSEGV); } /* Checks if the fp is valid */ @@ -445,6 +442,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, struct signal_sframe32 *sframep; struct sigcontext32 *sc; unsigned seta[_NSIG_WORDS32]; + int err = 0; #if 0 int window = 0; @@ -465,14 +463,14 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, /* Don't change signal code and address, so that * post mortem debuggers can have a look. */ - lock_kernel (); do_exit(SIGILL); } sc = &sframep->sig_context; /* We've already made sure frame pointer isn't in kernel space... */ - __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), &sc->sigc_onstack); + err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), + &sc->sigc_onstack); switch (_NSIG_WORDS) { case 4: seta[7] = (oldset->sig[3] >> 32); @@ -484,67 +482,80 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, case 1: seta[1] = (oldset->sig[0] >> 32); seta[0] = oldset->sig[0]; } - __put_user(seta[0], &sc->sigc_mask); - __copy_to_user(sframep->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)); - __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); - __put_user(pc, &sc->sigc_pc); - __put_user(npc, &sc->sigc_npc); + err |= __put_user(seta[0], &sc->sigc_mask); + err |= __copy_to_user(sframep->extramask, seta + 1, + (_NSIG_WORDS32 - 1) * sizeof(unsigned)); + err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); + err |= __put_user(pc, &sc->sigc_pc); + err |= __put_user(npc, &sc->sigc_npc); psr = tstate_to_psr (regs->tstate); if(current->tss.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; - __put_user(psr, &sc->sigc_psr); - __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); - __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); - __put_user(current->tss.w_saved, &sc->sigc_oswins); + err |= __put_user(psr, &sc->sigc_psr); + err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); + err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); + err |= __put_user(current->tss.w_saved, &sc->sigc_oswins); #if 0 /* w_saved is not currently used... */ if(current->tss.w_saved) for(window = 0; window < current->tss.w_saved; window++) { sc->sigc_spbuf[window] = (char *)current->tss.rwbuf_stkptrs[window]; - copy_to_user(&sc->sigc_wbuf[window], - ¤t->tss.reg_window[window], - sizeof(struct reg_window)); + err |= copy_to_user(&sc->sigc_wbuf[window], + ¤t->tss.reg_window[window], + sizeof(struct reg_window)); } else #endif - copy_in_user((u32 *)sframep, - (u32 *)(regs->u_regs[UREG_FP]), - sizeof(struct reg_window32)); + err |= copy_in_user((u32 *)sframep, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); current->tss.w_saved = 0; /* So process is allowed to execute. */ - __put_user(signr, &sframep->sig_num); + err |= __put_user(signr, &sframep->sig_num); if(signr == SIGSEGV || signr == SIGILL || signr == SIGFPE || signr == SIGBUS || signr == SIGEMT) { - __put_user(current->tss.sig_desc, &sframep->sig_code); - __put_user(current->tss.sig_address, &sframep->sig_address); + err |= __put_user(current->tss.sig_desc, &sframep->sig_code); + err |= __put_user(current->tss.sig_address, &sframep->sig_address); } else { - __put_user(0, &sframep->sig_code); - __put_user(0, &sframep->sig_address); + err |= __put_user(0, &sframep->sig_code); + err |= __put_user(0, &sframep->sig_address); } - __put_user((u64)sc, &sframep->sig_scptr); + err |= __put_user((u64)sc, &sframep->sig_scptr); + if (err) + goto sigsegv; + regs->u_regs[UREG_FP] = (unsigned long) sframep; regs->tpc = (unsigned long) sa->sa_handler; regs->tnpc = (regs->tpc + 4); + return; + +sigsegv: + do_exit(SIGSEGV); } -static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) +static inline int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; + int err = 0; fprs = current->tss.fpsaved[0]; if (fprs & FPRS_DL) - copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32)); + err |= copy_to_user(&fpu->si_float_regs[0], fpregs, + (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) - copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32)); - __put_user(current->tss.xfsr[0], &fpu->si_fsr); - __put_user(current->tss.gsr[0], &fpu->si_gsr); - __put_user(fprs, &fpu->si_fprs); + err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16, + (sizeof(unsigned int) * 32)); + err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr); + err |= __put_user(current->tss.gsr[0], &fpu->si_gsr); + err |= __put_user(fprs, &fpu->si_fprs); + + return err; } static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, @@ -553,7 +564,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg struct new_signal_frame32 *sf; int sigframe_size; u32 psr; - int i; + int i, err; unsigned seta[_NSIG_WORDS32]; /* 1. Make sure everything is clean */ @@ -583,21 +594,25 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg } /* 2. Save the current process state */ - put_user(regs->tpc, &sf->info.si_regs.pc); - __put_user(regs->tnpc, &sf->info.si_regs.npc); - __put_user(regs->y, &sf->info.si_regs.y); + err = put_user(regs->tpc, &sf->info.si_regs.pc); + err |= __put_user(regs->tnpc, &sf->info.si_regs.npc); + err |= __put_user(regs->y, &sf->info.si_regs.y); psr = tstate_to_psr (regs->tstate); if(current->tss.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; - __put_user(psr, &sf->info.si_regs.psr); + err |= __put_user(psr, &sf->info.si_regs.psr); for (i = 0; i < 16; i++) - __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); + err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); + err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size); + err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]); + for (i = 1; i < 16; i++) + err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); if (psr & PSR_EF) { - save_fpu_state32(regs, &sf->fpu_state); - __put_user((u64)&sf->fpu_state, &sf->fpu_save); + err |= save_fpu_state32(regs, &sf->fpu_state); + err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { - __put_user(0, &sf->fpu_save); + err |= __put_user(0, &sf->fpu_save); } switch (_NSIG_WORDS) { @@ -610,13 +625,17 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg case 1: seta[1] = (oldset->sig[0] >> 32); seta[0] = oldset->sig[0]; } - __put_user(seta[0], &sf->info.si_mask); - __copy_to_user(sf->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)); + err |= __put_user(seta[0], &sf->info.si_mask); + err |= __copy_to_user(sf->extramask, seta + 1, + (_NSIG_WORDS32 - 1) * sizeof(unsigned)); - copy_in_user((u32 *)sf, - (u32 *)(regs->u_regs[UREG_FP]), - sizeof(struct reg_window32)); + err |= copy_in_user((u32 *)sf, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); + if (err) + goto sigsegv; + /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; regs->u_regs[UREG_I0] = signo; @@ -638,8 +657,10 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + err = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/ + err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/ + if(err) + goto sigsegv; if(pte_present(*ptep)) { unsigned long page = pte_page(*ptep); @@ -654,8 +675,9 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg return; sigill: - lock_kernel(); do_exit(SIGILL); +sigsegv: + do_exit(SIGSEGV); } /* Setup a Solaris stack frame */ @@ -674,7 +696,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, int window = 0; #endif unsigned psr; - int i; + int i, err; synchronize_user_stack(); save_and_clear_fpu(); @@ -686,12 +708,11 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, #ifdef DEBUG_SIGNALS printk ("Invalid stack frame\n"); #endif - lock_kernel (); do_exit(SIGILL); } /* Start with a clean frame pointer and fill it */ - clear_user(sfp, sizeof (*sfp)); + err = clear_user(sfp, sizeof (*sfp)); /* Setup convenience variables */ si = &sfp->si; @@ -709,37 +730,37 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, if (_NSIG_WORDS >= 2) { setv.sigbits[2] = oldset->sig[1]; setv.sigbits[3] = (oldset->sig[1] >> 32); - __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); } else - __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); + err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); /* Store registers */ - __put_user(regs->tpc, &((*gr) [SVR4_PC])); - __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); + err |= __put_user(regs->tpc, &((*gr) [SVR4_PC])); + err |= __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); psr = tstate_to_psr (regs->tstate); if(current->tss.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; - __put_user(psr, &((*gr) [SVR4_PSR])); - __put_user(regs->y, &((*gr) [SVR4_Y])); + err |= __put_user(psr, &((*gr) [SVR4_PSR])); + err |= __put_user(regs->y, &((*gr) [SVR4_Y])); /* Copy g [1..7] and o [0..7] registers */ for (i = 0; i < 7; i++) - __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); + err |= __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); for (i = 0; i < 8; i++) - __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); + err |= __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); /* Setup sigaltstack */ - __put_user(current->sas_ss_sp, &uc->stack.sp); - __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); - __put_user(current->sas_ss_size, &uc->stack.size); + err |= __put_user(current->sas_ss_sp, &uc->stack.sp); + err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); + err |= __put_user(current->sas_ss_size, &uc->stack.size); /* Save the currently window file: */ /* 1. Link sfp->uc->gwins to our windows */ - __put_user((u32)(long)gw, &mc->gwin); + err |= __put_user((u32)(long)gw, &mc->gwin); /* 2. Number of windows to restore at setcontext (): */ - __put_user(current->tss.w_saved, &gw->count); + err |= __put_user(current->tss.w_saved, &gw->count); /* 3. Save each valid window * Currently, it makes a copy of the windows from the kernel copy. @@ -754,9 +775,12 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, */ #if 0 for(window = 0; window < current->tss.w_saved; window++) { - __put_user((int *) &(gw->win [window]), (int **)gw->winptr +window ); - copy_to_user(&gw->win [window], ¤t->tss.reg_window [window], sizeof (svr4_rwindow_t)); - __put_user(0, (int *)gw->winptr + window); + err |= __put_user((int *) &(gw->win [window]), + (int **)gw->winptr +window ); + err |= copy_to_user(&gw->win [window], + ¤t->tss.reg_window [window], + sizeof (svr4_rwindow_t)); + err |= __put_user(0, (int *)gw->winptr + window); } #endif @@ -768,8 +792,10 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, * that much currently, should use those that David already * is providing with tss.sig_desc */ - __put_user(signr, &si->siginfo.signo); - __put_user(SVR4_SINOINFO, &si->siginfo.code); + err |= __put_user(signr, &si->siginfo.signo); + err |= __put_user(SVR4_SINOINFO, &si->siginfo.code); + if (err) + goto sigsegv; regs->u_regs[UREG_FP] = (unsigned long) sfp; regs->tpc = (unsigned long) sa->sa_handler; @@ -783,14 +809,21 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, struct reg_window32 *rw = (struct reg_window32 *) (regs->u_regs [14] & 0x00000000ffffffffUL); - __put_user(signr, &rw->ins [0]); - __put_user((u64)si, &rw->ins [1]); - __put_user((u64)uc, &rw->ins [2]); - __put_user((u64)sfp, &rw->ins [6]); /* frame pointer */ + err |= __put_user(signr, &rw->ins [0]); + err |= __put_user((u64)si, &rw->ins [1]); + err |= __put_user((u64)uc, &rw->ins [2]); + err |= __put_user((u64)sfp, &rw->ins [6]); /* frame pointer */ + if (err) + goto sigsegv; + regs->u_regs[UREG_I0] = signr; regs->u_regs[UREG_I1] = (u32)(u64) si; regs->u_regs[UREG_I2] = (u32)(u64) uc; } + return; + +sigsegv: + do_exit(SIGSEGV); } asmlinkage int @@ -799,18 +832,16 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) svr4_gregset_t *gr; svr4_mcontext_t *mc; svr4_sigset_t setv; - int i; + int i, err; synchronize_user_stack(); save_and_clear_fpu(); if (current->tss.w_saved){ printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved); - lock_kernel(); do_exit (SIGSEGV); } - if(clear_user(uc, sizeof (*uc))) - return -EFAULT; + err = clear_user(uc, sizeof (*uc)); /* Setup convenience variables */ mc = &uc->mcontext; @@ -821,38 +852,38 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) if (_NSIG_WORDS >= 2) { setv.sigbits[2] = current->blocked.sig[1]; setv.sigbits[3] = (current->blocked.sig[1] >> 32); - __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); + err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); } else - __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); + err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned)); /* Store registers */ - __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); - __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]); + err |= __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); + err |= __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]); #if 1 - __put_user(0, &uc->mcontext.greg [SVR4_PSR]); + err |= __put_user(0, &uc->mcontext.greg [SVR4_PSR]); #else i = tstate_to_psr(regs->tstate) & ~PSR_EF; if (current->tss.fpsaved[0] & FPRS_FEF) i |= PSR_EF; - __put_user(i, &uc->mcontext.greg [SVR4_PSR]); + err |= __put_user(i, &uc->mcontext.greg [SVR4_PSR]); #endif - __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); + err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); /* Copy g [1..7] and o [0..7] registers */ for (i = 0; i < 7; i++) - __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); + err |= __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); for (i = 0; i < 8; i++) - __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); + err |= __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); /* Setup sigaltstack */ - __put_user(current->sas_ss_sp, &uc->stack.sp); - __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); - __put_user(current->sas_ss_size, &uc->stack.size); + err |= __put_user(current->sas_ss_sp, &uc->stack.sp); + err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); + err |= __put_user(current->sas_ss_size, &uc->stack.size); /* The register file is not saved * we have already stuffed all of it with sync_user_stack */ - return 0; + return (err ? -EFAULT : 0); } @@ -923,9 +954,9 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) spin_unlock_irq(¤t->sigmask_lock); regs->tpc = pc; regs->tnpc = npc | 1; - __get_user(regs->y, &((*gr) [SVR4_Y])); - __get_user(psr, &((*gr) [SVR4_PSR])); - regs->tstate &= ~(TSTATE_ICC); + err |= __get_user(regs->y, &((*gr) [SVR4_Y])); + err |= __get_user(psr, &((*gr) [SVR4_PSR])); + regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); #if 0 if(psr & PSR_EF) @@ -933,13 +964,14 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) #endif /* Restore g[1..7] and o[0..7] registers */ for (i = 0; i < 7; i++) - __get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); + err |= __get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); for (i = 0; i < 8; i++) - __get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); + err |= __get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); + if(err) + goto sigsegv; return -EINTR; sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -950,7 +982,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs struct rt_signal_frame32 *sf; int sigframe_size; u32 psr; - int i; + int i, err; sigset_t32 seta; /* 1. Make sure everything is clean */ @@ -980,27 +1012,31 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs } /* 2. Save the current process state */ - put_user(regs->tpc, &sf->regs.pc); - __put_user(regs->tnpc, &sf->regs.npc); - __put_user(regs->y, &sf->regs.y); + err = put_user(regs->tpc, &sf->regs.pc); + err |= __put_user(regs->tnpc, &sf->regs.npc); + err |= __put_user(regs->y, &sf->regs.y); psr = tstate_to_psr (regs->tstate); if(current->tss.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; - __put_user(psr, &sf->regs.psr); + err |= __put_user(psr, &sf->regs.psr); for (i = 0; i < 16; i++) - __put_user(regs->u_regs[i], &sf->regs.u_regs[i]); + err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]); + err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size); + err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]); + for (i = 1; i < 16; i++) + err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); if (psr & PSR_EF) { - save_fpu_state32(regs, &sf->fpu_state); - __put_user((u64)&sf->fpu_state, &sf->fpu_save); + err |= save_fpu_state32(regs, &sf->fpu_state); + err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { - __put_user(0, &sf->fpu_save); + err |= __put_user(0, &sf->fpu_save); } /* Setup sigaltstack */ - __put_user(current->sas_ss_sp, &sf->stack.ss_sp); - __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); - __put_user(current->sas_ss_size, &sf->stack.ss_size); + err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); + err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); switch (_NSIG_WORDS) { case 4: seta.sig[7] = (oldset->sig[3] >> 32); @@ -1012,11 +1048,13 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs case 1: seta.sig[1] = (oldset->sig[0] >> 32); seta.sig[0] = oldset->sig[0]; } - __copy_to_user(&sf->mask, &seta, sizeof(sigset_t)); + err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t)); - copy_in_user((u32 *)sf, - (u32 *)(regs->u_regs[UREG_FP]), - sizeof(struct reg_window32)); + err |= copy_in_user((u32 *)sf, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); + if (err) + goto sigsegv; /* 3. signal handler back-trampoline and parameters */ regs->u_regs[UREG_FP] = (unsigned long) sf; @@ -1039,8 +1077,13 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2); - __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ - __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */ + /* mov __NR_rt_sigreturn, %g1 */ + err |= __put_user(0x82102065, &sf->insns[0]); + + /* t 0x10 */ + err |= __put_user(0x91d02010, &sf->insns[1]); + if (err) + goto sigsegv; if(pte_present(*ptep)) { unsigned long page = pte_page(*ptep); @@ -1055,8 +1098,9 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs return; sigill: - lock_kernel(); do_exit(SIGILL); +sigsegv: + do_exit(SIGSEGV); } static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, @@ -1249,14 +1293,27 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs, case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); - if(current->binfmt->core_dump(signr, regs)) + if(current->binfmt && + current->binfmt->core_dump && + current->binfmt->core_dump(signr, regs)) exit_code |= 0x80; unlock_kernel(); } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); - show_regs (regs); + /* On SMP we are only interested in the current + * CPU's registers. + */ + __show_regs (regs); +#ifdef DEBUG_SIGNALS_TLB + do { + extern void sparc_ultra_dump_itlb(void); + extern void sparc_ultra_dump_dtlb(void); + sparc_ultra_dump_dtlb(); + sparc_ultra_dump_itlb(); + } while(0); +#endif #ifdef DEBUG_SIGNALS_TRACE { struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 3ec32e92b..4bdfca1b7 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -41,7 +41,9 @@ int smp_threads_ready = 0; struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64))); -static unsigned char boot_cpu_id __initdata = 0; +/* Please don't make this initdata!!! --DaveM */ +static unsigned char boot_cpu_id = 0; + static int smp_activated = 0; volatile int cpu_number_map[NR_CPUS]; @@ -63,7 +65,7 @@ int smp_info(char *buf) for (i = 0; i < NR_CPUS; i++) if(cpu_present_map & (1UL << i)) len += sprintf(buf + len, - "CPU%d:\t\tonline\n", i + "CPU%d:\t\tonline\n", i); return len; } @@ -82,12 +84,16 @@ int smp_bogo(char *buf) __initfunc(void smp_store_cpu_info(int id)) { - cpu_data[id].udelay_val = loops_per_sec; cpu_data[id].irq_count = 0; + cpu_data[id].bh_count = 0; + /* multiplier and counter set by + smp_setup_percpu_timer() */ + cpu_data[id].udelay_val = loops_per_sec; + cpu_data[id].pgcache_size = 0; + cpu_data[id].pte_cache = NULL; cpu_data[id].pgdcache_size = 0; cpu_data[id].pgd_cache = NULL; - cpu_data[id].pte_cache = NULL; } extern void distribute_irqs(void); @@ -137,6 +143,11 @@ __initfunc(void smp_callin(void)) __asm__ __volatile__("membar #Sync\n\t" "flush %%g6" : : : "memory"); + /* Clear this or we will die instantly when we + * schedule back to this idler... + */ + current->tss.flags &= ~(SPARC_FLAG_NEWCHILD); + while(!smp_processors_ready) membar("#LoadLoad"); } @@ -380,7 +391,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm) { u32 ctx = mm->context & 0x3ff; - if(mm == current->mm && mm->count == 1) { + if(mm == current->mm && atomic_read(&mm->count) == 1) { if(mm->cpu_vm_mask == (1UL << smp_processor_id())) goto local_flush_and_out; return smp_cross_call_avoidance(mm); @@ -396,7 +407,9 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, { u32 ctx = mm->context & 0x3ff; - if(mm == current->mm && mm->count == 1) { + start &= PAGE_MASK; + end &= PAGE_MASK; + if(mm == current->mm && atomic_read(&mm->count) == 1) { if(mm->cpu_vm_mask == (1UL << smp_processor_id())) goto local_flush_and_out; return smp_cross_call_avoidance(mm); @@ -404,8 +417,6 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); local_flush_and_out: - start &= PAGE_MASK; - end &= PAGE_MASK; __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start)); } @@ -413,13 +424,14 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) { u32 ctx = mm->context & 0x3ff; - if(mm == current->mm && mm->count == 1) { + page &= PAGE_MASK; + if(mm == current->mm && atomic_read(&mm->count) == 1) { if(mm->cpu_vm_mask == (1UL << smp_processor_id())) goto local_flush_and_out; return smp_cross_call_avoidance(mm); } #if 0 /* XXX Disabled until further notice... */ - else if(mm->count == 1) { + else if(atomic_read(&mm->count) == 1) { /* Try to handle two special cases to avoid cross calls * in common scenerios where we are swapping process * pages out. @@ -433,11 +445,11 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); local_flush_and_out: - __flush_tlb_page(ctx, (page & PAGE_MASK), SECONDARY_CONTEXT); + __flush_tlb_page(ctx, page, SECONDARY_CONTEXT); } /* CPU capture. */ -#define CAPTURE_DEBUG +/* #define CAPTURE_DEBUG */ extern unsigned long xcall_capture; static atomic_t smp_capture_depth = ATOMIC_INIT(0); @@ -446,37 +458,42 @@ static unsigned long penguins_are_doing_time = 0; void smp_capture(void) { - int result = atomic_add_return(1, &smp_capture_depth); + if (smp_processors_ready) { + int result = atomic_add_return(1, &smp_capture_depth); - membar("#StoreStore | #LoadStore"); - if(result == 1) { - int ncpus = smp_num_cpus; + membar("#StoreStore | #LoadStore"); + if(result == 1) { + int ncpus = smp_num_cpus; #ifdef CAPTURE_DEBUG - printk("CPU[%d]: Sending penguins to jail...", smp_processor_id()); + printk("CPU[%d]: Sending penguins to jail...", + smp_processor_id()); #endif - penguins_are_doing_time = 1; - membar("#StoreStore | #LoadStore"); - atomic_inc(&smp_capture_registry); - smp_cross_call(&xcall_capture, 0, 0, 0); - while(atomic_read(&smp_capture_registry) != ncpus) - membar("#LoadLoad"); + penguins_are_doing_time = 1; + membar("#StoreStore | #LoadStore"); + atomic_inc(&smp_capture_registry); + smp_cross_call(&xcall_capture, 0, 0, 0); + while(atomic_read(&smp_capture_registry) != ncpus) + membar("#LoadLoad"); #ifdef CAPTURE_DEBUG - printk("done\n"); + printk("done\n"); #endif + } } } void smp_release(void) { - if(atomic_dec_and_test(&smp_capture_depth)) { + if(smp_processors_ready) { + if(atomic_dec_and_test(&smp_capture_depth)) { #ifdef CAPTURE_DEBUG - printk("CPU[%d]: Giving pardon to imprisoned penguins\n", - smp_processor_id()); + printk("CPU[%d]: Giving pardon to imprisoned penguins\n", + smp_processor_id()); #endif - penguins_are_doing_time = 0; - membar("#StoreStore | #StoreLoad"); - atomic_dec(&smp_capture_registry); + penguins_are_doing_time = 0; + membar("#StoreStore | #StoreLoad"); + atomic_dec(&smp_capture_registry); + } } } @@ -539,8 +556,12 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) if(!--prof_counter(cpu)) { if (cpu == boot_cpu_id) { - extern void irq_enter(int, int); - extern void irq_exit(int, int); +/* XXX Keep this in sync with irq.c --DaveM */ +#define irq_enter(cpu, irq) \ +do { hardirq_enter(cpu); \ + spin_unlock_wait(&global_irq_lock); \ +} while(0) +#define irq_exit(cpu, irq) hardirq_exit(cpu) irq_enter(cpu, 0); kstat.irqs[cpu][0]++; @@ -548,6 +569,9 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) timer_tick_interrupt(regs); irq_exit(cpu, 0); + +#undef irq_enter +#undef irq_exit } if(current->pid) { diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 0bdd42775..a42505edc 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.39 1998/07/04 12:35:59 ecd Exp $ +/* $Id: sparc64_ksyms.c,v 1.49 1998/10/28 08:11:28 jj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -13,8 +13,10 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> +#include <linux/sched.h> #include <linux/in6.h> #include <linux/pci.h> +#include <linux/interrupt.h> #include <asm/oplib.h> #include <asm/delay.h> @@ -55,13 +57,14 @@ extern void die_if_kernel(char *str, struct pt_regs *regs); extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); -extern void *__bzero_1page(void *); extern void *__bzero(void *, size_t); extern void *__bzero_noasi(void *, size_t); extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); extern int __strncmp(const char *, const char *, __kernel_size_t); +extern __kernel_size_t __strlen(const char *); +extern __kernel_size_t strlen(const char *); extern char saved_command_line[]; extern char *getname32(u32 name); extern void linux_sparc_syscall(void); @@ -86,6 +89,17 @@ extern void dump_thread(struct pt_regs *, struct user *); #ifdef __SMP__ extern spinlock_t scheduler_lock; +extern spinlock_t kernel_flag; +extern int smp_num_cpus; +#ifdef SPIN_LOCK_DEBUG +extern void _do_spin_lock (spinlock_t *lock, char *str); +extern void _do_spin_unlock (spinlock_t *lock); +extern int _spin_trylock (spinlock_t *lock); +extern void _do_read_lock(rwlock_t *rw, char *str); +extern void _do_read_unlock(rwlock_t *rw, char *str); +extern void _do_write_lock(rwlock_t *rw, char *str); +extern void _do_write_unlock(rwlock_t *rw); +#endif #endif /* One thing to note is that the way the symbols of the mul/div @@ -101,20 +115,46 @@ __attribute__((section("__ksymtab"))) = \ /* used by various drivers */ #ifdef __SMP__ +/* Kernel wide locking */ EXPORT_SYMBOL(scheduler_lock); +EXPORT_SYMBOL(kernel_flag); + +/* Software-IRQ BH locking */ EXPORT_SYMBOL(global_bh_lock); -EXPORT_SYMBOL(klock_info); +EXPORT_SYMBOL(global_bh_count); +EXPORT_SYMBOL(synchronize_bh); + +/* Hard IRQ locking */ EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(global_irq_lock); +EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL_PRIVATE(global_cli); EXPORT_SYMBOL_PRIVATE(global_sti); +EXPORT_SYMBOL_PRIVATE(global_save_flags); EXPORT_SYMBOL_PRIVATE(global_restore_flags); + +/* Per-CPU information table */ +EXPORT_SYMBOL(cpu_data); + +/* Misc SMP information */ +EXPORT_SYMBOL(smp_num_cpus); + +/* Spinlock debugging library, optional. */ +#ifdef SPIN_LOCK_DEBUG +EXPORT_SYMBOL(_do_spin_lock); +EXPORT_SYMBOL(_do_spin_unlock); +EXPORT_SYMBOL(_spin_trylock); +EXPORT_SYMBOL(_do_read_lock); +EXPORT_SYMBOL(_do_read_unlock); +EXPORT_SYMBOL(_do_write_lock); +EXPORT_SYMBOL(_do_write_unlock); +#endif + #else EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(local_bh_count); #endif -EXPORT_SYMBOL_PRIVATE(_lock_kernel); -EXPORT_SYMBOL_PRIVATE(_unlock_kernel); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -124,7 +164,6 @@ EXPORT_SYMBOL(mstk48t02_regs); EXPORT_SYMBOL(request_fast_irq); EXPORT_SYMBOL(sparc_alloc_io); EXPORT_SYMBOL(sparc_free_io); -EXPORT_SYMBOL(__sparc64_bh_counter); EXPORT_SYMBOL(sparc_ultra_unmapioaddr); EXPORT_SYMBOL(mmu_get_scsi_sgl); EXPORT_SYMBOL(mmu_get_scsi_one); @@ -184,7 +223,10 @@ EXPORT_SYMBOL(__prom_getsibling); /* sparc library symbols */ EXPORT_SYMBOL(bcopy); +EXPORT_SYMBOL(__strlen); +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 EXPORT_SYMBOL(strlen); +#endif EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); @@ -215,12 +257,15 @@ EXPORT_SYMBOL(svr4_setcontext); EXPORT_SYMBOL(prom_cpu_nodes); EXPORT_SYMBOL(sys_ioctl); EXPORT_SYMBOL(sys32_ioctl); +EXPORT_SYMBOL(get_unmapped_area); +EXPORT_SYMBOL(move_addr_to_kernel); +EXPORT_SYMBOL(move_addr_to_user); #endif /* Special internal versions of library functions. */ EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(__bzero_1page); +EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(__bzero); EXPORT_SYMBOL(__memscan_zero); EXPORT_SYMBOL(__memscan_generic); diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c index a0bfb47ef..d32ea68c2 100644 --- a/arch/sparc64/kernel/sunos_ioctl32.c +++ b/arch/sparc64/kernel/sunos_ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl32.c,v 1.9 1998/03/29 10:10:53 davem Exp $ +/* $Id: sunos_ioctl32.c,v 1.10 1998/08/15 20:42:46 davem Exp $ * sunos_ioctl32.c: SunOS ioctl compatability on sparc64. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -24,7 +24,14 @@ #include <linux/smp_lock.h> #include <asm/kbio.h> -#define A(x) ((unsigned long)x) +/* Use this to get at 32-bit user passed pointers. */ +#define A(__x) \ +({ unsigned long __ret; \ + __asm__ ("srl %0, 0, %0" \ + : "=r" (__ret) \ + : "0" (__x)); \ + __ret; \ +}) #define SUNOS_NR_OPEN 256 diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index ec23e92a0..fd1ff6a0b 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -1,95 +1,76 @@ -/* $Id: sys32.S,v 1.6 1998/06/28 08:28:22 ecd Exp $ +/* $Id: sys32.S,v 1.8 1998/10/28 08:10:37 jj Exp $ * sys32.S: I-cache tricks for 32-bit compatability layer simple * conversions. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ +/* NOTE: call as jump breaks return stack, we have to avoid that */ + .text .align 32 .globl sys32_mmap sys32_mmap: - srl %o0, 0, %o0 ! IEU0 Group - sethi %hi(0xffffffff), %g2 ! IEU1 - srl %o1, 0, %o1 ! IEU0 Group - or %g2, %lo(0xffffffff), %g2 ! IEU1 - srl %o2, 0, %o2 ! IEU0 Group - mov %o7, %g1 ! IEU1 - and %o3, %g2, %o3 ! IEU0 Group - and %o4, %g2, %o4 ! IEU1 - and %o5, %g2, %o5 ! IEU0 Group - call sys_mmap ! CTI Group brk forced - mov %g1, %o7 ! IEU0 Group (regdep) + srl %o4, 0, %o4 + sethi %hi(sys_mmap), %g1 + jmpl %g1 + %lo(sys_mmap), %g0 + srl %o5, 0, %o5 .align 32 .globl sys32_lseek .globl sys32_chmod, sys32_chown, sys32_lchown, sys32_mknod sys32_lseek: sra %o1, 0, %o1 - mov %o7, %g1 - call sys_lseek - mov %g1, %o7 + sethi %hi(sys_lseek), %g1 + jmpl %g1 + %lo(sys_lseek), %g0 + nop sys32_chmod: - sll %o1, 16, %o1 - mov %o7, %g1 - srl %o0, 0, %o0 - srl %o1, 16, %o1 - call sys_chmod - mov %g1, %o7 + sethi %hi(0xffff), %g2 + sethi %hi(sys_chmod), %g1 + orcc %g2, %lo(0xffff), %g2 + jmpl %g1 + %lo(sys_chmod), %g0 + and %o1, %g2, %o1 sys32_chown: - sll %o1, 16, %o1 - mov %o7, %g1 - sll %o2, 16, %o2 - srl %o0, 0, %o0 - srl %o1, 16, %o1 - srl %o2, 16, %o2 - call sys_chown - mov %g1, %o7 + sethi %hi(0xffff), %g2 + sethi %hi(sys_chown), %g1 + orcc %g2, %lo(0xffff), %g2 + and %o1, %g2, %o1 + jmpl %g1 + %lo(sys_chown), %g0 + and %o2, %g2, %o2 sys32_lchown: - sll %o1, 16, %o1 - mov %o7, %g1 - sll %o2, 16, %o2 - srl %o0, 0, %o0 - srl %o1, 16, %o1 - srl %o2, 16, %o2 - call sys_lchown - mov %g1, %o7 + sethi %hi(0xffff), %g2 + sethi %hi(sys_lchown), %g1 + orcc %g2, %lo(0xffff), %g2 + and %o1, %g2, %o1 + jmpl %g1 + %lo(sys_lchown), %g0 + and %o2, %g2, %o2 sys32_mknod: - sll %o2, 16, %o2 - mov %o7, %g1 - srl %o0, 0, %o0 - srl %o2, 16, %o2 - call sys_mknod - mov %g1, %o7 + sethi %hi(0xffff), %g2 + sethi %hi(sys_mknod), %g1 + orcc %g2, %lo(0xffff), %g2 + jmpl %g1 + %lo(sys_mknod), %g0 + and %o2, %g2, %o2 .align 32 .globl sys32_sendto, sys32_recvfrom, sys32_getsockopt sys32_sendto: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - srl %o4, 0, %o4 - call sys_sendto - mov %g1, %o7 + sethi %hi(sys_sendto), %g1 + jmpl %g1 + %lo(sys_sendto), %g0 + srl %o4, 0, %o4 sys32_recvfrom: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 srl %o4, 0, %o4 - srl %o5, 0, %o5 - call sys_recvfrom - mov %g1, %o7 + sethi %hi(sys_recvfrom), %g1 + jmpl %g1 + %lo(sys_recvfrom), %g0 + srl %o5, 0, %o5 sys32_getsockopt: - srl %o3, 0, %o3 - mov %o7, %g1 - srl %o4, 0, %o4 - call sys_getsockopt - mov %g1, %o7 + sethi %hi(sys_getsockopt), %g1 + jmpl %g1 + %lo(sys_getsockopt), %g0 + srl %o4, 0, %o4 .globl sys32_bdflush sys32_bdflush: - sra %o1, 0, %o1 - mov %o7, %g1 - call sys_bdflush - mov %g1, %o7 + sethi %hi(sys_bdflush), %g1 + jmpl %g1 + %lo(sys_bdflush), %g0 + sra %o1, 0, %o1 diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 1d9c0457e..08ce07244 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.20 1998/08/03 20:03:26 davem Exp $ +/* $Id: sys_sparc.c,v 1.25 1998/10/21 03:21:15 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -25,6 +25,7 @@ #include <asm/uaccess.h> #include <asm/ipc.h> #include <asm/utrap.h> +#include <asm/perfctr.h> /* 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. @@ -151,6 +152,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, struct file * file = NULL; unsigned long retval = -EBADF; + down(¤t->mm->mmap_sem); lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); @@ -181,6 +183,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, } } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, off); out_putf: @@ -188,6 +191,7 @@ out_putf: fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -252,17 +256,20 @@ asmlinkage int sys_aplib(void) asmlinkage int solaris_syscall(struct pt_regs *regs) { + static int count = 0; lock_kernel(); regs->tpc = regs->tnpc; regs->tnpc += 4; - printk ("For Solaris binary emulation you need solaris module loaded\n"); + if(++count <= 20) + printk ("For Solaris binary emulation you need solaris module loaded\n"); show_regs (regs); send_sig(SIGSEGV, current, 1); unlock_kernel(); - return 0; + return -ENOSYS; } -asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p, utrap_handler_t new_d, +asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p, + utrap_handler_t new_d, utrap_handler_t *old_p, utrap_handler_t *old_d) { if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31) @@ -374,3 +381,105 @@ sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, return ret; } + +/* Invoked by rtrap code to update performance counters in + * user space. + */ +asmlinkage void +update_perfctrs(void) +{ + unsigned long pic, tmp; + + read_pic(pic); + tmp = (current->tss.kernel_cntd0 += (unsigned int)pic); + __put_user(tmp, current->tss.user_cntd0); + tmp = (current->tss.kernel_cntd1 += (pic >> 32)); + __put_user(tmp, current->tss.user_cntd1); + reset_pic(); +} + +asmlinkage int +sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2) +{ + int err = 0; + + switch(opcode) { + case PERFCTR_ON: + current->tss.pcr_reg = arg2; + current->tss.user_cntd0 = (u64 *) arg0; + current->tss.user_cntd1 = (u64 *) arg1; + current->tss.kernel_cntd0 = + current->tss.kernel_cntd1 = 0; + write_pcr(arg2); + reset_pic(); + current->tss.flags |= SPARC_FLAG_PERFCTR; + break; + + case PERFCTR_OFF: + err = -EINVAL; + if ((current->tss.flags & SPARC_FLAG_PERFCTR) != 0) { + current->tss.user_cntd0 = + current->tss.user_cntd1 = NULL; + current->tss.pcr_reg = 0; + write_pcr(0); + current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + err = 0; + } + break; + + case PERFCTR_READ: { + unsigned long pic, tmp; + + if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + err = -EINVAL; + break; + } + read_pic(pic); + tmp = (current->tss.kernel_cntd0 += (unsigned int)pic); + err |= __put_user(tmp, current->tss.user_cntd0); + tmp = (current->tss.kernel_cntd1 += (pic >> 32)); + err |= __put_user(tmp, current->tss.user_cntd1); + reset_pic(); + break; + } + + case PERFCTR_CLRPIC: + if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + err = -EINVAL; + break; + } + current->tss.kernel_cntd0 = + current->tss.kernel_cntd1 = 0; + reset_pic(); + break; + + case PERFCTR_SETPCR: { + u64 *user_pcr = (u64 *)arg0; + if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + err = -EINVAL; + break; + } + err |= __get_user(current->tss.pcr_reg, user_pcr); + write_pcr(current->tss.pcr_reg); + current->tss.kernel_cntd0 = + current->tss.kernel_cntd1 = 0; + reset_pic(); + break; + } + + case PERFCTR_GETPCR: { + u64 *user_pcr = (u64 *)arg0; + if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + err = -EINVAL; + break; + } + err |= __put_user(current->tss.pcr_reg, user_pcr); + break; + } + + default: + err = -EINVAL; + break; + }; + return err; +} diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index a5043b3ac..1a49380f1 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.90 1998/07/29 16:32:30 jj Exp $ +/* $Id: sys_sparc32.c,v 1.100 1998/11/08 11:14:00 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -50,14 +50,30 @@ #include <asm/fpumacro.h> #include <asm/semaphore.h> -/* As gcc will warn about casting u32 to some ptr, we have to cast it to - * unsigned long first, and that's what is A() for. - * You just do (void *)A(x), instead of having to - * type (void *)((unsigned long)x) or instead of just (void *)x, which will - * produce warnings. +/* Use this to get at 32-bit user passed pointers. */ +/* Things to consider: the low-level assembly stub does + srl x, 0, x for first four arguments, so if you have + pointer to something in the first four arguments, just + declare it as a pointer, not u32. On the other side, + arguments from 5th onwards should be declared as u32 + for pointers, and need AA() around each usage. + A() macro should be used for places where you e.g. + have some internal variable u32 and just want to get + rid of a compiler warning. AA() has to be used in + places where you want to convert a function argument + to 32bit pointer or when you e.g. access pt_regs + structure and want to consider 32bit registers only. + -jj */ -#define A(x) ((unsigned long)x) - +#define A(__x) ((unsigned long)(__x)) +#define AA(__x) \ +({ unsigned long __ret; \ + __asm__ ("srl %0, 0, %0" \ + : "=r" (__ret) \ + : "0" (__x)); \ + __ret; \ +}) + static inline char * get_page(void) { char * res; @@ -73,12 +89,12 @@ static inline char * get_page(void) * * POSIX.1 2.4: an empty pathname is invalid (ENOENT). */ -static inline int do_getname32(u32 filename, char *page) +static inline int do_getname32(const char *filename, char *page) { int retval; /* 32bit pointer will be always far below TASK_SIZE :)) */ - retval = strncpy_from_user((char *)page, (char *)A(filename), PAGE_SIZE); + retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE); if (retval > 0) { if (retval < PAGE_SIZE) return 0; @@ -88,7 +104,7 @@ static inline int do_getname32(u32 filename, char *page) return retval; } -char * getname32(u32 filename) +char * getname32(const char *filename) { char *tmp, *result; @@ -208,9 +224,6 @@ struct shmid_ds32 { __kernel_ipc_pid_t32 shm_cpid; __kernel_ipc_pid_t32 shm_lpid; unsigned short shm_nattch; - unsigned short shm_npages; - u32 shm_pages; - u32 attaches; }; /* @@ -218,6 +231,261 @@ struct shmid_ds32 { * * This is really horribly ugly. */ +#define IPCOP_MASK(__x) (1UL << (__x)) +static int do_sys32_semctl(int first, int second, int third, void *uptr) +{ + union semun fourth; + u32 pad; + int err = -EINVAL; + + if (!uptr) + goto out; + err = -EFAULT; + if (get_user (pad, (u32 *)uptr)) + goto out; + fourth.__pad = (void *)A(pad); + if (IPCOP_MASK (third) & + (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | IPCOP_MASK (GETVAL) | + IPCOP_MASK (GETPID) | IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) | + IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) | IPCOP_MASK (IPC_RMID))) { + err = sys_semctl (first, second, third, fourth); + } else { + struct semid_ds s; + struct semid_ds32 *usp = (struct semid_ds32 *)A(pad); + mm_segment_t old_fs; + int need_back_translation; + + if (third == IPC_SET) { + err = get_user (s.sem_perm.uid, &usp->sem_perm.uid); + err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid); + err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode); + if (err) + goto out; + fourth.__pad = &s; + } + need_back_translation = + (IPCOP_MASK (third) & + (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0; + if (need_back_translation) + fourth.__pad = &s; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_semctl (first, second, third, fourth); + set_fs (old_fs); + if (need_back_translation) { + int err2 = put_user (s.sem_perm.key, &usp->sem_perm.key); + err2 |= __put_user (s.sem_perm.uid, &usp->sem_perm.uid); + err2 |= __put_user (s.sem_perm.gid, &usp->sem_perm.gid); + err2 |= __put_user (s.sem_perm.cuid, &usp->sem_perm.cuid); + err2 |= __put_user (s.sem_perm.cgid, &usp->sem_perm.cgid); + err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode); + err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); + err2 |= __put_user (s.sem_otime, &usp->sem_otime); + err2 |= __put_user (s.sem_ctime, &usp->sem_ctime); + err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); + if (err2) err = -EFAULT; + } + } +out: + return err; +} + +static int do_sys32_msgsnd (int first, int second, int third, void *uptr) +{ + struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); + struct msgbuf32 *up = (struct msgbuf32 *)uptr; + mm_segment_t old_fs; + int err; + + if (!p) + return -ENOMEM; + err = get_user (p->mtype, &up->mtype); + err |= __copy_from_user (p->mtext, &up->mtext, second); + if (err) + goto out; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgsnd (first, p, second, third); + set_fs (old_fs); +out: + kfree (p); + return err; +} + +static int do_sys32_msgrcv (int first, int second, int msgtyp, int third, + int version, void *uptr) +{ + struct msgbuf32 *up; + struct msgbuf *p; + mm_segment_t old_fs; + int err; + + if (!version) { + struct ipc_kludge *uipck = (struct ipc_kludge *)uptr; + struct ipc_kludge ipck; + + err = -EINVAL; + if (!uptr) + goto out; + err = -EFAULT; + if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge))) + goto out; + uptr = (void *)A(ipck.msgp); + msgtyp = ipck.msgtyp; + } + err = -ENOMEM; + p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); + if (!p) + goto out; + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgrcv (first, p, second + 4, msgtyp, third); + set_fs (old_fs); + if (err < 0) + goto free_then_out; + up = (struct msgbuf32 *)uptr; + if (put_user (p->mtype, &up->mtype) || + __copy_to_user (&up->mtext, p->mtext, err)) + err = -EFAULT; +free_then_out: + kfree (p); +out: + return err; +} + +static int do_sys32_msgctl (int first, int second, void *uptr) +{ + int err; + + if (IPCOP_MASK (second) & + (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (MSG_INFO) | + IPCOP_MASK (IPC_RMID))) { + err = sys_msgctl (first, second, (struct msqid_ds *)uptr); + } else { + struct msqid_ds m; + struct msqid_ds32 *up = (struct msqid_ds32 *)uptr; + mm_segment_t old_fs; + + if (second == IPC_SET) { + err = get_user (m.msg_perm.uid, &up->msg_perm.uid); + err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid); + err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode); + err |= __get_user (m.msg_qbytes, &up->msg_qbytes); + if (err) + goto out; + } + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_msgctl (first, second, &m); + set_fs (old_fs); + if (IPCOP_MASK (second) & + (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) { + int err2 = put_user (m.msg_perm.key, &up->msg_perm.key); + err2 |= __put_user (m.msg_perm.uid, &up->msg_perm.uid); + err2 |= __put_user (m.msg_perm.gid, &up->msg_perm.gid); + err2 |= __put_user (m.msg_perm.cuid, &up->msg_perm.cuid); + err2 |= __put_user (m.msg_perm.cgid, &up->msg_perm.cgid); + err2 |= __put_user (m.msg_perm.mode, &up->msg_perm.mode); + err2 |= __put_user (m.msg_perm.seq, &up->msg_perm.seq); + err2 |= __put_user (m.msg_stime, &up->msg_stime); + err2 |= __put_user (m.msg_rtime, &up->msg_rtime); + err2 |= __put_user (m.msg_ctime, &up->msg_ctime); + err2 |= __put_user (m.msg_cbytes, &up->msg_cbytes); + err2 |= __put_user (m.msg_qnum, &up->msg_qnum); + err2 |= __put_user (m.msg_qbytes, &up->msg_qbytes); + err2 |= __put_user (m.msg_lspid, &up->msg_lspid); + err2 |= __put_user (m.msg_lrpid, &up->msg_lrpid); + if (err2) + err = -EFAULT; + } + } + +out: + return err; +} + +static int do_sys32_shmat (int first, int second, int third, int version, void *uptr) +{ + unsigned long raddr; + u32 *uaddr = (u32 *)A((u32)third); + int err = -EINVAL; + + if (version == 1) + goto out; + err = sys_shmat (first, uptr, second, &raddr); + if (err) + goto out; + err = put_user (raddr, uaddr); +out: + return err; +} + +static int do_sys32_shmctl (int first, int second, void *uptr) +{ + int err; + + if (IPCOP_MASK (second) & + (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SHM_LOCK) | IPCOP_MASK (SHM_UNLOCK) | + IPCOP_MASK (IPC_RMID))) { + err = sys_shmctl (first, second, (struct shmid_ds *)uptr); + } else { + struct shmid_ds s; + struct shmid_ds32 *up = (struct shmid_ds32 *)uptr; + mm_segment_t old_fs; + + if (second == IPC_SET) { + err = get_user (s.shm_perm.uid, &up->shm_perm.uid); + err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); + err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode); + if (err) + goto out; + } + old_fs = get_fs (); + set_fs (KERNEL_DS); + err = sys_shmctl (first, second, &s); + set_fs (old_fs); + if (err < 0) + goto out; + + /* Mask it even in this case so it becomes a CSE. */ + if (second == SHM_INFO) { + struct shm_info32 { + int used_ids; + u32 shm_tot, shm_rss, shm_swp; + u32 swap_attempts, swap_successes; + } *uip = (struct shm_info32 *)uptr; + struct shm_info *kp = (struct shm_info *)&s; + int err2 = put_user (kp->used_ids, &uip->used_ids); + err2 |= __put_user (kp->shm_tot, &uip->shm_tot); + err2 |= __put_user (kp->shm_rss, &uip->shm_rss); + err2 |= __put_user (kp->shm_swp, &uip->shm_swp); + err2 |= __put_user (kp->swap_attempts, &uip->swap_attempts); + err2 |= __put_user (kp->swap_successes, &uip->swap_successes); + if (err2) + err = -EFAULT; + } else if (IPCOP_MASK (second) & + (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) { + int err2 = put_user (s.shm_perm.key, &up->shm_perm.key); + err2 |= __put_user (s.shm_perm.uid, &up->shm_perm.uid); + err2 |= __put_user (s.shm_perm.gid, &up->shm_perm.gid); + err2 |= __put_user (s.shm_perm.cuid, &up->shm_perm.cuid); + err2 |= __put_user (s.shm_perm.cgid, &up->shm_perm.cgid); + err2 |= __put_user (s.shm_perm.mode, &up->shm_perm.mode); + err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq); + err2 |= __put_user (s.shm_atime, &up->shm_atime); + err2 |= __put_user (s.shm_dtime, &up->shm_dtime); + err2 |= __put_user (s.shm_ctime, &up->shm_ctime); + err2 |= __put_user (s.shm_segsz, &up->shm_segsz); + err2 |= __put_user (s.shm_nattch, &up->shm_nattch); + err2 |= __put_user (s.shm_cpid, &up->shm_cpid); + err2 |= __put_user (s.shm_lpid, &up->shm_lpid); + if (err2) + err = -EFAULT; + } + } +out: + return err; +} asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) { @@ -231,190 +499,32 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u switch (call) { case SEMOP: /* struct sembuf is the same on 32 and 64bit :)) */ - err = sys_semop (first, (struct sembuf *)A(ptr), second); + err = sys_semop (first, (struct sembuf *)AA(ptr), second); goto out; case SEMGET: err = sys_semget (first, second, third); goto out; - case SEMCTL: { - union semun fourth; - void *pad; - mm_segment_t old_fs; - struct semid_ds s; - - err = -EINVAL; - if (!ptr) - goto out; - err = -EFAULT; - if(get_user(pad, (void **)A(ptr))) - goto out; - fourth.__pad = pad; - switch (third) { - case IPC_INFO: - case SEM_INFO: - case GETVAL: - case GETPID: - case GETNCNT: - case GETZCNT: - case GETALL: - case SETALL: - case IPC_RMID: - err = sys_semctl (first, second, third, fourth); - goto out; - case IPC_SET: - if (get_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) || - __get_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) || - __get_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode))) { - err = -EFAULT; - goto out; - } - /* Fall through */ - case SEM_STAT: - case IPC_STAT: - fourth.__pad = &s; - break; - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_semctl (first, second, third, fourth); - set_fs (old_fs); - switch (third) { - case SEM_STAT: - case IPC_STAT: - if (put_user (s.sem_perm.key, &(((struct semid_ds32 *)A(pad))->sem_perm.key)) || - __put_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) || - __put_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) || - __put_user (s.sem_perm.cuid, &(((struct semid_ds32 *)A(pad))->sem_perm.cuid)) || - __put_user (s.sem_perm.cgid, &(((struct semid_ds32 *)A(pad))->sem_perm.cgid)) || - __put_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode)) || - __put_user (s.sem_perm.seq, &(((struct semid_ds32 *)A(pad))->sem_perm.seq)) || - __put_user (s.sem_otime, &(((struct semid_ds32 *)A(pad))->sem_otime)) || - __put_user (s.sem_ctime, &(((struct semid_ds32 *)A(pad))->sem_ctime)) || - __put_user (s.sem_nsems, &(((struct semid_ds32 *)A(pad))->sem_nsems))) - err = -EFAULT; - } + case SEMCTL: + err = do_sys32_semctl (first, second, third, (void *)AA(ptr)); goto out; - } default: err = -EINVAL; goto out; - } + }; if (call <= MSGCTL) switch (call) { case MSGSND: - { - struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL); - - if (!p) err = -ENOMEM; - else { - err = 0; - if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) || - __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second)) - err = -EFAULT; - if (!err) { - mm_segment_t old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_msgsnd (first, p, second, third); - set_fs (old_fs); - } - kfree (p); - } - } + err = do_sys32_msgsnd (first, second, third, (void *)AA(ptr)); goto out; case MSGRCV: - { - struct msgbuf *p; - mm_segment_t old_fs; - long msgtyp = fifth; - - if (!version) { - struct ipc_kludge tmp; - err = -EINVAL; - if (!ptr) - goto out; - err = -EFAULT; - if(copy_from_user(&tmp,(struct ipc_kludge *)A(ptr), sizeof (tmp))) - goto out; - ptr = tmp.msgp; - msgtyp = tmp.msgtyp; - } - - p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL); - if (!p) { - err = -EFAULT; - goto out; - } - - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_msgrcv (first, p, second + 4, msgtyp, third); - set_fs (old_fs); - - if (err < 0) - goto out; - - if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) || - __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err)) - err = -EFAULT; - kfree (p); - goto out; - } + err = do_sys32_msgrcv (first, second, fifth, third, + version, (void *)AA(ptr)); + goto out; case MSGGET: err = sys_msgget ((key_t) first, second); goto out; case MSGCTL: - { - struct msqid_ds m; - mm_segment_t old_fs; - - switch (second) { - case IPC_INFO: - case MSG_INFO: - /* struct msginfo is the same */ - case IPC_RMID: - /* and this doesn't care about ptr */ - err = sys_msgctl (first, second, (struct msqid_ds *)A(ptr)); - goto out; - - case IPC_SET: - if (get_user (m.msg_perm.uid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.uid)) || - __get_user (m.msg_perm.gid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.gid)) || - __get_user (m.msg_perm.mode, &(((struct msqid_ds32 *)A(ptr))->msg_perm.mode)) || - __get_user (m.msg_qbytes, &(((struct msqid_ds32 *)A(ptr))->msg_qbytes))) { - err = -EFAULT; - goto out; - } - default: - break; - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_msgctl (first, second, &m); - set_fs (old_fs); - switch (second) { - case MSG_STAT: - case IPC_STAT: - if (put_user (m.msg_perm.key, &(((struct msqid_ds32 *)A(ptr))->msg_perm.key)) || - __put_user (m.msg_perm.uid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.uid)) || - __put_user (m.msg_perm.gid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.gid)) || - __put_user (m.msg_perm.cuid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.cuid)) || - __put_user (m.msg_perm.cgid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.cgid)) || - __put_user (m.msg_perm.mode, &(((struct msqid_ds32 *)A(ptr))->msg_perm.mode)) || - __put_user (m.msg_perm.seq, &(((struct msqid_ds32 *)A(ptr))->msg_perm.seq)) || - __put_user (m.msg_stime, &(((struct msqid_ds32 *)A(ptr))->msg_stime)) || - __put_user (m.msg_rtime, &(((struct msqid_ds32 *)A(ptr))->msg_rtime)) || - __put_user (m.msg_ctime, &(((struct msqid_ds32 *)A(ptr))->msg_ctime)) || - __put_user (m.msg_cbytes, &(((struct msqid_ds32 *)A(ptr))->msg_cbytes)) || - __put_user (m.msg_qnum, &(((struct msqid_ds32 *)A(ptr))->msg_qnum)) || - __put_user (m.msg_qbytes, &(((struct msqid_ds32 *)A(ptr))->msg_qbytes)) || - __put_user (m.msg_lspid, &(((struct msqid_ds32 *)A(ptr))->msg_lspid)) || - __put_user (m.msg_lrpid, &(((struct msqid_ds32 *)A(ptr))->msg_lrpid))) - err = -EFAULT; - break; - default: - break; - } - } + err = do_sys32_msgctl (first, second, (void *)AA(ptr)); goto out; default: err = -EINVAL; @@ -423,95 +533,17 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u if (call <= SHMCTL) switch (call) { case SHMAT: - switch (version) { - case 0: default: { - unsigned long raddr; - u32 *uptr = (u32 *) A(((u32)third)); - err = sys_shmat (first, (char *)A(ptr), second, &raddr); - if (err) - goto out; - err = -EFAULT; - if(put_user (raddr, uptr)) - goto out; - err = 0; - goto out; - } - case 1: /* If iBCS2 should ever run, then for sure in 64bit mode, not 32bit... */ - err = -EINVAL; - goto out; - } + err = do_sys32_shmat (first, second, third, + version, (void *)AA(ptr)); + goto out; case SHMDT: - err = sys_shmdt ((char *)A(ptr)); + err = sys_shmdt ((char *)AA(ptr)); goto out; case SHMGET: err = sys_shmget (first, second, third); goto out; case SHMCTL: - { - struct shmid_ds s; - mm_segment_t old_fs; - - switch (second) { - case IPC_INFO: - /* struct shminfo is the same */ - case SHM_LOCK: - case SHM_UNLOCK: - case IPC_RMID: - /* and these three aren't using ptr at all */ - err = sys_shmctl (first, second, (struct shmid_ds *)A(ptr)); - goto out; - - case IPC_SET: - if (get_user (s.shm_perm.uid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.uid)) || - __get_user (s.shm_perm.gid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.gid)) || - __get_user (s.shm_perm.mode, &(((struct shmid_ds32 *)A(ptr))->shm_perm.mode))) { - err = -EFAULT; - goto out; - } - default: - break; - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_shmctl (first, second, &s); - set_fs (old_fs); - switch (second) { - case SHM_INFO: - { - struct shm_info32 { int used_ids; u32 shm_tot; u32 shm_rss; u32 shm_swp; u32 swap_attempts; u32 swap_successes; }; - struct shm_info *si = (struct shm_info *)&s; - - if (put_user (si->used_ids, &(((struct shm_info32 *)A(ptr))->used_ids)) || - __put_user (si->shm_tot, &(((struct shm_info32 *)A(ptr))->shm_tot)) || - __put_user (si->shm_rss, &(((struct shm_info32 *)A(ptr))->shm_rss)) || - __put_user (si->shm_swp, &(((struct shm_info32 *)A(ptr))->shm_swp)) || - __put_user (si->swap_attempts, &(((struct shm_info32 *)A(ptr))->swap_attempts)) || - __put_user (si->swap_successes, &(((struct shm_info32 *)A(ptr))->swap_successes))) - err = -EFAULT; - } - break; - case SHM_STAT: - case IPC_STAT: - if (put_user (s.shm_perm.key, &(((struct shmid_ds32 *)A(ptr))->shm_perm.key)) || - __put_user (s.shm_perm.uid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.uid)) || - __put_user (s.shm_perm.gid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.gid)) || - __put_user (s.shm_perm.cuid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.cuid)) || - __put_user (s.shm_perm.cgid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.cgid)) || - __put_user (s.shm_perm.mode, &(((struct shmid_ds32 *)A(ptr))->shm_perm.mode)) || - __put_user (s.shm_perm.seq, &(((struct shmid_ds32 *)A(ptr))->shm_perm.seq)) || - __put_user (s.shm_atime, &(((struct shmid_ds32 *)A(ptr))->shm_atime)) || - __put_user (s.shm_dtime, &(((struct shmid_ds32 *)A(ptr))->shm_dtime)) || - __put_user (s.shm_ctime, &(((struct shmid_ds32 *)A(ptr))->shm_ctime)) || - __put_user (s.shm_segsz, &(((struct shmid_ds32 *)A(ptr))->shm_segsz)) || - __put_user (s.shm_nattch, &(((struct shmid_ds32 *)A(ptr))->shm_nattch)) || - __put_user (s.shm_lpid, &(((struct shmid_ds32 *)A(ptr))->shm_cpid)) || - __put_user (s.shm_cpid, &(((struct shmid_ds32 *)A(ptr))->shm_lpid))) - err = -EFAULT; - break; - default: - break; - } - } + err = do_sys32_shmctl (first, second, (void *)AA(ptr)); goto out; default: err = -EINVAL; @@ -527,29 +559,31 @@ out: static inline int get_flock(struct flock *kfl, struct flock32 *ufl) { - if(get_user(kfl->l_type, &ufl->l_type) || - __get_user(kfl->l_whence, &ufl->l_whence) || - __get_user(kfl->l_start, &ufl->l_start) || - __get_user(kfl->l_len, &ufl->l_len) || - __get_user(kfl->l_pid, &ufl->l_pid)) - return -EFAULT; - return 0; + int err; + + err = get_user(kfl->l_type, &ufl->l_type); + err |= __get_user(kfl->l_whence, &ufl->l_whence); + err |= __get_user(kfl->l_start, &ufl->l_start); + err |= __get_user(kfl->l_len, &ufl->l_len); + err |= __get_user(kfl->l_pid, &ufl->l_pid); + return err; } static inline int put_flock(struct flock *kfl, struct flock32 *ufl) { - if(__put_user(kfl->l_type, &ufl->l_type) || - __put_user(kfl->l_whence, &ufl->l_whence) || - __put_user(kfl->l_start, &ufl->l_start) || - __put_user(kfl->l_len, &ufl->l_len) || - __put_user(kfl->l_pid, &ufl->l_pid)) - return -EFAULT; - return 0; + int err; + + err = __put_user(kfl->l_type, &ufl->l_type); + err |= __put_user(kfl->l_whence, &ufl->l_whence); + err |= __put_user(kfl->l_start, &ufl->l_start); + err |= __put_user(kfl->l_len, &ufl->l_len); + err |= __put_user(kfl->l_pid, &ufl->l_pid); + return err; } extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); -asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg) +asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) { switch (cmd) { case F_GETLK: @@ -560,12 +594,12 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg) mm_segment_t old_fs; long ret; - if(get_flock(&f, (struct flock32 *)A(arg))) + if(get_flock(&f, (struct flock32 *)arg)) return -EFAULT; old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs (old_fs); - if(put_flock(&f, (struct flock32 *)A(arg))) + if(put_flock(&f, (struct flock32 *)arg)) return -EFAULT; return ret; } @@ -587,7 +621,7 @@ struct dqblk32 { extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr); -asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) +asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr) { int cmds = cmd >> SUBCMDSHIFT; int err; @@ -601,29 +635,29 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) case Q_SETQUOTA: case Q_SETUSE: case Q_SETQLIM: - if (copy_from_user (&d, (struct dqblk32 *)A(addr), + if (copy_from_user (&d, (struct dqblk32 *)addr, sizeof (struct dqblk32))) return -EFAULT; d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime; d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime; break; default: - return sys_quotactl(cmd, (const char *)A(special), - id, (caddr_t)A(addr)); + return sys_quotactl(cmd, special, + id, (caddr_t)addr); } spec = getname32 (special); err = PTR_ERR(spec); if (IS_ERR(spec)) return err; old_fs = get_fs (); set_fs (KERNEL_DS); - err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr)); + err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d); set_fs (old_fs); putname32 (spec); if (cmds == Q_GETQUOTA) { __kernel_time_t b = d.dqb_btime, i = d.dqb_itime; ((struct dqblk32 *)&d)->dqb_itime = i; ((struct dqblk32 *)&d)->dqb_btime = b; - if (copy_to_user ((struct dqblk32 *)A(addr), &d, + if (copy_to_user ((struct dqblk32 *)addr, &d, sizeof (struct dqblk32))) return -EFAULT; } @@ -632,23 +666,24 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { - if (put_user (kbuf->f_type, &ubuf->f_type) || - __put_user (kbuf->f_bsize, &ubuf->f_bsize) || - __put_user (kbuf->f_blocks, &ubuf->f_blocks) || - __put_user (kbuf->f_bfree, &ubuf->f_bfree) || - __put_user (kbuf->f_bavail, &ubuf->f_bavail) || - __put_user (kbuf->f_files, &ubuf->f_files) || - __put_user (kbuf->f_ffree, &ubuf->f_ffree) || - __put_user (kbuf->f_namelen, &ubuf->f_namelen) || - __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || - __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1])) - return -EFAULT; - return 0; + int err; + + err = put_user (kbuf->f_type, &ubuf->f_type); + err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize); + err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks); + err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree); + err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail); + err |= __put_user (kbuf->f_files, &ubuf->f_files); + err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree); + err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen); + err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]); + err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]); + return err; } extern asmlinkage int sys_statfs(const char * path, struct statfs * buf); -asmlinkage int sys32_statfs(u32 path, u32 buf) +asmlinkage int sys32_statfs(const char * path, struct statfs32 *buf) { int ret; struct statfs s; @@ -662,7 +697,7 @@ asmlinkage int sys32_statfs(u32 path, u32 buf) ret = sys_statfs((const char *)pth, &s); set_fs (old_fs); putname32 (pth); - if (put_statfs((struct statfs32 *)A(buf), &s)) + if (put_statfs(buf, &s)) return -EFAULT; } return ret; @@ -670,7 +705,7 @@ asmlinkage int sys32_statfs(u32 path, u32 buf) extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf); -asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf) +asmlinkage int sys32_fstatfs(unsigned int fd, struct statfs32 *buf) { int ret; struct statfs s; @@ -679,25 +714,28 @@ asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf) set_fs (KERNEL_DS); ret = sys_fstatfs(fd, &s); set_fs (old_fs); - if (put_statfs((struct statfs32 *)A(buf), &s)) + if (put_statfs(buf, &s)) return -EFAULT; return ret; } extern asmlinkage int sys_utime(char * filename, struct utimbuf * times); -asmlinkage int sys32_utime(u32 filename, u32 times) +struct utimbuf32 { + __kernel_time_t32 actime, modtime; +}; + +asmlinkage int sys32_utime(char * filename, struct utimbuf32 *times) { - struct utimbuf32 { __kernel_time_t32 actime, modtime; }; struct utimbuf t; mm_segment_t old_fs; int ret; char *filenam; if (!times) - return sys_utime((char *)A(filename), NULL); - if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) || - __get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime))) + return sys_utime(filename, NULL); + if (get_user (t.actime, ×->actime) || + __get_user (t.modtime, ×->modtime)) return -EFAULT; filenam = getname32 (filename); ret = PTR_ERR(filenam); @@ -813,7 +851,7 @@ static long do_readv_writev32(int type, struct file *file, return retval; } -asmlinkage long sys32_readv(int fd, u32 vector, u32 count) +asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count) { struct file *file; long ret = -EBADF; @@ -827,7 +865,7 @@ asmlinkage long sys32_readv(int fd, u32 vector, u32 count) goto out; ret = do_readv_writev32(VERIFY_WRITE, file, - (struct iovec32 *)A(vector), count); + vector, count); out: fput(file); bad_file: @@ -835,7 +873,7 @@ bad_file: return ret; } -asmlinkage long sys32_writev(int fd, u32 vector, u32 count) +asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count) { struct file *file; int ret = -EBADF; @@ -850,7 +888,7 @@ asmlinkage long sys32_writev(int fd, u32 vector, u32 count) down(&file->f_dentry->d_inode->i_sem); ret = do_readv_writev32(VERIFY_READ, file, - (struct iovec32 *)A(vector), count); + vector, count); up(&file->f_dentry->d_inode->i_sem); out: fput(file); @@ -894,7 +932,7 @@ static int fillonedir(void * __buf, const char * name, int namlen, return 0; } -asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count) +asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count) { int error = -EBADF; struct file * file; @@ -907,7 +945,7 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count) goto out; buf.count = 0; - buf.dirent = (struct old_linux_dirent32 *)A(dirent); + buf.dirent = dirent; error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) @@ -966,7 +1004,7 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in return 0; } -asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) +asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count) { struct file * file; struct inode * inode; @@ -979,7 +1017,7 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) if (!file) goto out; - buf.current_dir = (struct linux_dirent32 *) A(dirent); + buf.current_dir = dirent; buf.previous = NULL; buf.count = count; buf.error = 0; @@ -1015,10 +1053,8 @@ out: */ static inline int -get_fd_set32(unsigned long n, unsigned long *fdset, u32 ufdset_x) +get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset) { - u32 *ufdset = (u32 *)A(ufdset_x); - if (ufdset) { unsigned long odd; @@ -1048,10 +1084,9 @@ get_fd_set32(unsigned long n, unsigned long *fdset, u32 ufdset_x) } static inline void -set_fd_set32(unsigned long n, u32 ufdset_x, unsigned long *fdset) +set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset) { unsigned long odd; - u32 *ufdset = (u32 *)A(ufdset_x); if (!ufdset) return; @@ -1071,14 +1106,15 @@ set_fd_set32(unsigned long n, u32 ufdset_x, unsigned long *fdset) __put_user(*fdset, ufdset); } -asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x) +asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x) { fd_set_buffer *fds; - struct timeval32 *tvp = (struct timeval32 *)A(tvp_x); - unsigned long timeout, nn; + struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x); + unsigned long nn; + long timeout; int ret; - timeout = ~0UL; + timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { time_t sec, usec; @@ -1089,8 +1125,6 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x) timeout = (usec + 1000000/HZ - 1) / (1000000/HZ); timeout += sec * HZ; - if (timeout) - timeout += jiffies + 1; } ret = -ENOMEM; @@ -1112,12 +1146,11 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x) zero_fd_set(n, fds->res_out); zero_fd_set(n, fds->res_ex); - ret = do_select(n, fds, timeout); + ret = do_select(n, fds, &timeout); if (tvp && !(current->personality & STICKY_TIMEOUTS)) { - unsigned long timeout = current->timeout - jiffies - 1; time_t sec = 0, usec = 0; - if ((long) timeout > 0) { + if (timeout) { sec = timeout / HZ; usec = timeout % HZ; usec *= (1000000/HZ); @@ -1125,7 +1158,6 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x) put_user(sec, &tvp->tv_sec); put_user(usec, &tvp->tv_usec); } - current->timeout = 0; if (ret < 0) goto out; @@ -1148,26 +1180,27 @@ out_nofds: static inline int putstat(struct stat32 *ubuf, struct stat *kbuf) { - if (put_user (kbuf->st_dev, &ubuf->st_dev) || - __put_user (kbuf->st_ino, &ubuf->st_ino) || - __put_user (kbuf->st_mode, &ubuf->st_mode) || - __put_user (kbuf->st_nlink, &ubuf->st_nlink) || - __put_user (kbuf->st_uid, &ubuf->st_uid) || - __put_user (kbuf->st_gid, &ubuf->st_gid) || - __put_user (kbuf->st_rdev, &ubuf->st_rdev) || - __put_user (kbuf->st_size, &ubuf->st_size) || - __put_user (kbuf->st_atime, &ubuf->st_atime) || - __put_user (kbuf->st_mtime, &ubuf->st_mtime) || - __put_user (kbuf->st_ctime, &ubuf->st_ctime) || - __put_user (kbuf->st_blksize, &ubuf->st_blksize) || - __put_user (kbuf->st_blocks, &ubuf->st_blocks)) - return -EFAULT; - return 0; + int err; + + err = put_user (kbuf->st_dev, &ubuf->st_dev); + err |= __put_user (kbuf->st_ino, &ubuf->st_ino); + err |= __put_user (kbuf->st_mode, &ubuf->st_mode); + err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink); + err |= __put_user (kbuf->st_uid, &ubuf->st_uid); + err |= __put_user (kbuf->st_gid, &ubuf->st_gid); + err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev); + err |= __put_user (kbuf->st_size, &ubuf->st_size); + err |= __put_user (kbuf->st_atime, &ubuf->st_atime); + err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime); + err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime); + err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize); + err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks); + return err; } extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf); -asmlinkage int sys32_newstat(u32 filename, u32 statbuf) +asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf) { int ret; struct stat s; @@ -1181,7 +1214,7 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf) ret = sys_newstat(filenam, &s); set_fs (old_fs); putname32 (filenam); - if (putstat ((struct stat32 *)A(statbuf), &s)) + if (putstat (statbuf, &s)) return -EFAULT; } return ret; @@ -1189,7 +1222,7 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf) extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf); -asmlinkage int sys32_newlstat(u32 filename, u32 statbuf) +asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf) { int ret; struct stat s; @@ -1203,7 +1236,7 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf) ret = sys_newlstat(filenam, &s); set_fs (old_fs); putname32 (filenam); - if (putstat ((struct stat32 *)A(statbuf), &s)) + if (putstat (statbuf, &s)) return -EFAULT; } return ret; @@ -1211,7 +1244,7 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf) extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf); -asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) +asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf) { int ret; struct stat s; @@ -1220,7 +1253,7 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) set_fs (KERNEL_DS); ret = sys_newfstat(fd, &s); set_fs (old_fs); - if (putstat ((struct stat32 *)A(statbuf), &s)) + if (putstat (statbuf, &s)) return -EFAULT; return ret; } @@ -1318,7 +1351,7 @@ extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, #define SMBFS_NAME "smbfs" #define NCPFS_NAME "ncpfs" -asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data) +asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data) { unsigned long type_page; int err, is_smb, is_ncp; @@ -1326,7 +1359,7 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, if(!capable(CAP_SYS_ADMIN)) return -EPERM; is_smb = is_ncp = 0; - err = copy_mount_stuff_to_kernel((const void *)A(type), &type_page); + err = copy_mount_stuff_to_kernel((const void *)type, &type_page); if(err) return err; if(type_page) { @@ -1336,20 +1369,18 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, if(!is_smb && !is_ncp) { if(type_page) free_page(type_page); - return sys_mount((char *)A(dev_name), (char *)A(dir_name), - (char *)A(type), (unsigned long)new_flags, - (void *)A(data)); + return sys_mount(dev_name, dir_name, type, new_flags, (void *)AA(data)); } else { unsigned long dev_page, dir_page, data_page; mm_segment_t old_fs; - err = copy_mount_stuff_to_kernel((const void *)A(dev_name), &dev_page); + err = copy_mount_stuff_to_kernel((const void *)dev_name, &dev_page); if(err) goto out; - err = copy_mount_stuff_to_kernel((const void *)A(dir_name), &dir_page); + err = copy_mount_stuff_to_kernel((const void *)dir_name, &dir_page); if(err) goto dev_out; - err = copy_mount_stuff_to_kernel((const void *)A(data), &data_page); + err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page); if(err) goto dir_out; if(is_ncp) @@ -1357,11 +1388,11 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, else if(is_smb) do_smb_super_data_conv((void *)data_page); else - panic("Tell DaveM he fucked up..."); + panic("The problem is here..."); old_fs = get_fs(); set_fs(KERNEL_DS); err = sys_mount((char *)dev_page, (char *)dir_page, - (char *)type_page, (unsigned long)new_flags, + (char *)type_page, new_flags, (void *)data_page); set_fs(old_fs); @@ -1399,37 +1430,38 @@ struct rusage32 { s32 ru_nivcsw; }; -static int put_rusage (u32 ru, struct rusage *r) -{ - if (put_user (r->ru_utime.tv_sec, &(((struct rusage32 *)A(ru))->ru_utime.tv_sec)) || - __put_user (r->ru_utime.tv_usec, &(((struct rusage32 *)A(ru))->ru_utime.tv_usec)) || - __put_user (r->ru_stime.tv_sec, &(((struct rusage32 *)A(ru))->ru_stime.tv_sec)) || - __put_user (r->ru_stime.tv_usec, &(((struct rusage32 *)A(ru))->ru_stime.tv_usec)) || - __put_user (r->ru_maxrss, &(((struct rusage32 *)A(ru))->ru_maxrss)) || - __put_user (r->ru_ixrss, &(((struct rusage32 *)A(ru))->ru_ixrss)) || - __put_user (r->ru_idrss, &(((struct rusage32 *)A(ru))->ru_idrss)) || - __put_user (r->ru_isrss, &(((struct rusage32 *)A(ru))->ru_isrss)) || - __put_user (r->ru_minflt, &(((struct rusage32 *)A(ru))->ru_minflt)) || - __put_user (r->ru_majflt, &(((struct rusage32 *)A(ru))->ru_majflt)) || - __put_user (r->ru_nswap, &(((struct rusage32 *)A(ru))->ru_nswap)) || - __put_user (r->ru_inblock, &(((struct rusage32 *)A(ru))->ru_inblock)) || - __put_user (r->ru_oublock, &(((struct rusage32 *)A(ru))->ru_oublock)) || - __put_user (r->ru_msgsnd, &(((struct rusage32 *)A(ru))->ru_msgsnd)) || - __put_user (r->ru_msgrcv, &(((struct rusage32 *)A(ru))->ru_msgrcv)) || - __put_user (r->ru_nsignals, &(((struct rusage32 *)A(ru))->ru_nsignals)) || - __put_user (r->ru_nvcsw, &(((struct rusage32 *)A(ru))->ru_nvcsw)) || - __put_user (r->ru_nivcsw, &(((struct rusage32 *)A(ru))->ru_nivcsw))) - return -EFAULT; - return 0; +static int put_rusage (struct rusage32 *ru, struct rusage *r) +{ + int err; + + err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec); + err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec); + err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec); + err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec); + err |= __put_user (r->ru_maxrss, &ru->ru_maxrss); + err |= __put_user (r->ru_ixrss, &ru->ru_ixrss); + err |= __put_user (r->ru_idrss, &ru->ru_idrss); + err |= __put_user (r->ru_isrss, &ru->ru_isrss); + err |= __put_user (r->ru_minflt, &ru->ru_minflt); + err |= __put_user (r->ru_majflt, &ru->ru_majflt); + err |= __put_user (r->ru_nswap, &ru->ru_nswap); + err |= __put_user (r->ru_inblock, &ru->ru_inblock); + err |= __put_user (r->ru_oublock, &ru->ru_oublock); + err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd); + err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv); + err |= __put_user (r->ru_nsignals, &ru->ru_nsignals); + err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw); + err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw); + return err; } extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); -asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru) +asmlinkage int sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, struct rusage32 *ru) { if (!ru) - return sys_wait4(pid, (unsigned int *)A(stat_addr), options, NULL); + return sys_wait4(pid, stat_addr, options, NULL); else { struct rusage r; int ret; @@ -1440,7 +1472,7 @@ asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); set_fs (old_fs); if (put_rusage (ru, &r)) return -EFAULT; - if (stat_addr && put_user (status, (unsigned int *)A(stat_addr))) + if (stat_addr && put_user (status, stat_addr)) return -EFAULT; return ret; } @@ -1461,26 +1493,27 @@ struct sysinfo32 { extern asmlinkage int sys_sysinfo(struct sysinfo *info); -asmlinkage int sys32_sysinfo(u32 info) +asmlinkage int sys32_sysinfo(struct sysinfo32 *info) { struct sysinfo s; - int ret; + int ret, err; mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_sysinfo(&s); set_fs (old_fs); - if (put_user (s.uptime, &(((struct sysinfo32 *)A(info))->uptime)) || - __put_user (s.loads[0], &(((struct sysinfo32 *)A(info))->loads[0])) || - __put_user (s.loads[1], &(((struct sysinfo32 *)A(info))->loads[1])) || - __put_user (s.loads[2], &(((struct sysinfo32 *)A(info))->loads[2])) || - __put_user (s.totalram, &(((struct sysinfo32 *)A(info))->totalram)) || - __put_user (s.freeram, &(((struct sysinfo32 *)A(info))->freeram)) || - __put_user (s.sharedram, &(((struct sysinfo32 *)A(info))->sharedram)) || - __put_user (s.bufferram, &(((struct sysinfo32 *)A(info))->bufferram)) || - __put_user (s.totalswap, &(((struct sysinfo32 *)A(info))->totalswap)) || - __put_user (s.freeswap, &(((struct sysinfo32 *)A(info))->freeswap)) || - __put_user (s.procs, &(((struct sysinfo32 *)A(info))->procs))) + err = put_user (s.uptime, &info->uptime); + err |= __put_user (s.loads[0], &info->loads[0]); + err |= __put_user (s.loads[1], &info->loads[1]); + err |= __put_user (s.loads[2], &info->loads[2]); + err |= __put_user (s.totalram, &info->totalram); + err |= __put_user (s.freeram, &info->freeram); + err |= __put_user (s.sharedram, &info->sharedram); + err |= __put_user (s.bufferram, &info->bufferram); + err |= __put_user (s.totalswap, &info->totalswap); + err |= __put_user (s.freeswap, &info->freeswap); + err |= __put_user (s.procs, &info->procs); + if (err) return -EFAULT; return ret; } @@ -1492,7 +1525,7 @@ struct timespec32 { extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval); -asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval) +asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval) { struct timespec t; int ret; @@ -1501,29 +1534,29 @@ asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval) set_fs (KERNEL_DS); ret = sys_sched_rr_get_interval(pid, &t); set_fs (old_fs); - if (put_user (t.tv_sec, &(((struct timespec32 *)A(interval))->tv_sec)) || - __put_user (t.tv_nsec, &(((struct timespec32 *)A(interval))->tv_nsec))) + if (put_user (t.tv_sec, &interval->tv_sec) || + __put_user (t.tv_nsec, &interval->tv_nsec)) return -EFAULT; return ret; } extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp); -asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp) +asmlinkage int sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp) { struct timespec t; int ret; mm_segment_t old_fs = get_fs (); - if (get_user (t.tv_sec, &(((struct timespec32 *)A(rqtp))->tv_sec)) || - __get_user (t.tv_nsec, &(((struct timespec32 *)A(rqtp))->tv_nsec))) + if (get_user (t.tv_sec, &rqtp->tv_sec) || + __get_user (t.tv_nsec, &rqtp->tv_nsec)) return -EFAULT; set_fs (KERNEL_DS); ret = sys_nanosleep(&t, rmtp ? &t : NULL); set_fs (old_fs); if (rmtp && ret == -EINTR) { - if (__put_user (t.tv_sec, &(((struct timespec32 *)A(rmtp))->tv_sec)) || - __put_user (t.tv_nsec, &(((struct timespec32 *)A(rmtp))->tv_nsec))) + if (__put_user (t.tv_sec, &rmtp->tv_sec) || + __put_user (t.tv_nsec, &rmtp->tv_nsec)) return -EFAULT; } return ret; @@ -1531,24 +1564,24 @@ asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp) extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset); -asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset) +asmlinkage int sys32_sigprocmask(int how, old_sigset_t32 *set, old_sigset_t32 *oset) { old_sigset_t s; int ret; mm_segment_t old_fs = get_fs(); - if (set && get_user (s, (old_sigset_t32 *)A(set))) return -EFAULT; + if (set && get_user (s, set)) return -EFAULT; set_fs (KERNEL_DS); ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL); set_fs (old_fs); if (ret) return ret; - if (oset && put_user (s, (old_sigset_t32 *)A(oset))) return -EFAULT; + if (oset && put_user (s, oset)) return -EFAULT; return 0; } extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize); -asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t32 sigsetsize) +asmlinkage int sys32_rt_sigprocmask(int how, sigset_t32 *set, sigset_t32 *oset, __kernel_size_t32 sigsetsize) { sigset_t s; sigset_t32 s32; @@ -1556,7 +1589,7 @@ asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t3 mm_segment_t old_fs = get_fs(); if (set) { - if (copy_from_user (&s32, (sigset_t32 *)A(set), sizeof(sigset_t32))) + if (copy_from_user (&s32, set, sizeof(sigset_t32))) return -EFAULT; switch (_NSIG_WORDS) { case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); @@ -1576,7 +1609,7 @@ asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t3 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; } - if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32))) + if (copy_to_user (oset, &s32, sizeof(sigset_t32))) return -EFAULT; } return 0; @@ -1584,7 +1617,7 @@ asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t3 extern asmlinkage int sys_sigpending(old_sigset_t *set); -asmlinkage int sys32_sigpending(u32 set) +asmlinkage int sys32_sigpending(old_sigset_t32 *set) { old_sigset_t s; int ret; @@ -1593,13 +1626,13 @@ asmlinkage int sys32_sigpending(u32 set) set_fs (KERNEL_DS); ret = sys_sigpending(&s); set_fs (old_fs); - if (put_user (s, (old_sigset_t32 *)A(set))) return -EFAULT; + if (put_user (s, set)) return -EFAULT; return ret; } extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize); -asmlinkage int sys32_rt_sigpending(u32 set, __kernel_size_t32 sigsetsize) +asmlinkage int sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize) { sigset_t s; sigset_t32 s32; @@ -1616,7 +1649,7 @@ asmlinkage int sys32_rt_sigpending(u32 set, __kernel_size_t32 sigsetsize) case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; } - if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32))) + if (copy_to_user (set, &s32, sizeof(sigset_t32))) return -EFAULT; } return ret; @@ -1706,8 +1739,8 @@ sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, const struct timespec *uts, size_t sigsetsize); asmlinkage int -sys32_rt_sigtimedwait(u32 uthese, u32 uinfo, - u32 uts, __kernel_size_t32 sigsetsize) +sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, + struct timespec32 *uts, __kernel_size_t32 sigsetsize) { sigset_t s; sigset_t32 s32; @@ -1717,7 +1750,7 @@ sys32_rt_sigtimedwait(u32 uthese, u32 uinfo, siginfo_t info; siginfo_t32 info32; - if (copy_from_user (&s32, (sigset_t32 *)A(uthese), sizeof(sigset_t32))) + if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) return -EFAULT; switch (_NSIG_WORDS) { case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); @@ -1726,15 +1759,16 @@ sys32_rt_sigtimedwait(u32 uthese, u32 uinfo, case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); } if (uts) { - if (get_user (t.tv_sec, &(((struct timespec32 *)A(uts))->tv_sec)) || - __get_user (t.tv_nsec, &(((struct timespec32 *)A(uts))->tv_nsec))) + ret = get_user (t.tv_sec, &uts->tv_sec); + ret |= __get_user (t.tv_nsec, &uts->tv_nsec); + if (ret) return -EFAULT; } set_fs (KERNEL_DS); ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); set_fs (old_fs); if (ret >= 0 && uinfo) { - if (copy_to_user ((siginfo_t32 *)A(uinfo), siginfo64to32(&info32, &info), sizeof(siginfo_t32))) + if (copy_to_user (uinfo, siginfo64to32(&info32, &info), sizeof(siginfo_t32))) return -EFAULT; } return ret; @@ -1744,14 +1778,14 @@ extern asmlinkage int sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); asmlinkage int -sys32_rt_sigqueueinfo(int pid, int sig, u32 uinfo) +sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) { siginfo_t info; siginfo_t32 info32; int ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&info32, (siginfo_t32 *)A(uinfo), sizeof(siginfo_t32))) + if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) return -EFAULT; /* XXX: Is this correct? */ siginfo32to64(&info, &info32); @@ -1788,7 +1822,7 @@ asmlinkage int sys32_setresuid(__kernel_uid_t32 ruid, extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); -asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid) +asmlinkage int sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid, __kernel_uid_t32 *suid) { uid_t a, b, c; int ret; @@ -1797,9 +1831,7 @@ asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid) set_fs (KERNEL_DS); ret = sys_getresuid(&a, &b, &c); set_fs (old_fs); - if (put_user (a, (__kernel_uid_t32 *)A(ruid)) || - put_user (b, (__kernel_uid_t32 *)A(euid)) || - put_user (c, (__kernel_uid_t32 *)A(suid))) + if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid)) return -EFAULT; return ret; } @@ -1831,7 +1863,7 @@ asmlinkage int sys32_setresgid(__kernel_gid_t32 rgid, extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); -asmlinkage int sys32_getresgid(u32 rgid, u32 egid, u32 sgid) +asmlinkage int sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, __kernel_gid_t32 *sgid) { gid_t a, b, c; int ret; @@ -1840,10 +1872,11 @@ asmlinkage int sys32_getresgid(u32 rgid, u32 egid, u32 sgid) set_fs (KERNEL_DS); ret = sys_getresgid(&a, &b, &c); set_fs (old_fs); - if (put_user (a, (__kernel_gid_t32 *)A(rgid)) || - put_user (b, (__kernel_gid_t32 *)A(egid)) || - put_user (c, (__kernel_gid_t32 *)A(sgid))) - return -EFAULT; + if (!ret) { + ret = put_user (a, rgid); + ret |= put_user (b, egid); + ret |= put_user (c, sgid); + } return ret; } @@ -1856,27 +1889,30 @@ struct tms32 { extern asmlinkage long sys_times(struct tms * tbuf); -asmlinkage long sys32_times(u32 tbuf) +asmlinkage long sys32_times(struct tms32 *tbuf) { struct tms t; long ret; mm_segment_t old_fs = get_fs (); + int err; set_fs (KERNEL_DS); ret = sys_times(tbuf ? &t : NULL); set_fs (old_fs); - if (tbuf && ( - put_user (t.tms_utime, &(((struct tms32 *)A(tbuf))->tms_utime)) || - __put_user (t.tms_stime, &(((struct tms32 *)A(tbuf))->tms_stime)) || - __put_user (t.tms_cutime, &(((struct tms32 *)A(tbuf))->tms_cutime)) || - __put_user (t.tms_cstime, &(((struct tms32 *)A(tbuf))->tms_cstime)))) - return -EFAULT; + if (tbuf) { + err = put_user (t.tms_utime, &tbuf->tms_utime); + err |= __put_user (t.tms_stime, &tbuf->tms_stime); + err |= __put_user (t.tms_cutime, &tbuf->tms_cutime); + err |= __put_user (t.tms_cstime, &tbuf->tms_cstime); + if (err) + ret = -EFAULT; + } return ret; } extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist); -asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist) +asmlinkage int sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist) { gid_t gl[NGROUPS]; int ret, i; @@ -1886,15 +1922,15 @@ asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist) ret = sys_getgroups(gidsetsize, gl); set_fs (old_fs); if (gidsetsize && ret > 0 && ret <= NGROUPS) - for (i = 0; i < ret; i++, grouplist += sizeof(__kernel_gid_t32)) - if (__put_user (gl[i], (__kernel_gid_t32 *)A(grouplist))) + for (i = 0; i < ret; i++, grouplist++) + if (__put_user (gl[i], grouplist)) return -EFAULT; return ret; } extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist); -asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist) +asmlinkage int sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist) { gid_t gl[NGROUPS]; int ret, i; @@ -1902,8 +1938,8 @@ asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist) if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; - for (i = 0; i < gidsetsize; i++, grouplist += sizeof(__kernel_gid_t32)) - if (__get_user (gl[i], (__kernel_gid_t32 *)A(grouplist))) + for (i = 0; i < gidsetsize; i++, grouplist++) + if (__get_user (gl[i], grouplist)) return -EFAULT; set_fs (KERNEL_DS); ret = sys_setgroups(gidsetsize, gl); @@ -1921,7 +1957,7 @@ struct rlimit32 { extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim); -asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim) +asmlinkage int sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim) { struct rlimit r; int ret; @@ -1930,24 +1966,24 @@ asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim) set_fs (KERNEL_DS); ret = sys_getrlimit(resource, &r); set_fs (old_fs); - if (!ret && ( - put_user (RESOURCE32(r.rlim_cur), &(((struct rlimit32 *)A(rlim))->rlim_cur)) || - __put_user (RESOURCE32(r.rlim_max), &(((struct rlimit32 *)A(rlim))->rlim_max)))) - return -EFAULT; + if (!ret) { + ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur); + ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max); + } return ret; } extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim); -asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim) +asmlinkage int sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim) { struct rlimit r; int ret; mm_segment_t old_fs = get_fs (); if (resource >= RLIM_NLIMITS) return -EINVAL; - if (get_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) || - __get_user (r.rlim_max, &(((struct rlimit32 *)A(rlim))->rlim_max))) + if (get_user (r.rlim_cur, &rlim->rlim_cur) || + __get_user (r.rlim_max, &rlim->rlim_max)) return -EFAULT; if (r.rlim_cur == RLIM_INFINITY32) r.rlim_cur = RLIM_INFINITY; @@ -1961,7 +1997,7 @@ asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim) extern asmlinkage int sys_getrusage(int who, struct rusage *ru); -asmlinkage int sys32_getrusage(int who, u32 ru) +asmlinkage int sys32_getrusage(int who, struct rusage32 *ru) { struct rusage r; int ret; @@ -1999,49 +2035,46 @@ struct timex32 { int :32; int :32; int :32; int :32; }; -extern asmlinkage int sys_adjtimex(struct timex *txc_p); +extern int do_adjtimex(struct timex *); -asmlinkage int sys32_adjtimex(u32 txc_p) +asmlinkage int sys32_adjtimex(struct timex32 *txc_p) { struct timex t; int ret; - mm_segment_t old_fs = get_fs (); - if (get_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) || - __get_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) || - __get_user (t.freq, &(((struct timex32 *)A(txc_p))->freq)) || - __get_user (t.maxerror, &(((struct timex32 *)A(txc_p))->maxerror)) || - __get_user (t.esterror, &(((struct timex32 *)A(txc_p))->esterror)) || - __get_user (t.status, &(((struct timex32 *)A(txc_p))->status)) || - __get_user (t.constant, &(((struct timex32 *)A(txc_p))->constant)) || - __get_user (t.tick, &(((struct timex32 *)A(txc_p))->tick)) || - __get_user (t.shift, &(((struct timex32 *)A(txc_p))->shift))) - return -EFAULT; - set_fs (KERNEL_DS); - ret = sys_adjtimex(&t); - set_fs (old_fs); - if ((unsigned)ret >= 0 && ( - __put_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) || - __put_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) || - __put_user (t.freq, &(((struct timex32 *)A(txc_p))->freq)) || - __put_user (t.maxerror, &(((struct timex32 *)A(txc_p))->maxerror)) || - __put_user (t.esterror, &(((struct timex32 *)A(txc_p))->esterror)) || - __put_user (t.status, &(((struct timex32 *)A(txc_p))->status)) || - __put_user (t.constant, &(((struct timex32 *)A(txc_p))->constant)) || - __put_user (t.precision, &(((struct timex32 *)A(txc_p))->precision)) || - __put_user (t.tolerance, &(((struct timex32 *)A(txc_p))->tolerance)) || - __put_user (t.time.tv_sec, &(((struct timex32 *)A(txc_p))->time.tv_sec)) || - __put_user (t.time.tv_usec, &(((struct timex32 *)A(txc_p))->time.tv_usec)) || - __put_user (t.tick, &(((struct timex32 *)A(txc_p))->tick)) || - __put_user (t.ppsfreq, &(((struct timex32 *)A(txc_p))->ppsfreq)) || - __put_user (t.jitter, &(((struct timex32 *)A(txc_p))->jitter)) || - __put_user (t.shift, &(((struct timex32 *)A(txc_p))->shift)) || - __put_user (t.stabil, &(((struct timex32 *)A(txc_p))->stabil)) || - __put_user (t.jitcnt, &(((struct timex32 *)A(txc_p))->jitcnt)) || - __put_user (t.calcnt, &(((struct timex32 *)A(txc_p))->calcnt)) || - __put_user (t.errcnt, &(((struct timex32 *)A(txc_p))->errcnt)) || - __put_user (t.stbcnt, &(((struct timex32 *)A(txc_p))->stbcnt)))) - return -EFAULT; + ret = get_user (t.modes, &txc_p->modes); + ret |= __get_user (t.offset, &txc_p->offset); + ret |= __get_user (t.freq, &txc_p->freq); + ret |= __get_user (t.maxerror, &txc_p->maxerror); + ret |= __get_user (t.esterror, &txc_p->esterror); + ret |= __get_user (t.status, &txc_p->status); + ret |= __get_user (t.constant, &txc_p->constant); + ret |= __get_user (t.tick, &txc_p->tick); + ret |= __get_user (t.shift, &txc_p->shift); + if (ret || (ret = do_adjtimex(&t))) + return ret; + ret = __put_user (t.modes, &txc_p->modes); + ret |= __put_user (t.offset, &txc_p->offset); + ret |= __put_user (t.freq, &txc_p->freq); + ret |= __put_user (t.maxerror, &txc_p->maxerror); + ret |= __put_user (t.esterror, &txc_p->esterror); + ret |= __put_user (t.status, &txc_p->status); + ret |= __put_user (t.constant, &txc_p->constant); + ret |= __put_user (t.precision, &txc_p->precision); + ret |= __put_user (t.tolerance, &txc_p->tolerance); + ret |= __put_user (t.time.tv_sec, &txc_p->time.tv_sec); + ret |= __put_user (t.time.tv_usec, &txc_p->time.tv_usec); + ret |= __put_user (t.tick, &txc_p->tick); + ret |= __put_user (t.ppsfreq, &txc_p->ppsfreq); + ret |= __put_user (t.jitter, &txc_p->jitter); + ret |= __put_user (t.shift, &txc_p->shift); + ret |= __put_user (t.stabil, &txc_p->stabil); + ret |= __put_user (t.jitcnt, &txc_p->jitcnt); + ret |= __put_user (t.calcnt, &txc_p->calcnt); + ret |= __put_user (t.errcnt, &txc_p->errcnt); + ret |= __put_user (t.stbcnt, &txc_p->stbcnt); + if (!ret) + ret = time_state; return ret; } @@ -2129,22 +2162,23 @@ static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg, struct msghdr32 *umsg) { u32 tmp1, tmp2, tmp3; + int err; - if(get_user(tmp1, &umsg->msg_name) || - get_user(tmp2, &umsg->msg_iov) || - get_user(tmp3, &umsg->msg_control)) + err = get_user(tmp1, &umsg->msg_name); + err |= __get_user(tmp2, &umsg->msg_iov); + err |= __get_user(tmp3, &umsg->msg_control); + if (err) return -EFAULT; kmsg->msg_name = (void *)A(tmp1); kmsg->msg_iov = (struct iovec *)A(tmp2); kmsg->msg_control = (void *)A(tmp3); - if(get_user(kmsg->msg_namelen, &umsg->msg_namelen) || - get_user(kmsg->msg_controllen, &umsg->msg_controllen) || - get_user(kmsg->msg_flags, &umsg->msg_flags)) - return -EFAULT; - - return 0; + err = get_user(kmsg->msg_namelen, &umsg->msg_namelen); + err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); + err |= get_user(kmsg->msg_flags, &umsg->msg_flags); + + return err; } /* I've named the args so it is easy to tell whose space the pointers are in. */ @@ -2183,7 +2217,7 @@ static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov, return tot_len; } -asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags) +asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags) { struct socket *sock; char address[MAX_SOCK_ADDR]; @@ -2193,7 +2227,7 @@ asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags) struct msghdr kern_msg; int err, total_len; - if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg))) + if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) return -EFAULT; if(kern_msg.msg_iovlen > UIO_MAXIOV) return -EINVAL; @@ -2246,7 +2280,7 @@ out: return err; } -asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags) +asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags) { struct iovec iovstack[UIO_FASTIOV]; struct msghdr kern_msg; @@ -2258,13 +2292,13 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags) unsigned long cmsg_ptr; int err, total_len, len = 0; - if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg))) + if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) return -EFAULT; if(kern_msg.msg_iovlen > UIO_MAXIOV) return -EINVAL; uaddr = kern_msg.msg_name; - uaddr_len = &((struct msghdr32 *)A(user_msg))->msg_namelen; + uaddr_len = &user_msg->msg_namelen; err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); if (err < 0) goto out; @@ -2288,12 +2322,11 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags) if(uaddr != NULL && err >= 0) err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); if(err >= 0) { - err = __put_user(kern_msg.msg_flags, - &((struct msghdr32 *)A(user_msg))->msg_flags); + err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); if(!err) { /* XXX Convert cmsg back into userspace 32-bit format... */ err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr, - &((struct msghdr32 *)A(user_msg))->msg_controllen); + &user_msg->msg_controllen); } } @@ -2334,14 +2367,14 @@ extern asmlinkage int sys_socketpair(int family, int type, int protocol, extern asmlinkage int sys_shutdown(int fd, int how); extern asmlinkage int sys_listen(int fd, int backlog); -asmlinkage int sys32_socketcall(int call, u32 args) +asmlinkage int sys32_socketcall(int call, u32 *args) { u32 a[6]; u32 a0,a1; if (call<SYS_SOCKET||call>SYS_RECVMSG) return -EINVAL; - if (copy_from_user(a, (u32 *)A(args), nargs[call])) + if (copy_from_user(a, args, nargs[call])) return -EFAULT; a0=a[0]; a1=a[1]; @@ -2379,16 +2412,16 @@ asmlinkage int sys32_socketcall(int call, u32 args) case SYS_GETSOCKOPT: return sys32_getsockopt(a0, a1, a[2], a[3], a[4]); case SYS_SENDMSG: - return sys32_sendmsg(a0, a1, a[2]); + return sys32_sendmsg(a0, (struct msghdr32 *)A(a1), a[2]); case SYS_RECVMSG: - return sys32_recvmsg(a0, a1, a[2]); + return sys32_recvmsg(a0, (struct msghdr32 *)A(a1), a[2]); } return -EINVAL; } extern void check_pending(int signum); -asmlinkage int sys32_sigaction (int sig, u32 act, u32 oact) +asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -2401,31 +2434,31 @@ asmlinkage int sys32_sigaction (int sig, u32 act, u32 oact) if (act) { old_sigset_t32 mask; - if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) || - __get_user((long)new_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(act))->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags); - __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask); - new_ka.ka_restorer = NULL; - siginitset(&new_ka.sa.sa_mask, mask); + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); + ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer); + ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= __get_user(mask, &act->sa_mask); + if (ret) + return ret; + new_ka.ka_restorer = NULL; + siginitset(&new_ka.sa.sa_mask, mask); } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (!ret && oact) { - if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) || - __put_user((long)old_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(oact))->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask); + if (!ret && oact) { + ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); + ret |= __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer); + ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; } asmlinkage int -sys32_rt_sigaction(int sig, u32 act, u32 oact, - u32 restorer, __kernel_size_t32 sigsetsize) +sys32_rt_sigaction(int sig, struct sigaction32 *act, struct sigaction32 *oact, + void *restorer, __kernel_size_t32 sigsetsize) { struct k_sigaction new_ka, old_ka; int ret; @@ -2435,35 +2468,40 @@ sys32_rt_sigaction(int sig, u32 act, u32 oact, if (sigsetsize != sizeof(sigset_t32)) return -EINVAL; + /* All tasks which use RT signals (effectively) use + * new style signals. + */ + current->tss.new_signal = 1; + if (act) { - if (get_user((long)new_ka.sa.sa_handler, &((struct sigaction32 *)A(act))->sa_handler) || - __copy_from_user(&set32, &((struct sigaction32 *)A(act))->sa_mask, sizeof(sigset_t32))) - return -EFAULT; + new_ka.ka_restorer = restorer; + ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler); + ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(sigset_t32)); switch (_NSIG_WORDS) { case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32); case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32); case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32); case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32); } - __get_user(new_ka.sa.sa_flags, &((struct sigaction32 *)A(act))->sa_flags); - __get_user((long)new_ka.sa.sa_restorer, &((struct sigaction32 *)A(act))->sa_restorer); - new_ka.ka_restorer = (void *)(long)restorer; - } + ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer); + if (ret) + return -EFAULT; + } - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (!ret && oact) { + if (!ret && oact) { switch (_NSIG_WORDS) { case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3]; case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2]; case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1]; case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0]; } - if (put_user((long)old_ka.sa.sa_handler, &((struct sigaction32 *)A(oact))->sa_handler) || - __copy_to_user(&((struct sigaction32 *)A(oact))->sa_mask, &set32, sizeof(sigset_t32))) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &((struct sigaction32 *)A(oact))->sa_flags); - __put_user((long)old_ka.sa.sa_restorer, &((struct sigaction32 *)A(oact))->sa_restorer); + ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler); + ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(sigset_t32)); + ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + ret |= __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer); } return ret; @@ -2608,14 +2646,14 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) base = 1; lock_kernel(); - filename = getname((char *)A((u32)regs->u_regs[base + UREG_I0])); + filename = getname32((char *)AA(regs->u_regs[base + UREG_I0])); error = PTR_ERR(filename); if(IS_ERR(filename)) goto out; error = do_execve32(filename, - (u32 *)A((u32)regs->u_regs[base + UREG_I1]), - (u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs); - putname(filename); + (u32 *)AA((u32)regs->u_regs[base + UREG_I1]), + (u32 *)AA((u32)regs->u_regs[base + UREG_I2]), regs); + putname32(filename); if(!error) { fprs_write(0); @@ -2632,9 +2670,9 @@ out: extern asmlinkage unsigned long sys_create_module(const char *name_user, size_t size); -asmlinkage unsigned long sys32_create_module(u32 name_user, __kernel_size_t32 size) +asmlinkage unsigned long sys32_create_module(const char *name_user, __kernel_size_t32 size) { - return sys_create_module((const char *)A(name_user), (size_t)size); + return sys_create_module(name_user, (size_t)size); } extern asmlinkage int sys_init_module(const char *name_user, struct module *mod_user); @@ -2642,16 +2680,16 @@ extern asmlinkage int sys_init_module(const char *name_user, struct module *mod_ /* Hey, when you're trying to init module, take time and prepare us a nice 64bit * module structure, even if from 32bit modutils... Why to pollute kernel... :)) */ -asmlinkage int sys32_init_module(u32 nameuser, u32 mod_user) +asmlinkage int sys32_init_module(const char *name_user, struct module *mod_user) { - return sys_init_module((const char *)A(nameuser), (struct module *)A(mod_user)); + return sys_init_module(name_user, mod_user); } extern asmlinkage int sys_delete_module(const char *name_user); -asmlinkage int sys32_delete_module(u32 name_user) +asmlinkage int sys32_delete_module(const char *name_user) { - return sys_delete_module((const char *)A(name_user)); + return sys_delete_module(name_user); } struct module_info32 { @@ -2663,10 +2701,53 @@ struct module_info32 { /* Query various bits about modules. */ -extern long get_mod_name(const char *user_name, char **buf); -extern void put_mod_name(char *buf); -extern struct module *find_module(const char *name); -extern struct module kernel_module; +static inline long +get_mod_name(const char *user_name, char **buf) +{ + unsigned long page; + long retval; + + if ((unsigned long)user_name >= TASK_SIZE + && !segment_eq(get_fs (), KERNEL_DS)) + return -EFAULT; + + page = __get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE); + if (retval > 0) { + if (retval < PAGE_SIZE) { + *buf = (char *)page; + return retval; + } + retval = -ENAMETOOLONG; + } else if (!retval) + retval = -EINVAL; + + free_page(page); + return retval; +} + +static inline void +put_mod_name(char *buf) +{ + free_page((unsigned long)buf); +} + +static __inline__ struct module *find_module(const char *name) +{ + struct module *mod; + + for (mod = module_list; mod ; mod = mod->next) { + if (mod->flags & MOD_DELETED) + continue; + if (!strcmp(mod->name, name)) + break; + } + + return mod; +} static int qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) @@ -2676,7 +2757,7 @@ qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) nmod = space = 0; - for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) { + for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) { len = strlen(mod->name)+1; if (len > bufsize) goto calc_space_needed; @@ -2694,7 +2775,7 @@ qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) calc_space_needed: space += len; - while ((mod = mod->next) != &kernel_module) + while ((mod = mod->next)->next != NULL) space += strlen(mod->name)+1; if (put_user(space, ret)) @@ -2708,7 +2789,7 @@ qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) { size_t i, space, len; - if (mod == &kernel_module) + if (mod->next == NULL) return -EINVAL; if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) if (put_user(0, ret)) @@ -2752,7 +2833,7 @@ qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) size_t nrefs, space, len; struct module_ref *ref; - if (mod == &kernel_module) + if (mod->next == NULL) return -EINVAL; if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) if (put_user(0, ret)) @@ -2854,7 +2935,7 @@ qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) { int error = 0; - if (mod == &kernel_module) + if (mod->next == NULL) return -EINVAL; if (sizeof(struct module_info32) <= bufsize) { @@ -2876,26 +2957,30 @@ qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) return error; } -asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 ret) +asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kernel_size_t32 bufsize, u32 ret) { struct module *mod; int err; lock_kernel(); - if (name_user == 0) - mod = &kernel_module; - else { + if (name_user == 0) { + /* This finds "kernel_module" which is not exported. */ + for(mod = module_list; mod->next != NULL; mod = mod->next) + ; + } else { long namelen; char *name; - if ((namelen = get_mod_name((char *)A(name_user), &name)) < 0) { + if ((namelen = get_mod_name(name_user, &name)) < 0) { err = namelen; goto out; } err = -ENOENT; - if (namelen == 0) - mod = &kernel_module; - else if ((mod = find_module(name)) == NULL) { + if (namelen == 0) { + /* This finds "kernel_module" which is not exported. */ + for(mod = module_list; mod->next != NULL; mod = mod->next) + ; + } else if ((mod = find_module(name)) == NULL) { put_mod_name(name); goto out; } @@ -2908,19 +2993,19 @@ asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_si err = 0; break; case QM_MODULES: - err = qm_modules((char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + err = qm_modules(buf, bufsize, (__kernel_size_t32 *)AA(ret)); break; case QM_DEPS: - err = qm_deps(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + err = qm_deps(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); break; case QM_REFS: - err = qm_refs(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + err = qm_refs(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); break; case QM_SYMBOLS: - err = qm_symbols(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + err = qm_symbols(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); break; case QM_INFO: - err = qm_info(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + err = qm_info(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret)); break; default: err = -EINVAL; @@ -2938,7 +3023,7 @@ struct kernel_sym32 { extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table); -asmlinkage int sys32_get_kernel_syms(u32 table) +asmlinkage int sys32_get_kernel_syms(struct kernel_sym32 *table) { int len, i; struct kernel_sym *tbl; @@ -2953,8 +3038,8 @@ asmlinkage int sys32_get_kernel_syms(u32 table) sys_get_kernel_syms(tbl); set_fs (old_fs); for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) { - if (put_user (tbl[i].value, &(((struct kernel_sym32 *)A(table))->value)) || - copy_to_user (((struct kernel_sym32 *)A(table))->name, tbl[i].name, 60)) + if (put_user (tbl[i].value, &table->value) || + copy_to_user (table->name, tbl[i].name, 60)) break; } kfree (tbl); @@ -3069,61 +3154,65 @@ union nfsctl_res32 { static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { - if(__get_user(karg->ca_version, &arg32->ca32_version) || - __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port) || - __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads)) - return -EFAULT; - return 0; + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port); + err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads); + return err; } static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { - if(__get_user(karg->ca_version, &arg32->ca32_version) || - copy_from_user(&karg->ca_client.cl_ident[0], + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_client.cl_ident[0], &arg32->ca32_client.cl32_ident[0], - NFSCLNT_IDMAX) || - __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr) || - copy_from_user(&karg->ca_client.cl_addrlist[0], + NFSCLNT_IDMAX); + err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr); + err |= copy_from_user(&karg->ca_client.cl_addrlist[0], &arg32->ca32_client.cl32_addrlist[0], - (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)) || - __get_user(karg->ca_client.cl_fhkeytype, - &arg32->ca32_client.cl32_fhkeytype) || - __get_user(karg->ca_client.cl_fhkeylen, - &arg32->ca32_client.cl32_fhkeylen) || - copy_from_user(&karg->ca_client.cl_fhkey[0], + (sizeof(struct in_addr) * NFSCLNT_ADDRMAX)); + err |= __get_user(karg->ca_client.cl_fhkeytype, + &arg32->ca32_client.cl32_fhkeytype); + err |= __get_user(karg->ca_client.cl_fhkeylen, + &arg32->ca32_client.cl32_fhkeylen); + err |= copy_from_user(&karg->ca_client.cl_fhkey[0], &arg32->ca32_client.cl32_fhkey[0], - NFSCLNT_KEYMAX)) - return -EFAULT; - return 0; + NFSCLNT_KEYMAX); + return err; } static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { - if(__get_user(karg->ca_version, &arg32->ca32_version) || - copy_from_user(&karg->ca_export.ex_client[0], + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_export.ex_client[0], &arg32->ca32_export.ex32_client[0], - NFSCLNT_IDMAX) || - copy_from_user(&karg->ca_export.ex_path[0], + NFSCLNT_IDMAX); + err |= copy_from_user(&karg->ca_export.ex_path[0], &arg32->ca32_export.ex32_path[0], - NFS_MAXPATHLEN) || - __get_user(karg->ca_export.ex_dev, - &arg32->ca32_export.ex32_dev) || - __get_user(karg->ca_export.ex_ino, - &arg32->ca32_export.ex32_ino) || - __get_user(karg->ca_export.ex_flags, - &arg32->ca32_export.ex32_flags) || - __get_user(karg->ca_export.ex_anon_uid, - &arg32->ca32_export.ex32_anon_uid) || - __get_user(karg->ca_export.ex_anon_gid, - &arg32->ca32_export.ex32_anon_gid)) - return -EFAULT; - return 0; + NFS_MAXPATHLEN); + err |= __get_user(karg->ca_export.ex_dev, + &arg32->ca32_export.ex32_dev); + err |= __get_user(karg->ca_export.ex_ino, + &arg32->ca32_export.ex32_ino); + err |= __get_user(karg->ca_export.ex_flags, + &arg32->ca32_export.ex32_flags); + err |= __get_user(karg->ca_export.ex_anon_uid, + &arg32->ca32_export.ex32_anon_uid); + err |= __get_user(karg->ca_export.ex_anon_gid, + &arg32->ca32_export.ex32_anon_gid); + return err; } static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { u32 uaddr; int i; + int err; memset(karg, 0, sizeof(*karg)); if(__get_user(karg->ca_version, &arg32->ca32_version)) @@ -3131,76 +3220,74 @@ static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER); if(!karg->ca_umap.ug_ident) return -ENOMEM; - if(__get_user(uaddr, &arg32->ca32_umap.ug32_ident)) - return -EFAULT; + err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident); if(strncpy_from_user(karg->ca_umap.ug_ident, (char *)A(uaddr), PAGE_SIZE) <= 0) return -EFAULT; - if(__get_user(karg->ca_umap.ug_uidbase, - &arg32->ca32_umap.ug32_uidbase) || - __get_user(karg->ca_umap.ug_uidlen, - &arg32->ca32_umap.ug32_uidlen) || - __get_user(uaddr, &arg32->ca32_umap.ug32_udimap)) + err |= __get_user(karg->ca_umap.ug_uidbase, + &arg32->ca32_umap.ug32_uidbase); + err |= __get_user(karg->ca_umap.ug_uidlen, + &arg32->ca32_umap.ug32_uidlen); + err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap); + if (err) return -EFAULT; karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen), GFP_USER); if(!karg->ca_umap.ug_udimap) - return -EFAULT; + return -ENOMEM; for(i = 0; i < karg->ca_umap.ug_uidlen; i++) - if(__get_user(karg->ca_umap.ug_udimap[i], - &(((__kernel_uid_t32 *)A(uaddr))[i]))) - return -EFAULT; - if(__get_user(karg->ca_umap.ug_gidbase, - &arg32->ca32_umap.ug32_gidbase) || - __get_user(karg->ca_umap.ug_uidlen, - &arg32->ca32_umap.ug32_gidlen) || - __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap)) + err |= __get_user(karg->ca_umap.ug_udimap[i], + &(((__kernel_uid_t32 *)A(uaddr))[i])); + err |= __get_user(karg->ca_umap.ug_gidbase, + &arg32->ca32_umap.ug32_gidbase); + err |= __get_user(karg->ca_umap.ug_uidlen, + &arg32->ca32_umap.ug32_gidlen); + err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap); + if (err) return -EFAULT; karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen), GFP_USER); if(!karg->ca_umap.ug_gdimap) - return -EFAULT; + return -ENOMEM; for(i = 0; i < karg->ca_umap.ug_gidlen; i++) - if(__get_user(karg->ca_umap.ug_gdimap[i], - &(((__kernel_gid_t32 *)A(uaddr))[i]))) - return -EFAULT; + err |= __get_user(karg->ca_umap.ug_gdimap[i], + &(((__kernel_gid_t32 *)A(uaddr))[i])); - /* Success! */ - return 0; + return err; } static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32) { - if(__get_user(karg->ca_version, &arg32->ca32_version) || - copy_from_user(&karg->ca_getfh.gf_addr, + int err; + + err = __get_user(karg->ca_version, &arg32->ca32_version); + err |= copy_from_user(&karg->ca_getfh.gf_addr, &arg32->ca32_getfh.gf32_addr, - (sizeof(struct sockaddr))) || - __get_user(karg->ca_getfh.gf_dev, - &arg32->ca32_getfh.gf32_dev) || - __get_user(karg->ca_getfh.gf_ino, - &arg32->ca32_getfh.gf32_ino) || - __get_user(karg->ca_getfh.gf_version, - &arg32->ca32_getfh.gf32_version)) - return -EFAULT; - return 0; + (sizeof(struct sockaddr))); + err |= __get_user(karg->ca_getfh.gf_dev, + &arg32->ca32_getfh.gf32_dev); + err |= __get_user(karg->ca_getfh.gf_ino, + &arg32->ca32_getfh.gf32_ino); + err |= __get_user(karg->ca_getfh.gf_version, + &arg32->ca32_getfh.gf32_version); + return err; } static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32) { - if(copy_to_user(&res32->cr32_getfh, + int err; + + err = copy_to_user(&res32->cr32_getfh, &kres->cr_getfh, - sizeof(res32->cr32_getfh)) || - __put_user(kres->cr_debug, &res32->cr32_debug)) - return -EFAULT; - return 0; + sizeof(res32->cr32_getfh)); + err |= __put_user(kres->cr_debug, &res32->cr32_debug); + return err; } extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp); -int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp) +int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32) { - struct nfsctl_arg32 *arg32 = (struct nfsctl_arg32 *)A(u_argp); - union nfsctl_res32 *res32 = (union nfsctl_res32 *)A(u_resp); struct nfsctl_arg *karg = NULL; union nfsctl_res *kres = NULL; mm_segment_t oldfs; @@ -3273,32 +3360,32 @@ done: extern struct timezone sys_tz; extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); -asmlinkage int sys32_gettimeofday(u32 tv, u32 tz) +asmlinkage int sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz) { if (tv) { struct timeval ktv; do_gettimeofday(&ktv); - if (put_tv32((struct timeval32 *)A(tv), &ktv)) + if (put_tv32(tv, &ktv)) return -EFAULT; } if (tz) { - if (copy_to_user((void*)A(tz), &sys_tz, sizeof(sys_tz))) + if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0; } -asmlinkage int sys32_settimeofday(u32 tv, u32 tz) +asmlinkage int sys32_settimeofday(struct timeval32 *tv, struct timezone *tz) { struct timeval ktv; struct timezone ktz; if (tv) { - if (get_tv32(&ktv, (struct timeval32 *)A(tv))) + if (get_tv32(&ktv, tv)) return -EFAULT; } if (tz) { - if (copy_from_user(&ktz, (void*)A(tz), sizeof(ktz))) + if (copy_from_user(&ktz, tz, sizeof(ktz))) return -EFAULT; } @@ -3307,13 +3394,13 @@ asmlinkage int sys32_settimeofday(u32 tv, u32 tz) extern int do_getitimer(int which, struct itimerval *value); -asmlinkage int sys32_getitimer(int which, u32 it) +asmlinkage int sys32_getitimer(int which, struct itimerval32 *it) { struct itimerval kit; int error; error = do_getitimer(which, &kit); - if (!error && put_it32((struct itimerval32 *)A(it), &kit)) + if (!error && put_it32(it, &kit)) error = -EFAULT; return error; @@ -3321,13 +3408,13 @@ asmlinkage int sys32_getitimer(int which, u32 it) extern int do_setitimer(int which, struct itimerval *, struct itimerval *); -asmlinkage int sys32_setitimer(int which, u32 in, u32 out) +asmlinkage int sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out) { struct itimerval kin, kout; int error; if (in) { - if (get_it32(&kin, (struct itimerval32 *)A(in))) + if (get_it32(&kin, in)) return -EFAULT; } else memset(&kin, 0, sizeof(kin)); @@ -3335,7 +3422,7 @@ asmlinkage int sys32_setitimer(int which, u32 in, u32 out) error = do_setitimer(which, &kin, out ? &kout : NULL); if (error || !out) return error; - if (put_it32((struct itimerval32 *)A(out), &kout)) + if (put_it32(out, &kout)) return -EFAULT; return 0; @@ -3344,7 +3431,7 @@ asmlinkage int sys32_setitimer(int which, u32 in, u32 out) asmlinkage int sys_utimes(char *, struct timeval *); -asmlinkage int sys32_utimes(u32 filename, u32 tvs) +asmlinkage int sys32_utimes(char *filename, struct timeval32 *tvs) { char *kfilename; struct timeval ktvs[2]; @@ -3355,8 +3442,8 @@ asmlinkage int sys32_utimes(u32 filename, u32 tvs) ret = PTR_ERR(kfilename); if (!IS_ERR(kfilename)) { if (tvs) { - if (get_tv32(&ktvs[0], (struct timeval32 *)A(tvs)) || - get_tv32(&ktvs[1], 1+(struct timeval32 *)A(tvs))) + if (get_tv32(&ktvs[0], tvs) || + get_tv32(&ktvs[1], 1+tvs)) return -EFAULT; } @@ -3397,7 +3484,7 @@ asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf (unsigned long) dfn, (unsigned long) off, (unsigned long) len, - (unsigned char *)A(ubuf)); + (unsigned char *)AA(ubuf)); } asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf) @@ -3406,7 +3493,7 @@ asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubu (unsigned long) dfn, (unsigned long) off, (unsigned long) len, - (unsigned char *)A(ubuf)); + (unsigned char *)AA(ubuf)); } extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3, @@ -3442,16 +3529,16 @@ extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf, typedef __kernel_ssize_t32 ssize_t32; -asmlinkage ssize_t32 sys32_pread(unsigned int fd, u32 ubuf, - __kernel_size_t32 count, u32 pos) +asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf, + __kernel_size_t32 count, u32 poshi, u32 poslo) { - return sys_pread(fd, (char *) A(ubuf), count, pos); + return sys_pread(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo)); } -asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, u32 ubuf, - __kernel_size_t32 count, u32 pos) +asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf, + __kernel_size_t32 count, u32 poshi, u32 poslo) { - return sys_pwrite(fd, (char *) A(ubuf), count, pos); + return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo)); } @@ -3472,20 +3559,20 @@ asmlinkage int sys32_personality(unsigned long personality) extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count); -asmlinkage int sys32_sendfile(int out_fd, int in_fd, u32 offset, s32 count) +asmlinkage int sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count) { mm_segment_t old_fs = get_fs(); int ret; off_t of; - if (offset && get_user(of, (__kernel_off_t32 *)A(offset))) + if (offset && get_user(of, offset)) return -EFAULT; set_fs(KERNEL_DS); ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); set_fs(old_fs); - if (!ret && offset && put_user(of, (__kernel_off_t32 *)A(offset))) + if (!ret && offset && put_user(of, offset)) return -EFAULT; return ret; diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index ec965972f..82701cc9e 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.16 1998/06/16 04:37:06 davem Exp $ +/* $Id: sys_sunos32.c,v 1.22 1998/10/26 20:01:13 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -52,7 +52,14 @@ #include <linux/time.h> #include <linux/personality.h> -#define A(x) ((unsigned long)x) +/* Use this to get at 32-bit user passed pointers. */ +#define A(__x) \ +({ unsigned long __ret; \ + __asm__ ("srl %0, 0, %0" \ + : "=r" (__ret) \ + : "0" (__x)); \ + __ret; \ +}) #define SUNOS_NR_OPEN 256 @@ -61,6 +68,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of struct file *file = NULL; unsigned long retval, ret_type; + down(¤t->mm->mmap_sem); lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { @@ -98,6 +106,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of ret_type = flags & _MAP_NEW; flags &= ~_MAP_NEW; + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, (unsigned long) addr, (unsigned long) len, (unsigned long) prot, (unsigned long) flags, @@ -109,6 +118,7 @@ out_putf: fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return (u32) retval; } @@ -123,6 +133,7 @@ asmlinkage int sunos_brk(u32 baddr) unsigned long rlim; unsigned long newbrk, oldbrk, brk = (unsigned long) baddr; + down(¤t->mm->mmap_sem); lock_kernel(); if (brk < current->mm->end_code) goto out; @@ -170,6 +181,7 @@ asmlinkage int sunos_brk(u32 baddr) retval = 0; out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -530,27 +542,17 @@ struct sunos_utsname { char mach[9]; }; -asmlinkage int sunos_uname(u32 u_name) +asmlinkage int sunos_uname(struct sunos_utsname *name) { - struct sunos_utsname *name = (struct sunos_utsname *)A(u_name); - int ret = -EFAULT; + int ret; down(&uts_sem); - if(!name) - goto out; - if(copy_to_user(&name->sname[0], - &system_utsname.sysname[0], - sizeof(name->sname) - 1)) - goto out; - copy_to_user(&name->nname[0], - &system_utsname.nodename[0], - sizeof(name->nname) - 1); - put_user('\0', &name->nname[8]); - copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); - copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); - copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); - ret = 0; -out: + ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1); + ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); + ret |= put_user('\0', &name->nname[8]); + ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); + ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); + ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); up(&uts_sem); return ret; } @@ -829,6 +831,8 @@ sunos_mount(char *type, char *dir, int flags, void *data) int ret = -EINVAL; char *dev_fname = 0; + if (!capable (CAP_SYS_ADMIN)) + return -EPERM; lock_kernel(); /* We don't handle the integer fs type */ if ((flags & SMNT_NEWTYPE) == 0) @@ -1203,9 +1207,6 @@ struct shmid_ds32 { __kernel_ipc_pid_t32 shm_cpid; __kernel_ipc_pid_t32 shm_lpid; unsigned short shm_nattch; - unsigned short shm_npages; - u32 shm_pages; - u32 attaches; }; static inline int sunos_shmid_get(struct shmid_ds32 *user, @@ -1222,8 +1223,7 @@ static inline int sunos_shmid_get(struct shmid_ds32 *user, __get_user(kern->shm_ctime, &user->shm_ctime) || __get_user(kern->shm_cpid, &user->shm_cpid) || __get_user(kern->shm_lpid, &user->shm_lpid) || - __get_user(kern->shm_nattch, &user->shm_nattch) || - __get_user(kern->shm_npages, &user->shm_npages)) + __get_user(kern->shm_nattch, &user->shm_nattch)) return -EFAULT; return 0; } @@ -1242,8 +1242,7 @@ static inline int sunos_shmid_put(struct shmid_ds32 *user, __put_user(kern->shm_ctime, &user->shm_ctime) || __put_user(kern->shm_cpid, &user->shm_cpid) || __put_user(kern->shm_lpid, &user->shm_lpid) || - __put_user(kern->shm_nattch, &user->shm_nattch) || - __put_user(kern->shm_npages, &user->shm_npages)) + __put_user(kern->shm_nattch, &user->shm_nattch)) return -EFAULT; return 0; } diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index beed61bd7..11c86ef5f 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.47 1998/07/28 13:07:55 jj Exp $ +/* $Id: systbls.S,v 1.50 1998/10/07 01:27:27 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -17,10 +17,10 @@ .globl sys_call_table32 sys_call_table32: -/*0*/ .word sys_setup, sparc_exit, sys_fork, sys_read, sys_write +/*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write /*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link -/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod -/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_nis_syscall, sys32_lseek +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod +/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice @@ -76,10 +76,10 @@ sys_call_table32: .globl sys_call_table64, sys_call_table sys_call_table64: sys_call_table: -/*0*/ .word sys_setup, sparc_exit, sys_fork, sys_read, sys_write +/*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write /*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link -/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod -/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod +/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_perfctr, sys_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 364f2b4a1..e95bf0727 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.15 1998/05/12 22:38:29 ecd Exp $ +/* $Id: time.c,v 1.16 1998/09/05 17:25:28 jj Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -32,8 +32,8 @@ #include <asm/ebus.h> struct mostek48t02 *mstk48t02_regs = 0; -struct mostek48t08 *mstk48t08_regs = 0; -struct mostek48t59 *mstk48t59_regs = 0; +static struct mostek48t08 *mstk48t08_regs = 0; +static struct mostek48t59 *mstk48t59_regs = 0; static int set_rtc_mmss(unsigned long); @@ -133,7 +133,7 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon, } /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ -static void kick_start_clock(void) +static void __init kick_start_clock(void) { register struct mostek48t02 *regs = mstk48t02_regs; unsigned char sec; @@ -182,7 +182,7 @@ static void kick_start_clock(void) } /* Return nonzero if the clock chip battery is low. */ -static int has_low_battery(void) +static int __init has_low_battery(void) { register struct mostek48t02 *regs = mstk48t02_regs; unsigned char data1, data2; @@ -197,7 +197,7 @@ static int has_low_battery(void) /* Probe for the real time clock chip. */ -__initfunc(static void set_system_time(void)) +static void __init set_system_time(void) { unsigned int year, mon, day, hour, min, sec; struct mostek48t02 *mregs; @@ -222,15 +222,18 @@ __initfunc(static void set_system_time(void)) mregs->creg &= ~MSTK_CREG_READ; } -__initfunc(void clock_probe(void)) +void __init clock_probe(void) { struct linux_prom_registers clk_reg[2]; char model[128]; int node, busnd = -1, err; + unsigned long flags; #ifdef CONFIG_PCI struct linux_ebus *ebus = 0; #endif + __save_and_cli(flags); + if(central_bus != NULL) { busnd = central_bus->child->prom_node; } @@ -349,6 +352,8 @@ __initfunc(void clock_probe(void)) kick_start_clock(); set_system_time(); + + __restore_flags(flags); } #ifndef BCD_TO_BIN @@ -359,19 +364,15 @@ __initfunc(void clock_probe(void)) #define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) #endif -__initfunc(void time_init(void)) -{ - /* clock_probe() is now done at end of sbus_init on sparc64 - * so that both sbus and fhc bus information is probed and - * available. - */ -} - extern void init_timers(void (*func)(int, void *, struct pt_regs *), unsigned long *); -__initfunc(void sun4u_start_timers(void)) +void __init time_init(void) { + /* clock_probe() is now done at end of [se]bus_init on sparc64 + * so that sbus, fhc and ebus bus information is probed and + * available. + */ unsigned long clock; init_timers(timer_interrupt, &clock); diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S index 797d4047e..9c0498348 100644 --- a/arch/sparc64/kernel/trampoline.S +++ b/arch/sparc64/kernel/trampoline.S @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.5 1998/05/25 05:31:45 davem Exp $ +/* $Id: trampoline.S,v 1.6 1998/10/11 06:58:23 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -27,6 +27,7 @@ sparc64_cpu_startup: stxa %g1, [%g0] ASI_LSU_CONTROL membar #Sync wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate + wr %g0, 0, %fprs wrpr %g0, 15, %pil sethi %uhi(PAGE_OFFSET), %g4 diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index e1d652841..cb5180fff 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.51 1998/06/12 14:54:20 jj Exp $ +/* $Id: traps.c,v 1.55 1998/10/11 06:58:22 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -178,6 +178,79 @@ unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) } #endif /* SYSCALL_TRACING */ +#if 0 +void rtrap_check(struct pt_regs *regs) +{ + register unsigned long pgd_phys asm("o1"); + register unsigned long pgd_cache asm("o2"); + register unsigned long g1_or_g3 asm("o3"); + register unsigned long g2 asm("o4"); + unsigned long ctx; + +#if 0 + do { + unsigned long test; + __asm__ __volatile__("rdpr %%pstate, %0" + : "=r" (test)); + if((test & PSTATE_MG) != 0 || + (test & PSTATE_IE) == 0) { + printk("rtrap_check: Bogus pstate[%016lx]\n", test); + return; + } + } while(0); +#endif + + __asm__ __volatile__(" + rdpr %%pstate, %%o5 + wrpr %%o5, %4, %%pstate + or %%g1, %%g3, %2 + mov %%g2, %3 + mov %%g7, %0 + mov %5, %1 + ldxa [%1] %6, %1 + wrpr %%o5, 0x0, %%pstate" + : "=r" (pgd_phys), "=r" (pgd_cache), + "=r" (g1_or_g3), "=r" (g2) + : "i" (PSTATE_IE | PSTATE_MG), "i" (TSB_REG), + "i" (ASI_DMMU) + : "o5"); + + ctx = spitfire_get_secondary_context(); + + if((pgd_phys != __pa(current->mm->pgd)) || + ((pgd_cache != 0) && + (pgd_cache != pgd_val(current->mm->pgd[0]))) || + (g1_or_g3 != (0xfffffffe00000000UL | 0x0000000000000018UL)) || +#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) +#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) + (g2 != (KERN_HIGHBITS | KERN_LOWBITS)) || +#undef KERN_HIGHBITS +#undef KERN_LOWBITS + ((ctx != (current->mm->context & 0x3ff)) || + (ctx == 0) || + (current->tss.ctx != ctx))) { + printk("SHIT[%s:%d]: " + "(PP[%016lx] CACH[%016lx] CTX[%x] g1g3[%016lx] g2[%016lx]) ", + current->comm, current->pid, + pgd_phys, pgd_cache, ctx, g1_or_g3, g2); + printk("SHIT[%s:%d]: " + "[PP[%016lx] CACH[%016lx] CTX[%x:%x]] PC[%016lx:%016lx]\n", + current->comm, current->pid, + __pa(current->mm->pgd), + pgd_val(current->mm->pgd[0]), + current->mm->context & 0x3ff, + current->tss.ctx, + regs->tpc, regs->tnpc); + show_regs(regs); +#if 1 + __sti(); + while(1) + barrier(); +#endif + } +} +#endif + void bad_trap (struct pt_regs *regs, long lvl) { lock_kernel (); @@ -205,7 +278,20 @@ void bad_trap_tl1 (struct pt_regs *regs, long lvl) unlock_kernel(); } -void data_access_exception (struct pt_regs *regs) +void instruction_access_exception (struct pt_regs *regs, + unsigned long sfsr, unsigned long sfar) +{ + lock_kernel(); +#if 1 + printk("instruction_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n", + sfsr, sfar); +#endif + die_if_kernel("Iax", regs); + unlock_kernel(); +} + +void data_access_exception (struct pt_regs *regs, + unsigned long sfsr, unsigned long sfar) { if (regs->tstate & TSTATE_PRIV) { /* Test if this comes from uaccess places. */ @@ -224,7 +310,17 @@ void data_access_exception (struct pt_regs *regs) regs->u_regs[UREG_G2] = g2; return; } + /* Shit... */ +#if 1 + printk("data_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n", + sfsr, sfar); +#endif + die_if_kernel("Dax", regs); } +#if 0 + else + rtrap_check(regs); +#endif lock_kernel(); force_sig(SIGSEGV, current); unlock_kernel(); @@ -286,7 +382,7 @@ void do_dae(struct pt_regs *regs) unlock_kernel(); } -void instruction_access_exception (struct pt_regs *regs) +void do_iae(struct pt_regs *regs) { clean_and_reenable_l1_caches(); @@ -295,13 +391,6 @@ void instruction_access_exception (struct pt_regs *regs) unlock_kernel(); } -void do_iae(struct pt_regs *regs) -{ - lock_kernel(); - force_sig(SIGSEGV, current); - unlock_kernel(); -} - void do_fpe_common(struct pt_regs *regs) { if(regs->tstate & TSTATE_PRIV) { @@ -572,7 +661,7 @@ void cache_flush_trap(struct pt_regs *regs) #ifndef __SMP__ unsigned node = linux_cpus[get_cpuid()].prom_node; #else -#error SMP not supported on sparc64 yet +#error cache_flush_trap not supported on sparc64/SMP yet #endif #if 0 diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 87f282fa1..656d29454 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.25 1998/05/23 18:24:53 jj Exp $ +/* $Id: ttable.S,v 1.27 1998/09/25 01:09:10 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -11,7 +11,7 @@ sparc64_ttable_tl0: tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) -tl0_iax: ACCESS_EXCEPTION_TRAP(instruction_access_exception) +tl0_iax: TRAP_NOSAVE(__do_instruction_access_exception) tl0_resv009: BTRAP(0x9) tl0_iae: TRAP(do_iae) tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) @@ -28,14 +28,14 @@ tl0_cwin: CLEAN_WINDOW tl0_div0: TRAP(do_div0) tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) tl0_resv02f: BTRAP(0x2f) -tl0_dax: ACCESS_EXCEPTION_TRAP(data_access_exception) +tl0_dax: TRAP_NOSAVE(__do_data_access_exception) tl0_resv031: BTRAP(0x31) tl0_dae: TRAP(do_dae) tl0_resv033: BTRAP(0x33) tl0_mna: TRAP_NOSAVE(do_mna) tl0_lddfmna: TRAP_NOSAVE(do_lddfmna) tl0_stdfmna: TRAP_NOSAVE(do_stdfmna) -tl0_privact: TRAP(do_privact) +tl0_privact: TRAP_NOSAVE(__do_privact) tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d) tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) tl0_irq1: TRAP_IRQ(handler_irq, 1) TRAP_IRQ(handler_irq, 2) @@ -160,7 +160,7 @@ tl0_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8) sparc64_ttable_tl1: tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3) tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7) -tl1_iax: ACCESS_EXCEPTION_TRAPTL1(instruction_access_exception) +tl1_iax: TRAP_NOSAVE(__do_instruction_access_exception_tl1) tl1_resv009: BTRAPTL1(0x9) tl1_iae: TRAPTL1(do_iae_tl1) tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf) @@ -178,7 +178,7 @@ tl1_cwin: CLEAN_WINDOW tl1_div0: TRAPTL1(do_div0_tl1) tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c) tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f) -tl1_dax: ACCESS_EXCEPTION_TRAPTL1(data_access_exception) +tl1_dax: TRAP_NOSAVE(__do_data_access_exception_tl1) tl1_resv031: BTRAPTL1(0x31) tl1_dae: TRAPTL1(do_dae_tl1) tl1_resv033: BTRAPTL1(0x33) diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 50de6cfd5..d32309b9d 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.10 1998/06/19 13:00:32 jj Exp $ +/* $Id: unaligned.c,v 1.13 1998/10/07 22:43:13 davem Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -58,9 +58,10 @@ static inline int decode_access_size(unsigned int insn) { unsigned int tmp; - if (((insn >> 19) & 0xf) == 14) - return 8; /* stx* */ - tmp = (insn >> 19) & 3; + tmp = ((insn >> 19) & 0xf); + if (tmp == 11 || tmp == 14) /* ldx/stx */ + return 8; + tmp &= 3; if(!tmp) return 4; else if(tmp == 3) @@ -91,10 +92,13 @@ static inline int decode_signedness(unsigned int insn) } static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2, - unsigned int rd) + unsigned int rd, int from_kernel) { if(rs2 >= 16 || rs1 >= 16 || rd >= 16) { - flushw_user(); + if(from_kernel != 0) + __asm__ __volatile__("flushw"); + else + flushw_user(); } } @@ -149,12 +153,13 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs, { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; + int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; if(insn & 0x2000) { - maybe_flush_windows(rs1, 0, rd); + maybe_flush_windows(rs1, 0, rd, from_kernel); return (fetch_reg(rs1, regs) + sign_extend_imm13(insn)); } else { - maybe_flush_windows(rs1, rs2, rd); + maybe_flush_windows(rs1, rs2, rd, from_kernel); return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs)); } } @@ -430,12 +435,13 @@ int handle_popc(u32 insn, struct pt_regs *regs) { u64 value; int ret, i, rd = ((insn >> 25) & 0x1f); + int from_kernel = (regs->tstate & TSTATE_PRIV) != 0; if (insn & 0x2000) { - maybe_flush_windows(0, 0, rd); + maybe_flush_windows(0, 0, rd, from_kernel); value = sign_extend_imm13(insn); } else { - maybe_flush_windows(0, insn & 0x1f, rd); + maybe_flush_windows(0, insn & 0x1f, rd, from_kernel); value = fetch_reg(insn & 0x1f, regs); } for (ret = 0, i = 0; i < 16; i++) { @@ -583,7 +589,8 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr pc = (u32)pc; if (get_user(insn, (u32 *)pc) != -EFAULT) { asi = sfsr >> 16; - if (asi > ASI_SNFL) + if ((asi > ASI_SNFL) || + (asi < ASI_P)) goto daex; if (get_user(first, (u32 *)sfar) || get_user(second, (u32 *)(sfar + 4))) { @@ -637,7 +644,8 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr asi = sfsr >> 16; value = 0; flag = (freg < 32) ? FPRS_DL : FPRS_DU; - if (asi > ASI_SNFL) + if ((asi > ASI_SNFL) || + (asi < ASI_P)) goto daex; save_and_clear_fpu(); if (current->tss.fpsaved[0] & flag) diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index fd75011fd..5bf82db59 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.24 1998/06/12 14:54:19 jj Exp $ +/* $Id: winfixup.S,v 1.27 1998/09/25 01:09:14 davem Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -27,7 +27,7 @@ * These are layed out in a special way for cache reasons, * don't touch... */ - .globl winfix_trampoline, fill_fixup, spill_fixup + .globl fill_fixup, spill_fixup fill_fixup: rdpr %tstate, %g1 andcc %g1, TSTATE_PRIV, %g0 @@ -192,8 +192,8 @@ fill_fixup_mna: stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus. flush %g6 ! Flush instruction buffers rdpr %pstate, %l1 ! Prepare to change globals. - mov %g4, %o5 ! Setup args for - mov %g5, %o4 ! final call to do_sparc64_fault. + mov %g4, %o2 ! Setup args for + mov %g5, %o1 ! final call to mem_address_unaligned. andn %l1, PSTATE_MM, %l1 ! We want to be in RMO mov %g6, %o7 ! Stash away current. @@ -261,8 +261,117 @@ window_mna_from_user_common: sethi %hi(109f), %g7 ba,pt %xcc, etrap 109: or %g7, %lo(109b), %g7 + mov %l4, %o2 + mov %l5, %o1 call mem_address_unaligned add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 + /* These are only needed for 64-bit mode processes which + * put their stack pointer into the VPTE area and there + * happens to be a VPTE tlb entry mapped there during + * a spill/fill trap to that stack frame. + */ + .globl winfix_dax, fill_fixup_dax, spill_fixup_dax +winfix_dax: + andn %g3, 0x7f, %g3 + add %g3, 0x74, %g3 + wrpr %g3, %tnpc + done +fill_fixup_dax: + rdpr %tstate, %g1 + andcc %g1, TSTATE_PRIV, %g0 + be,pt %xcc, window_dax_from_user_common + and %g1, TSTATE_CWP, %g1 + + /* Please, see fill_fixup commentary about why we must preserve + * %l5 and %l6 to preserve absolute correct semantics. + */ + rdpr %wstate, %g2 ! Grab user mode wstate. + wrpr %g1, %cwp ! Get into the right window. + sll %g2, 3, %g2 ! NORMAL-->OTHER + wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. + + wrpr %g2, 0x0, %wstate ! This must be consistant. + wrpr %g0, 0x0, %otherwin ! We know this. + mov PRIMARY_CONTEXT, %g1 ! Change contexts... + stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus. + flush %g6 ! Flush instruction buffers + rdpr %pstate, %l1 ! Prepare to change globals. + mov %g4, %o1 ! Setup args for + mov %g5, %o2 ! final call to data_access_exception. + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO + + mov %g6, %o7 ! Stash away current. + wrpr %g0, 0x0, %tl ! Out of trap levels. + wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate + sethi %uhi(PAGE_OFFSET), %g4 ! Set page_offset global reg. + mov %o7, %g6 ! Get current back. + sllx %g4, 32, %g4 ! Finish it. + call data_access_exception + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + + b,pt %xcc, rtrap + nop ! yes, the nop is correct +spill_fixup_dax: + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + andcc %g1, SPARC_FLAG_32BIT, %g0 + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + sll %g1, 3, %g3 + add %g6, %g3, %g3 + stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] + + sll %g1, 7, %g3 + bne,pt %xcc, 1f + add %g6, %g3, %g3 + stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + + stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] + stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] + stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] + stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] + stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] + + stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] + stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] + stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] + b,pt %xcc, 2f + add %g1, 1, %g1 +1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] + std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] + std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] + + std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] + std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] + std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] + std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] + std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] + add %g1, 1, %g1 +2: sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] + rdpr %tstate, %g1 + + andcc %g1, TSTATE_PRIV, %g0 + saved + be,pn %xcc, window_dax_from_user_common + and %g1, TSTATE_CWP, %g1 + retry +window_dax_from_user_common: + wrpr %g1, %cwp + sethi %hi(109f), %g7 + ba,pt %xcc, etrap +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call data_access_exception + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, rtrap + clr %l6 + diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index a580f7ae4..2a3c63e91 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -1,10 +1,10 @@ -# $Id: Makefile,v 1.16 1998/06/12 14:53:53 jj Exp $ +# $Id: Makefile,v 1.18 1998/10/13 09:07:24 davem Exp $ # Makefile for Sparc library files.. # CFLAGS := $(CFLAGS) -OBJS = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \ +OBJS = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o @@ -16,10 +16,10 @@ VIScopy.o: VIScopy.S VIS.h VISbzero.o: VISbzero.S VIS.h .S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s .S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o dep: diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S index 7f2f497cd..cdabf5c98 100644 --- a/arch/sparc64/lib/VIScopy.S +++ b/arch/sparc64/lib/VIScopy.S @@ -1,4 +1,4 @@ -/* $Id: VIScopy.S,v 1.18 1998/06/12 14:53:55 jj Exp $ +/* $Id: VIScopy.S,v 1.19 1998/10/19 21:52:19 davem Exp $ * VIScopy.S: High speed copy operations utilizing the UltraSparc * Visual Instruction Set. * @@ -480,7 +480,7 @@ vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis vis01:FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_SYNC(o0, f48) membar #Sync FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_JUMP(o0, f48, finish_f0) membar #Sync vis02:FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, check_finish_f16) add %o2, %g3, %g7 + FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, finish_f16) membar #Sync vis03:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_SYNC(o0, f48) membar #Sync FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_JUMP(o0, f48, finish_f32) membar #Sync VISLOOP_PAD @@ -569,18 +569,7 @@ finish_f8: FINISH_VISCHUNK(o0, f8, f10, g3) finish_f10: FINISH_VISCHUNK(o0, f10, f12, g3) finish_f12: FINISH_VISCHUNK(o0, f12, f14, g3) finish_f14: UNEVEN_VISCHUNK(o0, f14, f0, g3) -/* This is a special hack to speed up 8K page copy */ -check_finish_f16: - andcc %g1, 7, %g0 - bne,pn %icc, finish_f16 - cmp %g7, 0x40 - bne,pn %icc, finish_f16 - FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) - membar #Sync - EXVIS1(STBLK %f48, [%o0] ASIBLK) - b,pt %xcc, vis_ret -finish_f16: membar #Sync - FINISH_VISCHUNK(o0, f16, f18, g3) +finish_f16: FINISH_VISCHUNK(o0, f16, f18, g3) finish_f18: FINISH_VISCHUNK(o0, f18, f20, g3) finish_f20: FINISH_VISCHUNK(o0, f20, f22, g3) finish_f22: FINISH_VISCHUNK(o0, f22, f24, g3) diff --git a/arch/sparc64/lib/VISsave.S b/arch/sparc64/lib/VISsave.S index 10d127bb5..a189d0db6 100644 --- a/arch/sparc64/lib/VISsave.S +++ b/arch/sparc64/lib/VISsave.S @@ -1,4 +1,4 @@ -/* $Id: VISsave.S,v 1.2 1998/06/19 12:14:25 jj Exp $ +/* $Id: VISsave.S,v 1.3 1998/10/21 10:36:39 jj Exp $ * VISsave.S: Code for saving FPU register state for * VIS routines. One should not call this directly, * but use macros provided in <asm/visasm.h>. @@ -76,11 +76,13 @@ vis1: ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3 sll %g1, 5, %g1 add %g6, AOFF_task_fpregs+0xc0, %g3 + wr %g0, FPRS_FEF, %fprs membar #StoreStore | #LoadStore stda %f32, [%g2 + %g1] ASI_BLK_P stda %f48, [%g3 + %g1] ASI_BLK_P membar #Sync jmpl %g7 + %g0, %g0 + nop .align 32 diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S index c57f0aefc..cc189ce2d 100644 --- a/arch/sparc64/lib/blockops.S +++ b/arch/sparc64/lib/blockops.S @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.14 1998/06/12 14:53:46 jj Exp $ +/* $Id: blockops.S,v 1.16 1998/10/20 03:09:04 jj Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,9 @@ #include "VIS.h" #include <asm/visasm.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/asm_offsets.h> #define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7) \ fmovd %reg0, %f48; fmovd %reg1, %f50; \ @@ -14,12 +17,47 @@ fmovd %reg4, %f56; fmovd %reg5, %f58; \ fmovd %reg6, %f60; fmovd %reg7, %f62; +#define TLBTEMP_BASE (8 * 1024 * 1024) +#define DCACHE_SIZE (PAGE_SIZE * 2) +#define TLBTEMP_ENT1 (61 << 3) +#define TLBTEMP_ENT2 (62 << 3) +#define TLBTEMP_ENTSZ (1 << 3) + .text .align 32 .globl copy_page .type copy_page,@function copy_page: /* %o0=dest, %o1=src */ VISEntry + ldx [%g6 + AOFF_task_mm], %o2 + sub %o0, %g4, %g1 + sethi %uhi(_PAGE_VALID), %g3 + sub %o1, %g4, %g2 + sllx %g3, 32, %g3 + ldx [%o2 + AOFF_mm_segments], %o0 + or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3 + or %g1, %g3, %g1 + or %g2, %g3, %g2 + mov TLB_TAG_ACCESS, %o2 + sethi %hi(TLBTEMP_BASE), %o3 + sethi %hi(DCACHE_SIZE), %o1 + add %o0, %o3, %o0 + add %o0, %o1, %o1 + sethi %hi(TLBTEMP_ENT1), %o3 + rdpr %pstate, %g3 + wrpr %g3, PSTATE_IE, %pstate + ldxa [%o3] ASI_DTLB_TAG_READ, %o4 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %o5 + stxa %o0, [%o2] ASI_DMMU + stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + add %o3, (TLBTEMP_ENTSZ), %o3 + ldxa [%o3] ASI_DTLB_TAG_READ, %g5 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 + stxa %o1, [%o2] ASI_DMMU + stxa %g2, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + membar #LoadStore | #StoreStore | #StoreLoad ldda [%o1] ASI_BLK_P, %f0 add %o1, 0x40, %o1 @@ -50,15 +88,44 @@ copy_page: /* %o0=dest, %o1=src */ stda %f0, [%o0] ASI_BLK_P add %o0, 0x40, %o0 stda %f16, [%o0] ASI_BLK_P - membar #StoreStore | #StoreLoad + membar #Sync + VISExit + + mov TLB_TAG_ACCESS, %o2 + stxa %g5, [%o2] ASI_DMMU + stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + sub %o3, (TLBTEMP_ENTSZ), %o3 + stxa %o4, [%o2] ASI_DMMU + stxa %o5, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync jmpl %o7 + 0x8, %g0 - VISExit + wrpr %g3, 0x0, %pstate .align 32 - .globl __bzero_1page - .type __bzero_1page,@function -__bzero_1page: /* %o0=dest */ + .globl clear_page + .type clear_page,@function +clear_page: /* %o0=dest */ VISEntryHalf + ldx [%g6 + AOFF_task_mm], %o2 + sub %o0, %g4, %g1 + sethi %uhi(_PAGE_VALID), %g3 + sllx %g3, 32, %g3 + or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3 + ldx [%o2 + AOFF_mm_segments], %o0 + or %g1, %g3, %g1 + mov TLB_TAG_ACCESS, %o2 + sethi %hi(TLBTEMP_BASE), %o3 + add %o0, %o3, %o0 + sethi %hi(TLBTEMP_ENT2), %o3 + rdpr %pstate, %g3 + wrpr %g3, PSTATE_IE, %pstate + ldxa [%o3] ASI_DTLB_TAG_READ, %g5 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 + stxa %o0, [%o2] ASI_DMMU + stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + fzero %f0 ! FPA Group mov 32, %o1 ! IEU0 fzero %f2 ! FPA Group @@ -79,6 +146,11 @@ __bzero_1page: /* %o0=dest */ subcc %o1, 1, %o1 ! IEU1 bne,pt %icc, 1b ! CTI add %o0, 0x100, %o0 ! IEU0 Group - membar #StoreStore | #StoreLoad ! LSU Group - jmpl %o7 + 0x8, %g0 ! CTI Group brk forced - VISExitHalf + membar #Sync ! LSU Group + VISExitHalf + + stxa %g5, [%o2] ASI_DMMU + stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + jmpl %o7 + 0x8, %g0 + wrpr %g3, 0x0, %pstate diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S index 2e22ec2d8..ea732b367 100644 --- a/arch/sparc64/lib/checksum.S +++ b/arch/sparc64/lib/checksum.S @@ -180,7 +180,7 @@ ccfold: sllx %sum, 32, %o0 ! IEU0 Group bcs,a,pn %xcc, 1f ! CTI add %o0, 1, %o0 ! IEU1 4 clocks (mispredict) 1: retl ! CTI Group brk forced - sllx %g4, 32,%g4 ! IEU0 Group + sllx %g4, 32, %g4 ! IEU0 Group ccslow: mov 0, %g5 brlez,pn %len, 4f @@ -268,8 +268,9 @@ cpc_handler: sub %g0, EFAULT, %g2 brnz,a,pt %g1, 1f st %g2, [%g1] -1: retl - nop +1: sethi %uhi(PAGE_OFFSET), %g4 + retl + sllx %g4, 32, %g4 .section __ex_table .align 4 diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c new file mode 100644 index 000000000..69286c4b7 --- /dev/null +++ b/arch/sparc64/lib/debuglocks.c @@ -0,0 +1,278 @@ +/* $Id: debuglocks.c,v 1.2 1998/10/13 09:07:27 davem Exp $ + * debuglocks.c: Debugging versions of SMP locking primitives. + * + * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <asm/system.h> +#include <asm/spinlock.h> + +#ifdef __SMP__ + +/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */ +#ifdef SPIN_LOCK_DEBUG + +#define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC)) + +static inline void show (char *str, spinlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n", + str, lock, cpu, (unsigned int) caller, + lock->owner_pc, lock->owner_cpu); +} + +static inline void show_read (char *str, rwlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n", + str, lock, cpu, (unsigned int) caller, + lock->writer_pc, lock->writer_cpu); +} + +static inline void show_write (char *str, rwlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08x\n", + str, lock, cpu, (unsigned int) caller); + printk("Writer: PC(%08x):CPU(%x)\n", + lock->writer_pc, lock->writer_cpu); + printk("Readers: 0[%08x] 1[%08x] 2[%08x] 4[%08x]\n", + lock->reader_pc[0], lock->reader_pc[1], + lock->reader_pc[2], lock->reader_pc[3]); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +void _do_spin_lock(spinlock_t *lock, char *str) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + GET_CALLER(caller); +again: + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (val) + : "r" (&(lock->lock)) + : "memory"); + membar("#StoreLoad | #StoreStore"); + if (val) { + while (lock->lock) { + if (!--stuck) { + show(str, lock, caller); + stuck = INIT_STUCK; + } + membar("#LoadLoad"); + } + goto again; + } + lock->owner_pc = ((unsigned int)caller); + lock->owner_cpu = cpu; +} + +int _spin_trylock(spinlock_t *lock) +{ + unsigned long val, caller; + int cpu = smp_processor_id(); + + GET_CALLER(caller); + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (val) + : "r" (&(lock->lock)) + : "memory"); + membar("#StoreLoad | #StoreStore"); + if (!val) { + lock->owner_pc = ((unsigned int)caller); + lock->owner_cpu = cpu; + } + return val == 0; +} + +void _do_spin_unlock(spinlock_t *lock) +{ + lock->owner_pc = 0; + lock->owner_cpu = NO_PROC_ID; + membar("#StoreStore | #LoadStore"); + lock->lock = 0; +} + +/* Keep INIT_STUCK the same... */ + +void _do_read_lock (rwlock_t *rw, char *str) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + GET_CALLER(caller); +wlock_again: + /* Wait for any writer to go away. */ + while (((long)(rw->lock)) < 0) { + if (!--stuck) { + show_read(str, rw, caller); + stuck = INIT_STUCK; + } + membar("#LoadLoad"); + } + /* Try once to increment the counter. */ + __asm__ __volatile__(" + ldx [%0], %%g5 + brlz,a,pn %%g5, 2f + mov 1, %0 + add %%g5, 1, %%g7 + casx [%0], %%g5, %%g7 + sub %%g5, %%g7, %0 +2:" : "=r" (val) + : "0" (&(rw->lock)) + : "g5", "g7", "memory"); + membar("#StoreLoad | #StoreStore"); + if (val) + goto wlock_again; + rw->reader_pc[cpu] = ((unsigned int)caller); +} + +void _do_read_unlock (rwlock_t *rw, char *str) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + GET_CALLER(caller); + + /* Drop our identity _first_. */ + rw->reader_pc[cpu] = 0; +runlock_again: + /* Spin trying to decrement the counter using casx. */ + __asm__ __volatile__(" + ldx [%0], %%g5 + sub %%g5, 1, %%g7 + casx [%0], %%g5, %%g7 + membar #StoreLoad | #StoreStore + sub %%g5, %%g7, %0 +" : "=r" (val) + : "0" (&(rw->lock)) + : "g5", "g7", "memory"); + if (val) { + if (!--stuck) { + show_read(str, rw, caller); + stuck = INIT_STUCK; + } + goto runlock_again; + } +} + +void _do_write_lock (rwlock_t *rw, char *str) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + GET_CALLER(caller); +wlock_again: + /* Spin while there is another writer. */ + while (((long)rw->lock) < 0) { + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + membar("#LoadLoad"); + } + + /* Try to acuire the write bit. */ + __asm__ __volatile__(" + mov 1, %%g3 + sllx %%g3, 63, %%g3 + ldx [%0], %%g5 + brlz,pn %%g5, 1f + or %%g5, %%g3, %%g7 + casx [%0], %%g5, %%g7 + membar #StoreLoad | #StoreStore + ba,pt %%xcc, 2f + sub %%g5, %%g7, %0 +1: mov 1, %0 +2:" : "=r" (val) + : "0" (&(rw->lock)) + : "g3", "g5", "g7", "memory"); + if (val) { + /* We couldn't get the write bit. */ + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + goto wlock_again; + } + if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) { + /* Readers still around, drop the write + * lock, spin, and try again. + */ + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + __asm__ __volatile__(" + mov 1, %%g3 + sllx %%g3, 63, %%g3 +1: ldx [%0], %%g5 + andn %%g5, %%g3, %%g7 + casx [%0], %%g5, %%g7 + cmp %%g5, %%g7 + bne,pn %%xcc, 1b + membar #StoreLoad | #StoreStore" + : /* no outputs */ + : "r" (&(rw->lock)) + : "g3", "g5", "g7", "cc", "memory"); + while(rw->lock != 0) { + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + membar("#LoadLoad"); + } + goto wlock_again; + } + + /* We have it, say who we are. */ + rw->writer_pc = ((unsigned int)caller); + rw->writer_cpu = cpu; +} + +void _do_write_unlock(rwlock_t *rw) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + + GET_CALLER(caller); + + /* Drop our identity _first_ */ + rw->writer_pc = 0; + rw->writer_cpu = NO_PROC_ID; +wlock_again: + __asm__ __volatile__(" + mov 1, %%g3 + sllx %%g3, 63, %%g3 + ldx [%0], %%g5 + andn %%g5, %%g3, %%g7 + casx [%0], %%g5, %%g7 + membar #StoreLoad | #StoreStore + sub %%g5, %%g7, %0 +" : "=r" (val) + : "0" (&(rw->lock)) + : "g3", "g5", "g7", "memory"); + if (val) { + if (!--stuck) { + show_write("write_unlock", rw, caller); + stuck = INIT_STUCK; + } + goto wlock_again; + } +} + +#endif /* SPIN_LOCK_DEBUG */ +#endif /* __SMP__ */ diff --git a/arch/sparc64/lib/locks.S b/arch/sparc64/lib/locks.S deleted file mode 100644 index 7b2bdba62..000000000 --- a/arch/sparc64/lib/locks.S +++ /dev/null @@ -1,76 +0,0 @@ -/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $ - * locks.S: SMP low-level lock primitives on Sparc64. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#include <asm/asm_offsets.h> -#include <asm/ptrace.h> -#include <asm/smp.h> - - .text - .align 32 - -___lk_busy_spin: - ldub [%g1 + 0], %g2 - brnz,pt %g2, ___lk_busy_spin - membar #LoadLoad - b,pt %xcc, 1f - ldstub [%g1 + 0], %g2 - - .globl ___lock_kernel -___lock_kernel: - addcc %g2, -1, %g2 - rdpr %pil, %g3 - bcs,a,pn %icc, 9f - stw %g2, [%g6 + AOFF_task_lock_depth] - wrpr %g0, 15, %pil - ldstub [%g1 + 0], %g2 -1: brnz,pn %g2, ___lk_busy_spin - membar #StoreLoad | #StoreStore - lduw [%g6 + AOFF_task_processor], %g2 - stb %g2, [%g1 + 1] -2: mov -1, %g2 - stw %g2, [%g6 + AOFF_task_lock_depth] - wrpr %g3, 0, %pil -9: jmpl %o7 + 0x8, %g0 - mov %g5, %o7 - - .globl ___lock_reacquire_kernel -___lock_reacquire_kernel: - rdpr %pil, %g3 - wrpr %g0, 15, %pil - stw %g2, [%g6 + AOFF_task_lock_depth] - ldstub [%g1 + 0], %g2 -1: brz,pt %g2, 3f - membar #StoreLoad | #StoreStore -2: ldub [%g1 + 0], %g2 - brnz,pt %g2, 2b - membar #LoadLoad - b,pt %xcc, 1b - ldstub [%g1 + 0], %g2 -3: lduw [%g6 + AOFF_task_processor], %g2 - stb %g2, [%g1 + 1] - wrpr %g3, 0, %pil - jmpl %o7 + 0x8, %g0 - mov %g5, %o7 - -#undef NO_PROC_ID -#define NO_PROC_ID 0xff - - .globl ___unlock_kernel -___unlock_kernel: - addcc %g2, 1, %g2 - rdpr %pil, %g3 - bne,a,pn %icc, 1f - stw %g2, [%g6 + AOFF_task_lock_depth] - wrpr 15, %pil - mov NO_PROC_ID, %g2 - stb %g2, [%g1 + 1] - membar #StoreStore | #LoadStore - stb %g0, [%g1 + 0] - stw %g0, [%g6 + AOFF_task_lock_depth] - wrpr %g3, 0, %pil -1: jmpl %o7 + 0x8, %g0 - mov %g5, %o7 - diff --git a/arch/sparc64/lib/strlen.S b/arch/sparc64/lib/strlen.S index 5f2ec6bb4..55527f639 100644 --- a/arch/sparc64/lib/strlen.S +++ b/arch/sparc64/lib/strlen.S @@ -8,9 +8,10 @@ #define LO_MAGIC 0x01010101 #define HI_MAGIC 0x80808080 - .align 4 - .global strlen + .align 32 + .global strlen, __strlen strlen: +__strlen: mov %o0, %o1 andcc %o0, 3, %g0 be,pt %icc, 9f diff --git a/arch/sparc64/math-emu/Makefile b/arch/sparc64/math-emu/Makefile index 8f695b1e2..1f5a19499 100644 --- a/arch/sparc64/math-emu/Makefile +++ b/arch/sparc64/math-emu/Makefile @@ -16,10 +16,4 @@ O_OBJS := math.o fabsq.o faddq.o fdivq.o fdmulq.o fitoq.o \ fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o \ fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o -.S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s - -.S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o - include $(TOPDIR)/Rules.make diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c index 6dfaca524..a0d1c8144 100644 --- a/arch/sparc64/mm/asyncd.c +++ b/arch/sparc64/mm/asyncd.c @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.4 1998/05/24 02:53:58 davem Exp $ +/* $Id: asyncd.c,v 1.5 1998/09/13 04:30:33 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 21389e397..737872fb2 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.21 1998/03/25 10:43:20 jj Exp $ +/* $Id: fault.c,v 1.26 1998/11/08 11:14:03 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -100,49 +100,38 @@ void unhandled_fault(unsigned long address, struct task_struct *tsk, (unsigned long) tsk->mm->context); printk(KERN_ALERT "tsk->mm->pgd = %016lx\n", (unsigned long) tsk->mm->pgd); + lock_kernel(); die_if_kernel("Oops", regs); -} - -asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, - unsigned long address) -{ - unsigned long g2; - int i; - unsigned insn; - struct pt_regs regs; - - i = search_exception_table (ret_pc, &g2); - switch (i) { - /* load & store will be handled by fixup */ - case 3: return 3; - /* store will be handled by fixup, load will bump out */ - /* for _to_ macros */ - case 1: insn = *(unsigned *)pc; if ((insn >> 21) & 1) return 1; break; - /* load will be handled by fixup, store will bump out */ - /* for _from_ macros */ - case 2: insn = *(unsigned *)pc; - if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; - break; - default: break; - } - memset (®s, 0, sizeof (regs)); - regs.tpc = pc; - regs.tnpc = pc + 4; - /* FIXME: Should set up regs->tstate? */ - unhandled_fault (address, current, ®s); - /* Not reached */ - return 0; + unlock_kernel(); } /* #define DEBUG_EXCEPTIONS */ +/* #define DEBUG_LOCKUPS */ asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, int write) { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; +#ifdef DEBUG_LOCKUPS + static unsigned long lastaddr, lastpc; + static int lastwrite, lockcnt; +#endif - lock_kernel(); down(&mm->mmap_sem); +#ifdef DEBUG_LOCKUPS + if (regs->tpc == lastpc && address == lastaddr && write == lastwrite) { + lockcnt++; + if (lockcnt == 100000) { + printk("do_sparc64_fault: possible fault loop for %016lx %s\n", address, write ? "write" : "read"); + show_regs(regs); + } + } else { + lastpc = regs->tpc; + lastaddr = address; + lastwrite = write; + lockcnt = 0; + } +#endif vma = find_vma(mm, address); if(!vma) goto bad_area; @@ -165,9 +154,11 @@ good_area: if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(current, vma, address, write); + current->mm->segments = (void *) (address & PAGE_SIZE); + if (!handle_mm_fault(current, vma, address, write)) + goto do_sigbus; up(&mm->mmap_sem); - goto out; + return; /* * Something tried to access memory that isn't in our memory map.. * Fix it, but check if it's kernel or user first.. @@ -175,6 +166,7 @@ good_area: bad_area: up(&mm->mmap_sem); +do_kernel_fault: { unsigned long g2 = regs->u_regs[UREG_G2]; @@ -204,16 +196,23 @@ bad_area: regs->tpc = fixup; regs->tnpc = regs->tpc + 4; regs->u_regs[UREG_G2] = g2; - goto out; + return; } } else { current->tss.sig_address = address; current->tss.sig_desc = SUBSIG_NOMAPPING; force_sig(SIGSEGV, current); - goto out; + return; } unhandled_fault (address, current, regs); } -out: - unlock_kernel(); + return; + +do_sigbus: + up(&mm->mmap_sem); + current->tss.sig_address = address; + current->tss.sig_desc = SUBSIG_MISCERROR; + force_sig(SIGBUS, current); + if (regs->tstate & TSTATE_PRIV) + goto do_kernel_fault; } diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c index 730e8cb32..0b869a2f2 100644 --- a/arch/sparc64/mm/generic.c +++ b/arch/sparc64/mm/generic.c @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.2 1997/07/01 09:11:42 jj Exp $ +/* $Id: generic.c,v 1.3 1998/10/27 23:28:07 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -41,10 +41,11 @@ static inline void forget_pte(pte_t page) unsigned long addr = pte_page(page); if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr))) return; - free_page(addr); - if (current->mm->rss <= 0) - return; - current->mm->rss--; + /* + * free_page() used to be able to clear swap cache + * entries. We may now have to do it manually. + */ + free_page_and_swap_cache(addr); return; } swap_free(pte_val(page)); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 035b023fc..236c866d6 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.93 1998/08/04 20:49:25 davem Exp $ +/* $Id: init.c,v 1.103 1998/10/20 03:09:12 jj Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -37,14 +37,14 @@ struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; /* Ugly, but necessary... -DaveM */ unsigned long phys_base; -unsigned long tlb_context_cache = CTX_FIRST_VERSION; +/* get_new_mmu_context() uses "cache + 1". */ +unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; /* References to section boundaries */ extern char __init_begin, __init_end, etext, __bss_start; int do_check_pgt_cache(int low, int high) { - struct page *page, *page2; int freed = 0; if(pgtable_cache_size > high) { @@ -59,6 +59,7 @@ int do_check_pgt_cache(int low, int high) } #ifndef __SMP__ if (pgd_cache_size > high / 4) { + struct page *page, *page2; for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) { if ((unsigned long)page->pprev_hash == 3) { if (page2) @@ -536,7 +537,7 @@ static inline void inherit_prom_mappings(void) if (pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, PMD_TABLE_SIZE); - clear_page(pmdp); + memset(pmdp, 0, PAGE_SIZE); pgd_set(pgdp, pmdp); } pmdp = pmd_offset(pgdp, vaddr); @@ -565,9 +566,9 @@ static void __flush_nucleus_vptes(void) unsigned long prom_reserved_base = 0xfffffffc00000000UL; int i; - __asm__ __volatile__("rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate\n\t" - "flushw" + __asm__ __volatile__("flushw\n\t" + "rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" : "=r" (pstate) : "i" (PSTATE_IE)); @@ -590,12 +591,17 @@ static void __flush_nucleus_vptes(void) } static int prom_ditlb_set = 0; -int prom_itlb_ent, prom_dtlb_ent; -unsigned long prom_itlb_tag, prom_itlb_data; -unsigned long prom_dtlb_tag, prom_dtlb_data; +struct prom_tlb_entry { + int tlb_ent; + unsigned long tlb_tag; + unsigned long tlb_data; +}; +struct prom_tlb_entry prom_itlb[8], prom_dtlb[8]; void prom_world(int enter) { + int i; + if (!prom_ditlb_set) return; if (enter) { @@ -603,29 +609,44 @@ void prom_world(int enter) __flush_nucleus_vptes(); /* Install PROM world. */ - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS), + for (i = 0; i < 8; i++) { + if (prom_dtlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(62, prom_dtlb_data); - membar("#Sync"); - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS), + membar("#Sync"); + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, + prom_dtlb[i].tlb_data); + membar("#Sync"); + } + + if (prom_itlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(62, prom_itlb_data); - membar("#Sync"); + membar("#Sync"); + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, + prom_itlb[i].tlb_data); + membar("#Sync"); + } + } } else { - __asm__ __volatile__("stxa %%g0, [%0] %1" + for (i = 0; i < 8; i++) { + if (prom_dtlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(62, 0x0UL); - membar("#Sync"); - __asm__ __volatile__("stxa %%g0, [%0] %1" + membar("#Sync"); + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); + membar("#Sync"); + } + if (prom_itlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(62, 0x0UL); - membar("#Sync"); + membar("#Sync"); + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL); + membar("#Sync"); + } + } } } @@ -639,8 +660,8 @@ void inherit_locked_prom_mappings(int save_p) * it (conveniently) fails to mention any of these in the * translations property. The only ones that matter are * the locked PROM tlb entries, so we impose the following - * irrecovable rule on the PROM, it is allowed 1 locked - * entry in the ITLB and 1 in the DTLB. + * irrecovable rule on the PROM, it is allowed 8 locked + * entries in the ITLB and 8 in the DTLB. * * Supposedly the upper 16GB of the address space is * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED @@ -649,17 +670,23 @@ void inherit_locked_prom_mappings(int save_p) * systems to coordinate mmu mappings is also COMPLETELY * UNDOCUMENTED!!!!!! Thanks S(t)un! */ + if (save_p) { + for(i = 0; i < 8; i++) { + prom_dtlb[i].tlb_ent = -1; + prom_itlb[i].tlb_ent = -1; + } + } for(i = 0; i < 63; i++) { unsigned long data; data = spitfire_get_dtlb_data(i); - if(!dtlb_seen && (data & _PAGE_L)) { + if(data & _PAGE_L) { unsigned long tag = spitfire_get_dtlb_tag(i); if(save_p) { - prom_dtlb_ent = i; - prom_dtlb_tag = tag; - prom_dtlb_data = data; + prom_dtlb[dtlb_seen].tlb_ent = i; + prom_dtlb[dtlb_seen].tlb_tag = tag; + prom_dtlb[dtlb_seen].tlb_data = data; } __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); @@ -667,18 +694,22 @@ void inherit_locked_prom_mappings(int save_p) spitfire_put_dtlb_data(i, 0x0UL); membar("#Sync"); - dtlb_seen = 1; - if(itlb_seen) + dtlb_seen++; + if(dtlb_seen > 7) break; } + } + for(i = 0; i < 63; i++) { + unsigned long data; + data = spitfire_get_itlb_data(i); - if(!itlb_seen && (data & _PAGE_L)) { + if(data & _PAGE_L) { unsigned long tag = spitfire_get_itlb_tag(i); if(save_p) { - prom_itlb_ent = i; - prom_itlb_tag = tag; - prom_itlb_data = data; + prom_itlb[itlb_seen].tlb_ent = i; + prom_itlb[itlb_seen].tlb_tag = tag; + prom_itlb[itlb_seen].tlb_data = data; } __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); @@ -686,15 +717,8 @@ void inherit_locked_prom_mappings(int save_p) spitfire_put_itlb_data(i, 0x0UL); membar("#Sync"); - /* Re-install it. */ - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(62, data); - membar("#Sync"); - itlb_seen = 1; - if(dtlb_seen) + itlb_seen++; + if(itlb_seen > 7) break; } } @@ -705,19 +729,41 @@ void inherit_locked_prom_mappings(int save_p) /* Give PROM back his world, done during reboots... */ void prom_reload_locked(void) { - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(prom_dtlb_ent, prom_dtlb_data); - membar("#Sync"); + int i; - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(prom_itlb_ent, prom_itlb_data); - membar("#Sync"); + for (i = 0; i < 8; i++) { + if (prom_dtlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, + prom_dtlb[i].tlb_data); + membar("#Sync"); + } + + if (prom_itlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, + prom_itlb[i].tlb_data); + membar("#Sync"); + } + } +} + +void __flush_dcache_range(unsigned long start, unsigned long end) +{ + unsigned long va; + int n = 0; + + for (va = start; va < end; va += 32) { + spitfire_put_dcache_tag(va & 0x3fe0, 0x0); + if (++n >= 512) + break; + } } void __flush_cache_all(void) @@ -735,9 +781,9 @@ void __flush_tlb_all(void) unsigned long pstate; int i; - __asm__ __volatile__("rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate\n\t" - "flushw" + __asm__ __volatile__("flushw\n\t" + "rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate" : "=r" (pstate) : "i" (PSTATE_IE)); for(i = 0; i < 64; i++) { @@ -831,7 +877,7 @@ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL); if(pmd) { - clear_page(pmd); + memset(pmd, 0, PAGE_SIZE); pgd_set(pgd, pmd); return pmd + offset; } @@ -844,7 +890,7 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL); if(pte) { - clear_page(pte); + memset(pte, 0, PAGE_SIZE); pmd_set(pmd, pte); return pte + offset; } @@ -862,13 +908,13 @@ allocate_ptable_skeleton(unsigned long start, unsigned long end)) pgdp = pgd_offset(init_task.mm, start); if (pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, PAGE_SIZE); - clear_page(pmdp); + memset(pmdp, 0, PAGE_SIZE); pgd_set(pgdp, pmdp); } pmdp = pmd_offset(pgdp, start); if (pmd_none(*pmdp)) { ptep = sparc_init_alloc(&mempool, PAGE_SIZE); - clear_page(ptep); + memset(ptep, 0, PAGE_SIZE); pmd_set(pmdp, ptep); } start = (start + PMD_SIZE) & PMD_MASK; @@ -913,7 +959,6 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr) pte_clear(ptep); } -#ifdef NOTUSED void sparc_ultra_dump_itlb(void) { int slot; @@ -933,17 +978,17 @@ void sparc_ultra_dump_dtlb(void) { int slot; - prom_printf ("Contents of dtlb: "); + printk ("Contents of dtlb: "); for (slot = 0; slot < 14; slot++) printk (" "); - prom_printf ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0)); + printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), + spitfire_get_dtlb_data(0)); for (slot = 1; slot < 64; slot+=3) { - prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", + printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot), slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1), slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2)); } } -#endif /* paging_init() sets up the page tables */ diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 683f4bcb1..4362a15b4 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.24 1998/05/22 11:02:56 davem Exp $ +/* $Id: ultra.S,v 1.31 1998/11/07 06:39:21 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -56,38 +56,43 @@ __flush_tlb_range_page_by_page: __flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ /*IC5*/ rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate + mov TLB_TAG_ACCESS, %g3 mov (62 << 3), %g2 1: ldxa [%g2] ASI_ITLB_TAG_READ, %o4 and %o4, 0x3ff, %o5 cmp %o5, %o0 bne,pt %icc, 2f - andn %o4, 0x3ff, %o4 -/*IC6*/ cmp %o4, %o1 +/*IC6*/ andn %o4, 0x3ff, %o4 + cmp %o4, %o1 blu,pt %xcc, 2f cmp %o4, %o3 blu,pn %xcc, 4f 2: ldxa [%g2] ASI_DTLB_TAG_READ, %o4 and %o4, 0x3ff, %o5 cmp %o5, %o0 - andn %o4, 0x3ff, %o4 -/*IC7*/ bne,pt %icc, 3f +/*IC7*/ andn %o4, 0x3ff, %o4 + bne,pt %icc, 3f cmp %o4, %o1 blu,pt %xcc, 3f cmp %o4, %o3 blu,pn %xcc, 5f nop 3: brnz,pt %g2, 1b - sub %g2, (1 << 3), %g2 -/*IC8*/ retl +/*IC8*/ sub %g2, (1 << 3), %g2 + retl wrpr %g1, 0x0, %pstate -4: stxa %g0, [%g2] ASI_ITLB_DATA_ACCESS +4: stxa %g0, [%g3] ASI_IMMU + stxa %g0, [%g2] ASI_ITLB_DATA_ACCESS ba,pt %xcc, 2b flush %g6 -5: stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS +5: stxa %g0, [%g3] ASI_DMMU +/*IC9*/ stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS ba,pt %xcc, 3b flush %g6 + + .align 32 __flush_tlb_mm_slow: -/*IC9*/ rdpr %pstate, %g1 +/*IC10*/rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o1] ASI_DMMU stxa %g0, [%g3] ASI_DMMU_DEMAP @@ -95,21 +100,25 @@ __flush_tlb_mm_slow: flush %g6 stxa %g2, [%o1] ASI_DMMU flush %g6 -/*IC10*/retl +/*IC11*/retl wrpr %g1, 0, %pstate + + .align 32 __flush_tlb_page_slow: - rdpr %pstate, %g1 +/*IC12*/rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o2] ASI_DMMU stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP flush %g6 -/*IC11*/stxa %g2, [%o2] ASI_DMMU + stxa %g2, [%o2] ASI_DMMU flush %g6 - retl +/*IC13*/retl wrpr %g1, 0, %pstate + + .align 32 __flush_tlb_range_pbp_slow: - rdpr %pstate, %g1 +/*IC13*/rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%o2] ASI_DMMU 2: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP @@ -117,11 +126,47 @@ __flush_tlb_range_pbp_slow: brnz,pt %o5, 2b sub %o5, %o4, %o5 flush %g6 -/*IC13*/stxa %g2, [%o2] ASI_DMMU +/*IC14*/stxa %g2, [%o2] ASI_DMMU flush %g6 retl wrpr %g1, 0x0, %pstate + .align 32 + .globl flush_icache_page +flush_icache_page: /* %o0 = phys_page */ + sethi %hi(1 << 13), %o2 ! IC_set bit + mov 1, %g1 + srlx %o0, 5, %o0 ! phys-addr comparitor + clr %o1 ! IC_addr + sllx %g1, 36, %g1 + sub %g1, 1, %g2 + andn %g2, 0xff, %g2 ! IC_tag mask + nop + +1: ldda [%o1] ASI_IC_TAG, %o4 + and %o5, %g2, %o5 + cmp %o5, %o0 + be,pn %xcc, iflush1 + nop +2: ldda [%o1 + %o2] ASI_IC_TAG, %o4 + and %o5, %g2, %o5 + cmp %o5, %o0 + + be,pn %xcc, iflush2 + nop +3: add %o1, 0x20, %o1 + cmp %o1, %o2 + bne,pt %xcc, 1b + nop + retl + nop +iflush1:stxa %g0, [%o1] ASI_IC_TAG + ba,pt %xcc, 2b + flush %g6 +iflush2:stxa %g0, [%o1 + %o2] ASI_IC_TAG + ba,pt %xcc, 3b + flush %g6 + #ifdef __SMP__ /* These are all called by the slaves of a cross call, at * trap level 1, with interrupts fully disabled. diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 8e7ff7700..340c27223 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.10 1998/07/21 10:36:29 jj Exp $ +/* $Id: misc.c,v 1.13 1998/10/13 14:03:49 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -40,25 +40,18 @@ extern int serial_console; /* Drop into the prom, with the chance to continue with the 'go' * prom command. */ -/* XXX Fix the pre and post calls as it locks up my Ultra at the moment -DaveM */ void prom_cmdline(void) { - extern void kernel_enter_debugger(void); - /* extern void install_obp_ticker(void); */ - /* extern void install_linux_ticker(void); */ unsigned long flags; - /* kernel_enter_debugger(); */ #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) prom_palette (1); #endif - /* install_obp_ticker(); */ - save_flags(flags); cli(); + __save_and_cli(flags); p1275_cmd ("enter", P1275_INOUT(0,0)); - restore_flags(flags); - /* install_linux_ticker(); */ + __restore_flags(flags); #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) prom_palette (0); @@ -78,7 +71,7 @@ again: /* Set prom sync handler to call function 'funcp'. */ void -prom_setsync(sync_func_t funcp) +prom_setcallback(callback_func_t funcp) { if(!funcp) return; p1275_cmd ("set-callback", P1275_ARG(0,P1275_ARG_IN_FUNCTION)| diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c index 722243e99..9b1fafa37 100644 --- a/arch/sparc64/prom/p1275.c +++ b/arch/sparc64/prom/p1275.c @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.13 1998/04/24 15:45:35 jj Exp $ +/* $Id: p1275.c,v 1.15 1998/10/13 14:03:47 davem Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -15,9 +15,10 @@ #include <asm/system.h> #include <asm/spitfire.h> #include <asm/pstate.h> +#include <asm/spinlock.h> struct { - long prom_sync_routine; /* 0x00 */ + long prom_callback; /* 0x00 */ void (*prom_cif_handler)(long *); /* 0x08 */ unsigned long prom_cif_stack; /* 0x10 */ unsigned long prom_args [23]; /* 0x18 */ @@ -31,29 +32,262 @@ void prom_cif_interface (void) __asm__ __volatile__ (" mov %0, %%o0 ldx [%%o0 + 0x010], %%o1 ! prom_cif_stack - save %%o1, -0xc0, %%sp + save %%o1, -0x190, %%sp ldx [%%i0 + 0x008], %%l2 ! prom_cif_handler rdpr %%pstate, %%l4 - mov %%g4, %%l0 - mov %%g6, %%l1 - wrpr %%l4, %1, %%pstate ! turn on address masking + wrpr %%g0, 0x15, %%pstate ! save alternate globals + stx %%g1, [%%sp + 2047 + 0x0b0] + stx %%g2, [%%sp + 2047 + 0x0b8] + stx %%g3, [%%sp + 2047 + 0x0c0] + stx %%g4, [%%sp + 2047 + 0x0c8] + stx %%g5, [%%sp + 2047 + 0x0d0] + stx %%g6, [%%sp + 2047 + 0x0d8] + stx %%g7, [%%sp + 2047 + 0x0e0] + wrpr %%g0, 0x814, %%pstate ! save interrupt globals + stx %%g1, [%%sp + 2047 + 0x0e8] + stx %%g2, [%%sp + 2047 + 0x0f0] + stx %%g3, [%%sp + 2047 + 0x0f8] + stx %%g4, [%%sp + 2047 + 0x100] + stx %%g5, [%%sp + 2047 + 0x108] + stx %%g6, [%%sp + 2047 + 0x110] + stx %%g7, [%%sp + 2047 + 0x118] + wrpr %%g0, 0x14, %%pstate ! save normal globals + stx %%g1, [%%sp + 2047 + 0x120] + stx %%g2, [%%sp + 2047 + 0x128] + stx %%g3, [%%sp + 2047 + 0x130] + stx %%g4, [%%sp + 2047 + 0x138] + stx %%g5, [%%sp + 2047 + 0x140] + stx %%g6, [%%sp + 2047 + 0x148] + stx %%g7, [%%sp + 2047 + 0x150] + wrpr %%g0, 0x414, %%pstate ! save mmu globals + stx %%g1, [%%sp + 2047 + 0x158] + stx %%g2, [%%sp + 2047 + 0x160] + stx %%g3, [%%sp + 2047 + 0x168] + stx %%g4, [%%sp + 2047 + 0x170] + stx %%g5, [%%sp + 2047 + 0x178] + stx %%g6, [%%sp + 2047 + 0x180] + stx %%g7, [%%sp + 2047 + 0x188] + mov %%g1, %%l0 ! also save to locals, so we can handle + mov %%g2, %%l1 ! tlb faults later on, when accessing + mov %%g3, %%l3 ! the stack. + mov %%g7, %%l5 + wrpr %%l4, %1, %%pstate ! turn off interrupts call %%l2 add %%i0, 0x018, %%o0 ! prom_args - wrpr %%l4, 0, %%pstate ! put pstate back - mov %%l0, %%g4 + wrpr %%g0, 0x414, %%pstate ! restore mmu globals + mov %%l0, %%g1 + mov %%l1, %%g2 + mov %%l3, %%g3 + mov %%l5, %%g7 + wrpr %%g0, 0x14, %%pstate ! restore normal globals + ldx [%%sp + 2047 + 0x120], %%g1 + ldx [%%sp + 2047 + 0x128], %%g2 + ldx [%%sp + 2047 + 0x130], %%g3 + ldx [%%sp + 2047 + 0x138], %%g4 + ldx [%%sp + 2047 + 0x140], %%g5 + ldx [%%sp + 2047 + 0x148], %%g6 + ldx [%%sp + 2047 + 0x150], %%g7 + wrpr %%g0, 0x814, %%pstate ! restore interrupt globals + ldx [%%sp + 2047 + 0x0e8], %%g1 + ldx [%%sp + 2047 + 0x0f0], %%g2 + ldx [%%sp + 2047 + 0x0f8], %%g3 + ldx [%%sp + 2047 + 0x100], %%g4 + ldx [%%sp + 2047 + 0x108], %%g5 + ldx [%%sp + 2047 + 0x110], %%g6 + ldx [%%sp + 2047 + 0x118], %%g7 + wrpr %%g0, 0x15, %%pstate ! restore alternate globals + ldx [%%sp + 2047 + 0x0b0], %%g1 + ldx [%%sp + 2047 + 0x0b8], %%g2 + ldx [%%sp + 2047 + 0x0c0], %%g3 + ldx [%%sp + 2047 + 0x0c8], %%g4 + ldx [%%sp + 2047 + 0x0d0], %%g5 + ldx [%%sp + 2047 + 0x0d8], %%g6 + ldx [%%sp + 2047 + 0x0e0], %%g7 + wrpr %%l4, 0, %%pstate ! restore original pstate ret - restore %%l1, 0, %%g6 - save %%sp, -0xc0, %%sp ! If you change the offset of the save - rdpr %%pstate, %%l4 ! here, please change the 0x8038 - andn %%l4, %1, %%l3 ! constant below as well - wrpr %%l3, %%pstate - ldx [%%o0 + 0x000], %%l2 + restore + " : : "r" (&p1275buf), "i" (PSTATE_IE)); +} + +void prom_cif_callback(void) +{ + __asm__ __volatile__ (" + mov %0, %%o1 + save %%sp, -0x270, %%sp + rdpr %%pstate, %%l4 + wrpr %%g0, 0x15, %%pstate ! save PROM alternate globals + stx %%g1, [%%sp + 2047 + 0x0b0] + stx %%g2, [%%sp + 2047 + 0x0b8] + stx %%g3, [%%sp + 2047 + 0x0c0] + stx %%g4, [%%sp + 2047 + 0x0c8] + stx %%g5, [%%sp + 2047 + 0x0d0] + stx %%g6, [%%sp + 2047 + 0x0d8] + stx %%g7, [%%sp + 2047 + 0x0e0] + ! restore Linux alternate globals + ldx [%%sp + 2047 + 0x190], %%g1 + ldx [%%sp + 2047 + 0x198], %%g2 + ldx [%%sp + 2047 + 0x1a0], %%g3 + ldx [%%sp + 2047 + 0x1a8], %%g4 + ldx [%%sp + 2047 + 0x1b0], %%g5 + ldx [%%sp + 2047 + 0x1b8], %%g6 + ldx [%%sp + 2047 + 0x1c0], %%g7 + wrpr %%g0, 0x814, %%pstate ! save PROM interrupt globals + stx %%g1, [%%sp + 2047 + 0x0e8] + stx %%g2, [%%sp + 2047 + 0x0f0] + stx %%g3, [%%sp + 2047 + 0x0f8] + stx %%g4, [%%sp + 2047 + 0x100] + stx %%g5, [%%sp + 2047 + 0x108] + stx %%g6, [%%sp + 2047 + 0x110] + stx %%g7, [%%sp + 2047 + 0x118] + ! restore Linux interrupt globals + ldx [%%sp + 2047 + 0x1c8], %%g1 + ldx [%%sp + 2047 + 0x1d0], %%g2 + ldx [%%sp + 2047 + 0x1d8], %%g3 + ldx [%%sp + 2047 + 0x1e0], %%g4 + ldx [%%sp + 2047 + 0x1e8], %%g5 + ldx [%%sp + 2047 + 0x1f0], %%g6 + ldx [%%sp + 2047 + 0x1f8], %%g7 + wrpr %%g0, 0x14, %%pstate ! save PROM normal globals + stx %%g1, [%%sp + 2047 + 0x120] + stx %%g2, [%%sp + 2047 + 0x128] + stx %%g3, [%%sp + 2047 + 0x130] + stx %%g4, [%%sp + 2047 + 0x138] + stx %%g5, [%%sp + 2047 + 0x140] + stx %%g6, [%%sp + 2047 + 0x148] + stx %%g7, [%%sp + 2047 + 0x150] + ! restore Linux normal globals + ldx [%%sp + 2047 + 0x200], %%g1 + ldx [%%sp + 2047 + 0x208], %%g2 + ldx [%%sp + 2047 + 0x210], %%g3 + ldx [%%sp + 2047 + 0x218], %%g4 + ldx [%%sp + 2047 + 0x220], %%g5 + ldx [%%sp + 2047 + 0x228], %%g6 + ldx [%%sp + 2047 + 0x230], %%g7 + wrpr %%g0, 0x414, %%pstate ! save PROM mmu globals + stx %%g1, [%%sp + 2047 + 0x158] + stx %%g2, [%%sp + 2047 + 0x160] + stx %%g3, [%%sp + 2047 + 0x168] + stx %%g4, [%%sp + 2047 + 0x170] + stx %%g5, [%%sp + 2047 + 0x178] + stx %%g6, [%%sp + 2047 + 0x180] + stx %%g7, [%%sp + 2047 + 0x188] + ! restore Linux mmu globals + ldx [%%sp + 2047 + 0x238], %%o0 + ldx [%%sp + 2047 + 0x240], %%o1 + ldx [%%sp + 2047 + 0x248], %%l2 + ldx [%%sp + 2047 + 0x250], %%l3 + ldx [%%sp + 2047 + 0x258], %%l5 + ldx [%%sp + 2047 + 0x260], %%l6 + ldx [%%sp + 2047 + 0x268], %%l7 + ! switch to Linux tba + sethi %%hi(sparc64_ttable_tl0), %%l1 + rdpr %%tba, %%l0 ! save PROM tba + mov %%o0, %%g1 + mov %%o1, %%g2 + mov %%l2, %%g3 + mov %%l3, %%g4 + mov %%l5, %%g5 + mov %%l6, %%g6 + mov %%l7, %%g7 + wrpr %%l1, %%tba ! install Linux tba + wrpr %%l4, 0, %%pstate ! restore PSTATE + call prom_world + mov %%g0, %%o0 + ldx [%%i1 + 0x000], %%l2 call %%l2 - nop + mov %%i0, %%o0 + mov %%o0, %%l1 + call prom_world + or %%g0, 1, %%o0 + wrpr %%g0, 0x14, %%pstate ! interrupts off + ! restore PROM mmu globals + ldx [%%sp + 2047 + 0x158], %%o0 + ldx [%%sp + 2047 + 0x160], %%o1 + ldx [%%sp + 2047 + 0x168], %%l2 + ldx [%%sp + 2047 + 0x170], %%l3 + ldx [%%sp + 2047 + 0x178], %%l5 + ldx [%%sp + 2047 + 0x180], %%l6 + ldx [%%sp + 2047 + 0x188], %%l7 + wrpr %%g0, 0x414, %%pstate ! restore PROM mmu globals + mov %%o0, %%g1 + mov %%o1, %%g2 + mov %%l2, %%g3 + mov %%l3, %%g4 + mov %%l5, %%g5 + mov %%l6, %%g6 + mov %%l7, %%g7 + wrpr %%l0, %%tba ! restore PROM tba + wrpr %%g0, 0x14, %%pstate ! restore PROM normal globals + ldx [%%sp + 2047 + 0x120], %%g1 + ldx [%%sp + 2047 + 0x128], %%g2 + ldx [%%sp + 2047 + 0x130], %%g3 + ldx [%%sp + 2047 + 0x138], %%g4 + ldx [%%sp + 2047 + 0x140], %%g5 + ldx [%%sp + 2047 + 0x148], %%g6 + ldx [%%sp + 2047 + 0x150], %%g7 + wrpr %%g0, 0x814, %%pstate ! restore PROM interrupt globals + ldx [%%sp + 2047 + 0x0e8], %%g1 + ldx [%%sp + 2047 + 0x0f0], %%g2 + ldx [%%sp + 2047 + 0x0f8], %%g3 + ldx [%%sp + 2047 + 0x100], %%g4 + ldx [%%sp + 2047 + 0x108], %%g5 + ldx [%%sp + 2047 + 0x110], %%g6 + ldx [%%sp + 2047 + 0x118], %%g7 + wrpr %%g0, 0x15, %%pstate ! restore PROM alternate globals + ldx [%%sp + 2047 + 0x0b0], %%g1 + ldx [%%sp + 2047 + 0x0b8], %%g2 + ldx [%%sp + 2047 + 0x0c0], %%g3 + ldx [%%sp + 2047 + 0x0c8], %%g4 + ldx [%%sp + 2047 + 0x0d0], %%g5 + ldx [%%sp + 2047 + 0x0d8], %%g6 + ldx [%%sp + 2047 + 0x0e0], %%g7 wrpr %%l4, 0, %%pstate ret - restore - " : : "r" (&p1275buf), "i" (0 /* PSTATE_AM */)); + restore %%l1, 0, %%o0 + " : : "r" (&p1275buf), "i" (PSTATE_PRIV)); +} + +/* We need some SMP protection here. But be careful as + * prom callback code can call into here too, this is why + * the counter is needed. -DaveM + */ +static int prom_entry_depth = 0; +#ifdef __SMP__ +static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED; +extern void smp_capture(void); +extern void smp_release(void); +#endif + +static __inline__ unsigned long prom_get_lock(void) +{ + unsigned long flags; + + __save_and_cli(flags); + if (prom_entry_depth == 0) { + spin_lock(&prom_entry_lock); + +#if 1 /* DEBUGGING */ + if (prom_entry_depth != 0) + panic("prom_get_lock"); +#endif +#ifdef __SMP__ + smp_capture(); +#endif + } + prom_entry_depth++; + + return flags; +} + +static __inline__ void prom_release_lock(unsigned long flags) +{ + if (--prom_entry_depth == 0) { +#ifdef __SMP__ + smp_release(); +#endif + spin_unlock(&prom_entry_lock); + } + __restore_flags(flags); } long p1275_cmd (char *service, long fmt, ...) @@ -66,13 +300,15 @@ long p1275_cmd (char *service, long fmt, ...) long ctx = 0; p = p1275buf.prom_buffer; - __save_and_cli(flags); ctx = spitfire_get_primary_context (); if (ctx) { flushw_user (); spitfire_set_primary_context (0); } - p1275buf.prom_args[0] = (unsigned long)p; /* service */ + + flags = prom_get_lock(); + + p1275buf.prom_args[0] = (unsigned long)p; /* service */ strcpy (p, service); p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ @@ -82,7 +318,9 @@ long p1275_cmd (char *service, long fmt, ...) for (i = 0; i < nargs; i++, attrs >>= 3) { switch (attrs & 0x7) { case P1275_ARG_NUMBER: - p1275buf.prom_args[i + 3] = (unsigned)va_arg(list, long); break; + p1275buf.prom_args[i + 3] = + (unsigned)va_arg(list, long); + break; case P1275_ARG_IN_STRING: strcpy (p, va_arg(list, char *)); p1275buf.prom_args[i + 3] = (unsigned long)p; @@ -111,16 +349,16 @@ long p1275_cmd (char *service, long fmt, ...) p += 32; break; case P1275_ARG_IN_FUNCTION: - p1275buf.prom_args[i + 3] = (unsigned long)prom_cif_interface + 0x38; - p1275buf.prom_sync_routine = va_arg(list, long); break; + p1275buf.prom_args[i + 3] = + (unsigned long)prom_cif_callback; + p1275buf.prom_callback = va_arg(list, long); + break; } } va_end(list); prom_world(1); - prom_cif_interface(); - prom_world(0); attrs = fmt >> 8; @@ -128,11 +366,14 @@ long p1275_cmd (char *service, long fmt, ...) for (i = 0; i < nargs; i++, attrs >>= 3) { switch (attrs & 0x7) { case P1275_ARG_NUMBER: - (void) va_arg(list, long); break; + (void) va_arg(list, long); + break; case P1275_ARG_IN_STRING: - (void) va_arg(list, char *); break; + (void) va_arg(list, char *); + break; case P1275_ARG_IN_FUNCTION: - (void) va_arg(list, long); break; + (void) va_arg(list, long); + break; case P1275_ARG_IN_BUF: (void) va_arg(list, char *); (void) va_arg(list, long); @@ -152,10 +393,12 @@ long p1275_cmd (char *service, long fmt, ...) } va_end(list); x = p1275buf.prom_args [nargs + 3]; - + + prom_release_lock(flags); + if (ctx) spitfire_set_primary_context (ctx); - __restore_flags(flags); + return x; } diff --git a/arch/sparc64/solaris/Makefile b/arch/sparc64/solaris/Makefile index 691601a3e..5e5a6aff8 100644 --- a/arch/sparc64/solaris/Makefile +++ b/arch/sparc64/solaris/Makefile @@ -8,17 +8,17 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := solaris.o -O_OBJS := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o timod.o +O_OBJS := entry64.o fs.o misc.o signal.o systbl.o socket.o ioctl.o ipc.o socksys.o timod.o ifeq ($(CONFIG_SOLARIS_EMUL),m) M_OBJS := $(O_TARGET) CPPFLAGS = $(MODFLAGS) endif .S.s: - $(CPP) -D__ASSEMBLY__ $(CPPFLAGS) -ansi $< -o $*.s + $(CPP) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s .S.o: - $(CC) -D__ASSEMBLY__ $(CPPFLAGS) -ansi -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o ifneq ($(CONFIG_SOLARIS_EMUL),y) do_it_all: diff --git a/arch/sparc64/solaris/conv.h b/arch/sparc64/solaris/conv.h index fa716f595..1cb3c9018 100644 --- a/arch/sparc64/solaris/conv.h +++ b/arch/sparc64/solaris/conv.h @@ -1,4 +1,4 @@ -/* $Id: conv.h,v 1.3 1998/03/26 08:46:13 jj Exp $ +/* $Id: conv.h,v 1.4 1998/08/15 20:42:51 davem Exp $ * conv.h: Utility macros for Solaris emulation * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -11,13 +11,14 @@ #include <asm/unistd.h> -/* As gcc will warn about casting u32 to some ptr, we have to cast it to - * unsigned long first, and that's what is A() for. - * You just do (void *)A(x), instead of having to - * type (void *)((unsigned long)x) or instead of just (void *)x, which will - * produce warnings. - */ -#define A(x) ((unsigned long)x) +/* Use this to get at 32-bit user passed pointers. */ +#define A(__x) \ +({ unsigned long __ret; \ + __asm__ ("srl %0, 0, %0" \ + : "=r" (__ret) \ + : "0" (__x)); \ + __ret; \ +}) extern unsigned sys_call_table[]; extern unsigned sys_call_table32[]; diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 3980f1d67..3631d43b2 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -1,7 +1,7 @@ -/* $Id: fs.c,v 1.10 1998/05/09 06:15:45 davem Exp $ +/* $Id: fs.c,v 1.11 1998/10/28 08:12:04 jj Exp $ * fs.c: fs related syscall emulation for Solaris * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <linux/types.h> @@ -55,6 +55,26 @@ struct sol_stat { s32 st_pad4[8]; /* expansion area */ }; +struct sol_stat64 { + u32 st_dev; + s32 st_pad1[3]; /* network id */ + u64 st_ino; + u32 st_mode; + u32 st_nlink; + u32 st_uid; + u32 st_gid; + u32 st_rdev; + s32 st_pad2[2]; + s64 st_size; + timestruct_t st_atime; + timestruct_t st_mtime; + timestruct_t st_ctime; + s64 st_blksize; + s32 st_blocks; + char st_fstype[16]; + s32 st_pad4[4]; /* expansion area */ +}; + #define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8)) static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf) @@ -80,6 +100,29 @@ static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf) return 0; } +static inline int putstat64(struct sol_stat64 *ubuf, struct stat *kbuf) +{ + if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev) || + __put_user (kbuf->st_ino, &ubuf->st_ino) || + __put_user (kbuf->st_mode, &ubuf->st_mode) || + __put_user (kbuf->st_nlink, &ubuf->st_nlink) || + __put_user (kbuf->st_uid, &ubuf->st_uid) || + __put_user (kbuf->st_gid, &ubuf->st_gid) || + __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev) || + __put_user (kbuf->st_size, &ubuf->st_size) || + __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec) || + __put_user (0, &ubuf->st_atime.tv_nsec) || + __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec) || + __put_user (0, &ubuf->st_mtime.tv_nsec) || + __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec) || + __put_user (0, &ubuf->st_ctime.tv_nsec) || + __put_user (kbuf->st_blksize, &ubuf->st_blksize) || + __put_user (kbuf->st_blocks, &ubuf->st_blocks) || + __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype)) + return -EFAULT; + return 0; +} + asmlinkage int solaris_stat(u32 filename, u32 statbuf) { int ret; @@ -108,6 +151,28 @@ asmlinkage int solaris_xstat(int vers, u32 filename, u32 statbuf) return solaris_stat(filename, statbuf); } +asmlinkage int solaris_stat64(u32 filename, u32 statbuf) +{ + int ret; + struct stat s; + char *filenam; + mm_segment_t old_fs = get_fs(); + int (*sys_newstat)(char *,struct stat *) = + (int (*)(char *,struct stat *))SYS(stat); + + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { + set_fs (KERNEL_DS); + ret = sys_newstat(filenam, &s); + set_fs (old_fs); + putname32 (filenam); + if (putstat64 ((struct sol_stat64 *)A(statbuf), &s)) + return -EFAULT; + } + return ret; +} + asmlinkage int solaris_lstat(u32 filename, u32 statbuf) { int ret; @@ -135,6 +200,28 @@ asmlinkage int solaris_lxstat(int vers, u32 filename, u32 statbuf) return solaris_lstat(filename, statbuf); } +asmlinkage int solaris_lstat64(u32 filename, u32 statbuf) +{ + int ret; + struct stat s; + char *filenam; + mm_segment_t old_fs = get_fs(); + int (*sys_newlstat)(char *,struct stat *) = + (int (*)(char *,struct stat *))SYS(lstat); + + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { + set_fs (KERNEL_DS); + ret = sys_newlstat(filenam, &s); + set_fs (old_fs); + putname32 (filenam); + if (putstat64 ((struct sol_stat64 *)A(statbuf), &s)) + return -EFAULT; + } + return ret; +} + asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf) { int ret; @@ -156,6 +243,22 @@ asmlinkage int solaris_fxstat(int vers, u32 fd, u32 statbuf) return solaris_fstat(fd, statbuf); } +asmlinkage int solaris_fstat64(unsigned int fd, u32 statbuf) +{ + int ret; + struct stat s; + mm_segment_t old_fs = get_fs(); + int (*sys_newfstat)(unsigned,struct stat *) = + (int (*)(unsigned,struct stat *))SYS(fstat); + + set_fs (KERNEL_DS); + ret = sys_newfstat(fd, &s); + set_fs (old_fs); + if (putstat64 ((struct sol_stat64 *)A(statbuf), &s)) + return -EFAULT; + return ret; +} + asmlinkage int solaris_mknod(u32 path, u32 mode, s32 dev) { int (*sys_mknod)(const char *,int,dev_t) = @@ -172,6 +275,14 @@ asmlinkage int solaris_xmknod(int vers, u32 path, u32 mode, s32 dev) return solaris_mknod(path, mode, dev); } +asmlinkage int solaris_getdents64(unsigned int fd, void *dirent, unsigned int count) +{ + int (*sys_getdents)(unsigned int, void *, unsigned int) = + (int (*)(unsigned int, void *, unsigned int))SYS(getdents); + + return sys_getdents(fd, dirent, count); +} + /* This statfs thingie probably will go in the near future, but... */ struct sol_statfs { @@ -276,6 +387,23 @@ struct sol_statvfs { u32 f_filler[16]; }; +struct sol_statvfs64 { + u32 f_bsize; + u32 f_frsize; + u64 f_blocks; + u64 f_bfree; + u64 f_bavail; + u64 f_files; + u64 f_ffree; + u64 f_favail; + u32 f_fsid; + char f_basetype[16]; + u32 f_flag; + u32 f_namemax; + char f_fstr[32]; + u32 f_filler[16]; +}; + static int report_statvfs(struct inode *inode, u32 buf) { struct statfs s; @@ -313,6 +441,43 @@ static int report_statvfs(struct inode *inode, u32 buf) return error; } +static int report_statvfs64(struct inode *inode, u32 buf) +{ + struct statfs s; + mm_segment_t old_fs = get_fs(); + int error; + struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf); + + set_fs (KERNEL_DS); + error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs)); + set_fs (old_fs); + if (!error) { + const char *p = inode->i_sb->s_type->name; + int i = 0; + int j = strlen (p); + + if (j > 15) j = 15; + if (IS_RDONLY(inode)) i = 1; + if (IS_NOSUID(inode)) i |= 2; + if (put_user (s.f_bsize, &ss->f_bsize) || + __put_user (0, &ss->f_frsize) || + __put_user (s.f_blocks, &ss->f_blocks) || + __put_user (s.f_bfree, &ss->f_bfree) || + __put_user (s.f_bavail, &ss->f_bavail) || + __put_user (s.f_files, &ss->f_files) || + __put_user (s.f_ffree, &ss->f_ffree) || + __put_user (s.f_ffree, &ss->f_favail) || + __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) || + __copy_to_user (ss->f_basetype,p,j) || + __put_user (0, (char *)&ss->f_basetype[j]) || + __put_user (s.f_namelen, &ss->f_namemax) || + __put_user (i, &ss->f_flag) || + __clear_user (&ss->f_fstr, 32)) + return -EFAULT; + } + return error; +} + asmlinkage int solaris_statvfs(u32 path, u32 buf) { struct dentry * dentry; @@ -362,12 +527,62 @@ out: return error; } +asmlinkage int solaris_statvfs64(u32 path, u32 buf) +{ + struct dentry * dentry; + int error; + + lock_kernel(); + dentry = namei((const char *)A(path)); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + struct inode * inode = dentry->d_inode; + + error = -ENOSYS; + if (inode->i_sb->s_op->statfs) + error = report_statvfs64(inode, buf); + dput(dentry); + } + unlock_kernel(); + return error; +} + +asmlinkage int solaris_fstatvfs64(unsigned int fd, u32 buf) +{ + struct inode * inode; + struct dentry * dentry; + struct file * file; + int error; + + lock_kernel(); + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + if (!(dentry = file->f_dentry)) + error = -ENOENT; + else if (!(inode = dentry->d_inode)) + error = -ENOENT; + else if (!inode->i_sb) + error = -ENODEV; + else if (!inode->i_sb->s_op->statfs) + error = -ENOSYS; + else + error = report_statvfs64(inode, buf); + fput(file); +out: + unlock_kernel(); + return error; +} + asmlinkage int solaris_open(u32 filename, int flags, u32 mode) { int (*sys_open)(const char *,int,int) = (int (*)(const char *,int,int))SYS(open); int fl = flags & 0xf; - + +/* if (flags & 0x2000) - allow LFS */ if (flags & 0x8050) fl |= O_SYNC; if (flags & 0x80) fl |= O_NONBLOCK; if (flags & 0x100) fl |= O_CREAT; @@ -558,78 +773,20 @@ asmlinkage int solaris_facl(unsigned int fd, int cmd, int nentries, u32 aclbufp) return -ENOSYS; } -asmlinkage int solaris_pread(int fd, u32 buf, u32 nbyte, s32 offset) +asmlinkage int solaris_pread(unsigned int fd, char *buf, u32 count, u32 pos) { - off_t temp; - int retval; - struct file * file; - long (*sys_read)(unsigned int, char *, unsigned long) = - (long (*)(unsigned int, char *, unsigned long))SYS(read); - long (*sys_lseek)(unsigned int, off_t, unsigned int) = - (long (*)(unsigned int, off_t, unsigned int))SYS(lseek); - - lock_kernel(); - retval = -EBADF; - file = fget(fd); - if (!file) - goto bad; - - temp = file->f_pos; - if (temp != offset) { - retval = sys_lseek(fd, offset, 0); - if (retval < 0) - goto out_putf; - } - retval = sys_read(fd, (char *)A(buf), nbyte); - if (file->f_pos != temp) { - if (!retval) - retval = sys_lseek(fd, temp, 0); - else - sys_lseek(fd, temp, 0); - } - -out_putf: - fput(file); -bad: - unlock_kernel(); - return retval; + ssize_t (*sys_pread)(unsigned int, char *, size_t, loff_t) = + (ssize_t (*)(unsigned int, char *, size_t, loff_t))SYS(pread); + + return sys_pread(fd, buf, count, (loff_t)pos); } -asmlinkage int solaris_pwrite(int fd, u32 buf, u32 nbyte, s32 offset) +asmlinkage int solaris_pwrite(unsigned int fd, char *buf, u32 count, u32 pos) { - off_t temp; - int retval; - struct file * file; - long (*sys_write)(unsigned int, char *, unsigned long) = - (long (*)(unsigned int, char *, unsigned long))SYS(read); - long (*sys_lseek)(unsigned int, off_t, unsigned int) = - (long (*)(unsigned int, off_t, unsigned int))SYS(lseek); - - lock_kernel(); - retval = -EBADF; - file = fget(fd); - if (!file) - goto bad; - - temp = file->f_pos; - if (temp != offset) { - retval = sys_lseek(fd, offset, 0); - if (retval < 0) - goto out_putf; - } - retval = sys_write(fd, (char *)A(buf), nbyte); - if (file->f_pos != temp) { - if (!retval) - retval = sys_lseek(fd, temp, 0); - else - sys_lseek(fd, temp, 0); - } - -out_putf: - fput(file); -bad: - unlock_kernel(); - return retval; + ssize_t (*sys_pwrite)(unsigned int, char *, size_t, loff_t) = + (ssize_t (*)(unsigned int, char *, size_t, loff_t))SYS(pwrite); + + return sys_pwrite(fd, buf, count, (loff_t)pos); } /* POSIX.1 names */ diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 8e0ce81da..c29b79f68 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -1,7 +1,7 @@ -/* $Id: misc.c,v 1.12 1998/06/16 04:37:08 davem Exp $ +/* $Id: misc.c,v 1.13 1998/10/28 08:11:58 jj Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <linux/module.h> @@ -11,6 +11,9 @@ #include <linux/limits.h> #include <linux/mm.h> #include <linux/smp.h> +#include <linux/mman.h> +#include <linux/file.h> +#include <linux/timex.h> #include <asm/uaccess.h> #include <asm/string.h> @@ -43,16 +46,86 @@ int solaris_err_table[] = { /* 120 */ 22, 22, 88, 86, 85, 22, 22, }; +#define SOLARIS_NR_OPEN 256 + +static u32 do_solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u64 off) +{ + struct file *file = NULL; + unsigned long retval, ret_type; + + lock_kernel(); + current->personality |= PER_SVR4; + if (flags & MAP_NORESERVE) { + static int cnt = 0; + + if (cnt < 5) { + printk("%s: unimplemented Solaris MAP_NORESERVE mmap() flag\n", + current->comm); + cnt++; + } + flags &= ~MAP_NORESERVE; + } + retval = -EBADF; + if(!(flags & MAP_ANONYMOUS)) { + if(fd >= SOLARIS_NR_OPEN) + goto out; + file = fget(fd); + if (!file) + goto out; + if (file->f_dentry && file->f_dentry->d_inode) { + struct inode * inode = file->f_dentry->d_inode; + if(MAJOR(inode->i_rdev) == MEM_MAJOR && + MINOR(inode->i_rdev) == 5) { + flags |= MAP_ANONYMOUS; + fput(file); + file = NULL; + } + } + } + + retval = -ENOMEM; + if(!(flags & MAP_FIXED) && !addr) { + unsigned long attempt = get_unmapped_area(addr, len); + if(!attempt || (attempt >= 0xf0000000UL)) + goto out_putf; + addr = (u32) attempt; + } + if(!(flags & MAP_FIXED)) + addr = 0; + ret_type = flags & _MAP_NEW; + flags &= ~_MAP_NEW; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + retval = do_mmap(file, + (unsigned long) addr, (unsigned long) len, + (unsigned long) prot, (unsigned long) flags, off); + if(!ret_type) + retval = ((retval < 0xf0000000) ? 0 : retval); +out_putf: + if (file) + fput(file); +out: + unlock_kernel(); + return (u32) retval; +} + asmlinkage u32 solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off) { - u32 (*sunos_mmap)(u32,u32,u32,u32,u32,u32) = - (u32 (*)(u32,u32,u32,u32,u32,u32))SUNOS(71); - u32 ret; + return do_solaris_mmap(addr, len, prot, flags, fd, (u64) off); +} + +asmlinkage u32 solaris_mmap64(struct pt_regs *regs, u32 len, u32 prot, u32 flags, u32 fd, u32 offhi) +{ + u32 offlo; - ret = sunos_mmap(addr,len,prot,flags,fd,off); - /* sunos_mmap sets personality to PER_BSD */ - current->personality = PER_SVR4; - return ret; + if (regs->u_regs[UREG_G1]) { + if (get_user (offlo, (u32 *)(long)((u32)regs->u_regs[UREG_I6] + 0x5c))) + return -EFAULT; + } else { + if (get_user (offlo, (u32 *)(long)((u32)regs->u_regs[UREG_I6] + 0x60))) + return -EFAULT; + } + return do_solaris_mmap((u32)regs->u_regs[UREG_I0], len, prot, flags, fd, (((u64)offhi)<<32)|offlo); } asmlinkage int solaris_brk(u32 brk) @@ -326,6 +399,18 @@ asmlinkage int solaris_sysconf(int id) } } +asmlinkage int solaris_setreuid(s32 ruid, s32 euid) +{ + int (*sys_setreuid)(uid_t, uid_t) = (int (*)(uid_t, uid_t))SYS(setreuid); + return sys_setreuid(ruid, euid); +} + +asmlinkage int solaris_setregid(s32 rgid, s32 egid) +{ + int (*sys_setregid)(gid_t, gid_t) = (int (*)(gid_t, gid_t))SYS(setregid); + return sys_setregid(rgid, egid); +} + asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid) { int ret; @@ -378,6 +463,257 @@ asmlinkage int solaris_gettimeofday(u32 tim) return sys_gettimeofday((struct timeval *)(u64)tim, NULL); } +#define RLIM_SOL_INFINITY32 0x7fffffff +#define RLIM_SOL_SAVED_MAX32 0x7ffffffe +#define RLIM_SOL_SAVED_CUR32 0x7ffffffd +#define RLIM_SOL_INFINITY ((u64)-3) +#define RLIM_SOL_SAVED_MAX ((u64)-2) +#define RLIM_SOL_SAVED_CUR ((u64)-1) +#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) +#define RLIMIT_SOL_NOFILE 5 +#define RLIMIT_SOL_VMEM 6 + +struct rlimit32 { + s32 rlim_cur; + s32 rlim_max; +}; + +asmlinkage int solaris_getrlimit(unsigned int resource, struct rlimit32 *rlim) +{ + struct rlimit r; + int ret; + mm_segment_t old_fs = get_fs (); + int (*sys_getrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(getrlimit); + + if (resource > RLIMIT_SOL_VMEM) + return -EINVAL; + switch (resource) { + case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break; + case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break; + default: break; + } + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &r); + set_fs (old_fs); + if (!ret) { + if (r.rlim_cur == RLIM_INFINITY) + r.rlim_cur = RLIM_SOL_INFINITY32; + else if ((u64)r.rlim_cur > RLIM_SOL_INFINITY32) + r.rlim_cur = RLIM_SOL_SAVED_CUR32; + if (r.rlim_max == RLIM_INFINITY) + r.rlim_max = RLIM_SOL_INFINITY32; + else if ((u64)r.rlim_max > RLIM_SOL_INFINITY32) + r.rlim_max = RLIM_SOL_SAVED_MAX32; + ret = put_user (r.rlim_cur, &rlim->rlim_cur); + ret |= __put_user (r.rlim_max, &rlim->rlim_max); + } + return ret; +} + +asmlinkage int solaris_setrlimit(unsigned int resource, struct rlimit32 *rlim) +{ + struct rlimit r, rold; + int ret; + mm_segment_t old_fs = get_fs (); + int (*sys_getrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(getrlimit); + int (*sys_setrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(setrlimit); + + if (resource > RLIMIT_SOL_VMEM) + return -EINVAL; + switch (resource) { + case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break; + case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break; + default: break; + } + if (get_user (r.rlim_cur, &rlim->rlim_cur) || + __get_user (r.rlim_max, &rlim->rlim_max)) + return -EFAULT; + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &rold); + if (!ret) { + if (r.rlim_cur == RLIM_SOL_INFINITY32) + r.rlim_cur = RLIM_INFINITY; + else if (r.rlim_cur == RLIM_SOL_SAVED_CUR32) + r.rlim_cur = rold.rlim_cur; + else if (r.rlim_cur == RLIM_SOL_SAVED_MAX32) + r.rlim_cur = rold.rlim_max; + if (r.rlim_max == RLIM_SOL_INFINITY32) + r.rlim_max = RLIM_INFINITY; + else if (r.rlim_max == RLIM_SOL_SAVED_CUR32) + r.rlim_max = rold.rlim_cur; + else if (r.rlim_max == RLIM_SOL_SAVED_MAX32) + r.rlim_max = rold.rlim_max; + ret = sys_setrlimit(resource, &r); + } + set_fs (old_fs); + return ret; +} + +asmlinkage int solaris_getrlimit64(unsigned int resource, struct rlimit *rlim) +{ + struct rlimit r; + int ret; + mm_segment_t old_fs = get_fs (); + int (*sys_getrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(getrlimit); + + if (resource > RLIMIT_SOL_VMEM) + return -EINVAL; + switch (resource) { + case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break; + case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break; + default: break; + } + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &r); + set_fs (old_fs); + if (!ret) { + if (r.rlim_cur == RLIM_INFINITY) + r.rlim_cur = RLIM_SOL_INFINITY; + if (r.rlim_max == RLIM_INFINITY) + r.rlim_max = RLIM_SOL_INFINITY; + ret = put_user (r.rlim_cur, &rlim->rlim_cur); + ret |= __put_user (r.rlim_max, &rlim->rlim_max); + } + return ret; +} + +asmlinkage int solaris_setrlimit64(unsigned int resource, struct rlimit *rlim) +{ + struct rlimit r, rold; + int ret; + mm_segment_t old_fs = get_fs (); + int (*sys_getrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(getrlimit); + int (*sys_setrlimit)(unsigned int, struct rlimit *) = + (int (*)(unsigned int, struct rlimit *))SYS(setrlimit); + + if (resource > RLIMIT_SOL_VMEM) + return -EINVAL; + switch (resource) { + case RLIMIT_SOL_NOFILE: resource = RLIMIT_NOFILE; break; + case RLIMIT_SOL_VMEM: resource = RLIMIT_AS; break; + default: break; + } + if (get_user (r.rlim_cur, &rlim->rlim_cur) || + __get_user (r.rlim_max, &rlim->rlim_max)) + return -EFAULT; + set_fs (KERNEL_DS); + ret = sys_getrlimit(resource, &rold); + if (!ret) { + if (r.rlim_cur == RLIM_SOL_INFINITY) + r.rlim_cur = RLIM_INFINITY; + else if (r.rlim_cur == RLIM_SOL_SAVED_CUR) + r.rlim_cur = rold.rlim_cur; + else if (r.rlim_cur == RLIM_SOL_SAVED_MAX) + r.rlim_cur = rold.rlim_max; + if (r.rlim_max == RLIM_SOL_INFINITY) + r.rlim_max = RLIM_INFINITY; + else if (r.rlim_max == RLIM_SOL_SAVED_CUR) + r.rlim_max = rold.rlim_cur; + else if (r.rlim_max == RLIM_SOL_SAVED_MAX) + r.rlim_max = rold.rlim_max; + ret = sys_setrlimit(resource, &r); + } + set_fs (old_fs); + return ret; +} + +struct timeval32 { + int tv_sec, tv_usec; +}; + +struct sol_ntptimeval { + struct timeval32 time; + s32 maxerror; + s32 esterror; +}; + +struct sol_timex { + u32 modes; + s32 offset; + s32 freq; + s32 maxerror; + s32 esterror; + s32 status; + s32 constant; + s32 precision; + s32 tolerance; + s32 ppsfreq; + s32 jitter; + s32 shift; + s32 stabil; + s32 jitcnt; + s32 calcnt; + s32 errcnt; + s32 stbcnt; +}; + +asmlinkage int solaris_ntp_gettime(struct sol_ntptimeval *ntp) +{ + int (*sys_adjtimex)(struct timex *) = + (int (*)(struct timex *))SYS(adjtimex); + struct timex t; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + t.modes = 0; + ret = sys_adjtimex(&t); + set_fs(old_fs); + if (ret < 0) + return ret; + ret = put_user (t.time.tv_sec, &ntp->time.tv_sec); + ret |= __put_user (t.time.tv_usec, &ntp->time.tv_usec); + ret |= __put_user (t.maxerror, &ntp->maxerror); + ret |= __put_user (t.esterror, &ntp->esterror); + return ret; +} + +asmlinkage int solaris_ntp_adjtime(struct sol_timex *txp) +{ + int (*sys_adjtimex)(struct timex *) = + (int (*)(struct timex *))SYS(adjtimex); + struct timex t; + int ret, err; + mm_segment_t old_fs = get_fs(); + + ret = get_user (t.modes, &txp->modes); + ret |= __get_user (t.offset, &txp->offset); + ret |= __get_user (t.freq, &txp->freq); + ret |= __get_user (t.maxerror, &txp->maxerror); + ret |= __get_user (t.esterror, &txp->esterror); + ret |= __get_user (t.status, &txp->status); + ret |= __get_user (t.constant, &txp->constant); + set_fs(KERNEL_DS); + ret = sys_adjtimex(&t); + set_fs(old_fs); + if (ret < 0) + return ret; + err = put_user (t.offset, &txp->offset); + err |= __put_user (t.freq, &txp->freq); + err |= __put_user (t.maxerror, &txp->maxerror); + err |= __put_user (t.esterror, &txp->esterror); + err |= __put_user (t.status, &txp->status); + err |= __put_user (t.constant, &txp->constant); + err |= __put_user (t.precision, &txp->precision); + err |= __put_user (t.tolerance, &txp->tolerance); + err |= __put_user (t.ppsfreq, &txp->ppsfreq); + err |= __put_user (t.jitter, &txp->jitter); + err |= __put_user (t.shift, &txp->shift); + err |= __put_user (t.stabil, &txp->stabil); + err |= __put_user (t.jitcnt, &txp->jitcnt); + err |= __put_user (t.calcnt, &txp->calcnt); + err |= __put_user (t.errcnt, &txp->errcnt); + err |= __put_user (t.stbcnt, &txp->stbcnt); + if (err) + return -EFAULT; + return ret; +} + asmlinkage int do_sol_unimplemented(struct pt_regs *regs) { printk ("Unimplemented Solaris syscall %d %08x %08x %08x %08x\n", diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c new file mode 100644 index 000000000..4b3f18fc1 --- /dev/null +++ b/arch/sparc64/solaris/socket.c @@ -0,0 +1,463 @@ +/* $Id: socket.c,v 1.1 1998/10/28 08:12:11 jj Exp $ + * socket.c: Socket syscall emulation for Solaris 2.6+ + * + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include <linux/types.h> +#include <linux/smp_lock.h> +#include <linux/mm.h> +#include <linux/malloc.h> +#include <linux/socket.h> +#include <linux/file.h> + +#include <asm/uaccess.h> +#include <asm/string.h> +#include <asm/oplib.h> +#include <asm/idprom.h> +#include <asm/machines.h> + +#include "conv.h" + +#define SOCK_SOL_STREAM 2 +#define SOCK_SOL_DGRAM 1 +#define SOCK_SOL_RAW 4 +#define SOCK_SOL_RDM 5 +#define SOCK_SOL_SEQPACKET 6 + +static int socket_check(int family, int type) +{ + if (family != PF_UNIX && family != PF_INET) + return -ESOCKTNOSUPPORT; + switch (type) { + case SOCK_SOL_STREAM: type = SOCK_STREAM; break; + case SOCK_SOL_DGRAM: type = SOCK_DGRAM; break; + case SOCK_SOL_RAW: type = SOCK_RAW; break; + case SOCK_SOL_RDM: type = SOCK_RDM; break; + case SOCK_SOL_SEQPACKET: type = SOCK_SEQPACKET; break; + default: return -EINVAL; + } + return type; +} + +asmlinkage int solaris_socket(int family, int type, int protocol) +{ + int (*sys_socket)(int, int, int) = + (int (*)(int, int, int))SYS(socket); + + type = socket_check (family, type); + if (type < 0) return type; + return sys_socket(family, type, protocol); +} + +asmlinkage int solaris_socketpair(int family, int type, int protocol, int *usockvec) +{ + int (*sys_socketpair)(int, int, int, int *) = + (int (*)(int, int, int, int *))SYS(socketpair); + + type = socket_check (family, type); + if (type < 0) return type; + return sys_socketpair(family, type, protocol, usockvec); +} + +asmlinkage int solaris_bind(int fd, struct sockaddr *addr, int addrlen) +{ + int (*sys_bind)(int, struct sockaddr *, int) = + (int (*)(int, struct sockaddr *, int))SUNOS(104); + + return sys_bind(fd, addr, addrlen); +} + +asmlinkage int solaris_setsockopt(int fd, int level, int optname, u32 optval, int optlen) +{ + int (*sunos_setsockopt)(int, int, int, u32, int) = + (int (*)(int, int, int, u32, int))SUNOS(105); + + return sunos_setsockopt(fd, level, optname, optval, optlen); +} + +asmlinkage int solaris_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen) +{ + int (*sunos_getsockopt)(int, int, int, u32, u32) = + (int (*)(int, int, int, u32, u32))SUNOS(118); + + return sunos_getsockopt(fd, level, optname, optval, optlen); +} + +asmlinkage int solaris_connect(int fd, struct sockaddr *addr, int addrlen) +{ + int (*sys_connect)(int, struct sockaddr *, int) = + (int (*)(int, struct sockaddr *, int))SYS(connect); + + return sys_connect(fd, addr, addrlen); +} + +asmlinkage int solaris_accept(int fd, struct sockaddr *addr, int *addrlen) +{ + int (*sys_accept)(int, struct sockaddr *, int *) = + (int (*)(int, struct sockaddr *, int *))SYS(accept); + + return sys_accept(fd, addr, addrlen); +} + +asmlinkage int solaris_listen(int fd, int backlog) +{ + int (*sys_listen)(int, int) = + (int (*)(int, int))SUNOS(106); + + return sys_listen(fd, backlog); +} + +asmlinkage int solaris_shutdown(int fd, int how) +{ + int (*sys_shutdown)(int, int) = + (int (*)(int, int))SYS(shutdown); + + return sys_shutdown(fd, how); +} + +#define MSG_SOL_OOB 0x1 +#define MSG_SOL_PEEK 0x2 +#define MSG_SOL_DONTROUTE 0x4 +#define MSG_SOL_EOR 0x8 +#define MSG_SOL_CTRUNC 0x10 +#define MSG_SOL_TRUNC 0x20 +#define MSG_SOL_WAITALL 0x40 +#define MSG_SOL_DONTWAIT 0x80 + +static int solaris_to_linux_msgflags(int flags) +{ + int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE); + + if (flags & MSG_SOL_EOR) fl |= MSG_EOR; + if (flags & MSG_SOL_CTRUNC) fl |= MSG_CTRUNC; + if (flags & MSG_SOL_TRUNC) fl |= MSG_TRUNC; + if (flags & MSG_SOL_WAITALL) fl |= MSG_WAITALL; + if (flags & MSG_SOL_DONTWAIT) fl |= MSG_DONTWAIT; + return fl; +} + +static int linux_to_solaris_msgflags(int flags) +{ + int fl = flags & (MSG_OOB|MSG_PEEK|MSG_DONTROUTE); + + if (flags & MSG_EOR) fl |= MSG_SOL_EOR; + if (flags & MSG_CTRUNC) fl |= MSG_SOL_CTRUNC; + if (flags & MSG_TRUNC) fl |= MSG_SOL_TRUNC; + if (flags & MSG_WAITALL) fl |= MSG_SOL_WAITALL; + if (flags & MSG_DONTWAIT) fl |= MSG_SOL_DONTWAIT; + return fl; +} + +asmlinkage int solaris_recvfrom(int s, char *buf, int len, int flags, u32 from, u32 fromlen) +{ + int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *) = + (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom); + + return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), (struct sockaddr *)A(from), (int *)A(fromlen)); +} + +asmlinkage int solaris_recv(int s, char *buf, int len, int flags) +{ + int (*sys_recvfrom)(int, void *, size_t, unsigned, struct sockaddr *, int *) = + (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(recvfrom); + + return sys_recvfrom(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL); +} + +asmlinkage int solaris_sendto(int s, char *buf, int len, int flags, u32 to, u32 tolen) +{ + int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int *) = + (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(sendto); + + return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), (struct sockaddr *)A(to), (int *)A(tolen)); +} + +asmlinkage int solaris_send(int s, char *buf, int len, int flags) +{ + int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int *) = + (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int *))SYS(sendto); + + return sys_sendto(s, buf, len, solaris_to_linux_msgflags(flags), NULL, NULL); +} + +asmlinkage int solaris_getpeername(int fd, struct sockaddr *addr, int *addrlen) +{ + int (*sys_getpeername)(int, struct sockaddr *, int *) = + (int (*)(int, struct sockaddr *, int *))SYS(getpeername); + + return sys_getpeername(fd, addr, addrlen); +} + +asmlinkage int solaris_getsockname(int fd, struct sockaddr *addr, int *addrlen) +{ + int (*sys_getsockname)(int, struct sockaddr *, int *) = + (int (*)(int, struct sockaddr *, int *))SYS(getsockname); + + return sys_getsockname(fd, addr, addrlen); +} + +/* XXX This really belongs in some header file... -DaveM */ +#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - + 16 for IP, 16 for IPX, + 24 for IPv6, + about 80 for AX.25 */ + +/* XXX These as well... */ +extern __inline__ struct socket *socki_lookup(struct inode *inode) +{ + return &inode->u.socket_i; +} + +extern __inline__ struct socket *sockfd_lookup(int fd, int *err) +{ + struct file *file; + struct inode *inode; + + if (!(file = fget(fd))) { + *err = -EBADF; + return NULL; + } + + inode = file->f_dentry->d_inode; + if (!inode || !inode->i_sock || !socki_lookup(inode)) { + *err = -ENOTSOCK; + fput(file); + return NULL; + } + + return socki_lookup(inode); +} + +extern __inline__ void sockfd_put(struct socket *sock) +{ + fput(sock->file); +} + +struct sol_nmsghdr { + u32 msg_name; + int msg_namelen; + u32 msg_iov; + u32 msg_iovlen; + u32 msg_control; + u32 msg_controllen; + u32 msg_flags; +}; + +struct sol_cmsghdr { + u32 cmsg_len; + int cmsg_level; + int cmsg_type; + unsigned char cmsg_data[0]; +}; + +struct iovec32 { + u32 iov_base; + u32 iov_len; +}; + +static inline int iov_from_user32_to_kern(struct iovec *kiov, + struct iovec32 *uiov32, + int niov) +{ + int tot_len = 0; + + while(niov > 0) { + u32 len, buf; + + if(get_user(len, &uiov32->iov_len) || + get_user(buf, &uiov32->iov_base)) { + tot_len = -EFAULT; + break; + } + tot_len += len; + kiov->iov_base = (void *)A(buf); + kiov->iov_len = (__kernel_size_t) len; + uiov32++; + kiov++; + niov--; + } + return tot_len; +} + +static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg, + struct sol_nmsghdr *umsg) +{ + u32 tmp1, tmp2, tmp3; + int err; + + err = get_user(tmp1, &umsg->msg_name); + err |= __get_user(tmp2, &umsg->msg_iov); + err |= __get_user(tmp3, &umsg->msg_control); + if (err) + return -EFAULT; + + kmsg->msg_name = (void *)A(tmp1); + kmsg->msg_iov = (struct iovec *)A(tmp2); + kmsg->msg_control = (void *)A(tmp3); + + err = get_user(kmsg->msg_namelen, &umsg->msg_namelen); + err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); + err |= get_user(kmsg->msg_flags, &umsg->msg_flags); + + kmsg->msg_flags = solaris_to_linux_msgflags(kmsg->msg_flags); + + return err; +} + +/* I've named the args so it is easy to tell whose space the pointers are in. */ +static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov, + char *kern_address, int mode) +{ + int tot_len; + + if(kern_msg->msg_namelen) { + if(mode==VERIFY_READ) { + int err = move_addr_to_kernel(kern_msg->msg_name, + kern_msg->msg_namelen, + kern_address); + if(err < 0) + return err; + } + kern_msg->msg_name = kern_address; + } else + kern_msg->msg_name = NULL; + + if(kern_msg->msg_iovlen > UIO_FASTIOV) { + kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec), + GFP_KERNEL); + if(!kern_iov) + return -ENOMEM; + } + + tot_len = iov_from_user32_to_kern(kern_iov, + (struct iovec32 *)kern_msg->msg_iov, + kern_msg->msg_iovlen); + if(tot_len >= 0) + kern_msg->msg_iov = kern_iov; + else if(kern_msg->msg_iovlen > UIO_FASTIOV) + kfree(kern_iov); + + return tot_len; +} + +asmlinkage int solaris_sendmsg(int fd, struct sol_nmsghdr *user_msg, unsigned user_flags) +{ + struct socket *sock; + char address[MAX_SOCK_ADDR]; + struct iovec iov[UIO_FASTIOV]; + unsigned char ctl[sizeof(struct cmsghdr) + 20]; + unsigned char *ctl_buf = ctl; + struct msghdr kern_msg; + int err, total_len; + + if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) + return -EFAULT; + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; + err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ); + if (err < 0) + goto out; + total_len = err; + + if(kern_msg.msg_controllen) { + struct sol_cmsghdr *ucmsg = (struct sol_cmsghdr *)kern_msg.msg_control; + unsigned long *kcmsg; + __kernel_size_t32 cmlen; + + if(kern_msg.msg_controllen > sizeof(ctl) && + kern_msg.msg_controllen <= 256) { + err = -ENOBUFS; + ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL); + if(!ctl_buf) + goto out_freeiov; + } + __get_user(cmlen, &ucmsg->cmsg_len); + kcmsg = (unsigned long *) ctl_buf; + *kcmsg++ = (unsigned long)cmlen; + err = -EFAULT; + if(copy_from_user(kcmsg, &ucmsg->cmsg_level, + kern_msg.msg_controllen - sizeof(__kernel_size_t32))) + goto out_freectl; + kern_msg.msg_control = ctl_buf; + } + kern_msg.msg_flags = solaris_to_linux_msgflags(user_flags); + + lock_kernel(); + sock = sockfd_lookup(fd, &err); + if (sock != NULL) { + if (sock->file->f_flags & O_NONBLOCK) + kern_msg.msg_flags |= MSG_DONTWAIT; + err = sock_sendmsg(sock, &kern_msg, total_len); + sockfd_put(sock); + } + unlock_kernel(); + +out_freectl: + /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ + if(ctl_buf != ctl) + kfree(ctl_buf); +out_freeiov: + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); +out: + return err; +} + +asmlinkage int solaris_recvmsg(int fd, struct sol_nmsghdr *user_msg, unsigned int user_flags) +{ + struct iovec iovstack[UIO_FASTIOV]; + struct msghdr kern_msg; + char addr[MAX_SOCK_ADDR]; + struct socket *sock; + struct iovec *iov = iovstack; + struct sockaddr *uaddr; + int *uaddr_len; + unsigned long cmsg_ptr; + int err, total_len, len = 0; + + if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) + return -EFAULT; + if(kern_msg.msg_iovlen > UIO_MAXIOV) + return -EINVAL; + + uaddr = kern_msg.msg_name; + uaddr_len = &user_msg->msg_namelen; + err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); + if (err < 0) + goto out; + total_len = err; + + cmsg_ptr = (unsigned long) kern_msg.msg_control; + kern_msg.msg_flags = 0; + + lock_kernel(); + sock = sockfd_lookup(fd, &err); + if (sock != NULL) { + if (sock->file->f_flags & O_NONBLOCK) + user_flags |= MSG_DONTWAIT; + err = sock_recvmsg(sock, &kern_msg, total_len, user_flags); + if(err >= 0) + len = err; + sockfd_put(sock); + } + unlock_kernel(); + + if(uaddr != NULL && err >= 0) + err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); + if(err >= 0) { + err = __put_user(linux_to_solaris_msgflags(kern_msg.msg_flags), &user_msg->msg_flags); + if(!err) { + /* XXX Convert cmsg back into userspace 32-bit format... */ + err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr, + &user_msg->msg_controllen); + } + } + + if(kern_msg.msg_iov != iov) + kfree(kern_msg.msg_iov); +out: + if(err < 0) + return err; + return len; +} diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c index dce7927d8..dbdbcd1a2 100644 --- a/arch/sparc64/solaris/socksys.c +++ b/arch/sparc64/solaris/socksys.c @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.7 1998/03/29 10:11:04 davem Exp $ +/* $Id: socksys.c,v 1.8 1998/08/26 10:28:28 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff --git a/arch/sparc64/solaris/systbl.S b/arch/sparc64/solaris/systbl.S index bb18807f1..f47470e4c 100644 --- a/arch/sparc64/solaris/systbl.S +++ b/arch/sparc64/solaris/systbl.S @@ -1,7 +1,7 @@ -/* $Id: systbl.S,v 1.6 1998/03/26 08:46:08 jj Exp $ +/* $Id: systbl.S,v 1.7 1998/10/28 08:11:49 jj Exp $ * systbl.S: System call entry point table for Solaris compatibility. * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) */ @@ -156,8 +156,8 @@ solaris_sys_table: .word solaris_fxstat /* fxstat ddx 125 */ .word solaris_xmknod /* xmknod dsox 126 */ .word solaris_unimplemented /* syslocal d 127 */ - .word solaris_unimplemented /* setrlimit 128 */ - .word solaris_unimplemented /* getrlimit 129 */ + .word solaris_setrlimit /* setrlimit dp 128 */ + .word solaris_getrlimit /* getrlimit dp 129 */ .word CHAIN(chown) /* lchown sdd 130 */ .word solaris_unimplemented /* memcntl 131 */ .word solaris_getpmsg /* getpmsg dxxxx 132 */ @@ -230,8 +230,8 @@ solaris_sys_table: .word CHAIN(nanosleep) /* nanosleep dd 199 */ .word solaris_facl /* facl dddp 200 */ .word solaris_unimplemented /* 201 */ - .word solaris_unimplemented /* 202 */ - .word solaris_unimplemented /* 203 */ + .word solaris_setreuid /* setreuid dd 202 */ + .word solaris_setregid /* setregid dd 203 */ .word solaris_unimplemented /* 204 */ .word solaris_unimplemented /* 205 */ .word solaris_unimplemented /* 206 */ @@ -241,43 +241,43 @@ solaris_sys_table: .word solaris_unimplemented /* 210 */ .word solaris_unimplemented /* 211 */ .word solaris_unimplemented /* 212 */ - .word solaris_unimplemented /* 213 */ - .word solaris_unimplemented /* 214 */ - .word solaris_unimplemented /* 215 */ - .word solaris_unimplemented /* 216 */ - .word solaris_unimplemented /* 217 */ - .word solaris_unimplemented /* 218 */ - .word solaris_unimplemented /* 219 */ - .word solaris_unimplemented /* 220 */ - .word solaris_unimplemented /* 221 */ - .word solaris_unimplemented /* 222 */ - .word solaris_unimplemented /* 223 */ - .word solaris_unimplemented /* 224 */ - .word solaris_unimplemented /* 225 */ + .word solaris_getdents64 /* getdents64 dpd 213 */ + .word REGS(solaris_mmap64) /* mmap64 xxxxdX 214 */ + .word solaris_stat64 /* stat64 sP 215 */ + .word solaris_lstat64 /* lstat64 sP 216 */ + .word solaris_fstat64 /* fstat64 dP 217 */ + .word solaris_statvfs64 /* statvfs64 sP 218 */ + .word solaris_fstatvfs64 /* fstatvfs64 dP 219 */ + .word solaris_setrlimit64 /* setrlimit64 dP 220 */ + .word solaris_getrlimit64 /* getrlimit64 dP 221 */ + .word CHAIN(pread) /* pread64 dpdD 222 */ + .word CHAIN(pwrite) /* pwrite64 dpdD 223 */ + .word CHAIN(creat) /* creat64 so 224 */ + .word solaris_open /* open64 soo 225 */ .word solaris_unimplemented /* 226 */ .word solaris_unimplemented /* 227 */ .word solaris_unimplemented /* 228 */ .word solaris_unimplemented /* 229 */ - .word solaris_unimplemented /* 230 */ - .word solaris_unimplemented /* 231 */ - .word solaris_unimplemented /* 232 */ - .word solaris_unimplemented /* 233 */ - .word solaris_unimplemented /* 234 */ - .word solaris_unimplemented /* 235 */ - .word solaris_unimplemented /* 236 */ - .word solaris_unimplemented /* 237 */ - .word solaris_unimplemented /* 238 */ - .word solaris_unimplemented /* 239 */ - .word solaris_unimplemented /* 240 */ - .word solaris_unimplemented /* 241 */ - .word solaris_unimplemented /* 242 */ - .word solaris_unimplemented /* 243 */ - .word solaris_unimplemented /* 244 */ - .word solaris_unimplemented /* 245 */ - .word solaris_unimplemented /* 246 */ + .word solaris_socket /* socket ddd 230 */ + .word solaris_socketpair /* socketpair dddp 231 */ + .word solaris_bind /* bind dpd 232 */ + .word solaris_listen /* listen dd 233 */ + .word solaris_accept /* accept dpp 234 */ + .word solaris_connect /* connect dpd 235 */ + .word solaris_shutdown /* shutdown dd 236 */ + .word solaris_recv /* recv dpdd 237 */ + .word solaris_recvfrom /* recvfrom dpddpp 238 */ + .word solaris_recvmsg /* recvmsg dpd 239 */ + .word solaris_send /* send dpdd 240 */ + .word solaris_sendmsg /* sendmsg dpd 241 */ + .word solaris_sendto /* sendto dpddpd 242 */ + .word solaris_getpeername /* getpeername dpp 243 */ + .word solaris_getsockname /* getsockname dpp 244 */ + .word solaris_getsockopt /* getsockopt dddpp 245 */ + .word solaris_setsockopt /* setsockopt dddpp 246 */ .word solaris_unimplemented /* 247 */ - .word solaris_unimplemented /* 248 */ - .word solaris_unimplemented /* 249 */ + .word solaris_ntp_gettime /* ntp_gettime p 248 */ + .word solaris_ntp_adjtime /* ntp_adjtime p 249 */ .word solaris_unimplemented /* 250 */ .word solaris_unimplemented /* 251 */ .word solaris_unimplemented /* 252 */ |