summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/lib/Makefile6
-rw-r--r--arch/mips/lib/floppy-std.c3
-rw-r--r--arch/mips/lib/ide-std.c2
-rw-r--r--arch/mips/lib/kbd-no.c63
-rw-r--r--arch/mips/lib/kbd-std.c81
-rw-r--r--arch/mips/mm/andes.c7
-rw-r--r--arch/mips/mm/fault.c39
-rw-r--r--arch/mips/mm/init.c123
-rw-r--r--arch/mips/mm/r2300.c7
-rw-r--r--arch/mips/mm/r4xx0.c3
-rw-r--r--arch/mips/mm/r6000.c5
-rw-r--r--arch/mips/mm/tfp.c5
-rw-r--r--arch/mips/sgi/kernel/indy_int.c18
-rw-r--r--arch/mips/sgi/kernel/indy_sc.c3
-rw-r--r--arch/mips/sgi/kernel/indy_timer.c6
-rw-r--r--arch/mips/sgi/kernel/setup.c64
-rw-r--r--arch/mips/sni/Makefile5
-rw-r--r--arch/mips/sni/hw-access.c70
-rw-r--r--arch/mips/sni/int-handler.S214
-rw-r--r--arch/mips/sni/io.c106
-rw-r--r--arch/mips/sni/pci.c41
-rw-r--r--arch/mips/sni/pcimt_scache.c33
-rw-r--r--arch/mips/sni/setup.c22
-rw-r--r--arch/ppc/8xx_io/Makefile8
-rw-r--r--arch/ppc/8xx_io/commproc.c45
-rw-r--r--arch/ppc/8xx_io/commproc.h87
-rw-r--r--arch/ppc/8xx_io/enet.c2
-rw-r--r--arch/ppc/8xx_io/fec.c985
-rw-r--r--arch/ppc/8xx_io/uart.c290
-rw-r--r--arch/ppc/Makefile7
-rw-r--r--arch/ppc/amiga/amiints.c549
-rw-r--r--arch/ppc/amiga/config.c919
-rw-r--r--arch/ppc/amiga/time.c22
-rw-r--r--arch/ppc/apus_defconfig282
-rw-r--r--arch/ppc/boot/Makefile56
-rw-r--r--arch/ppc/boot/head.S8
-rw-r--r--arch/ppc/boot/mbxtty.c16
-rw-r--r--arch/ppc/boot/misc.c281
-rw-r--r--arch/ppc/boot/mkprep.c20
-rw-r--r--arch/ppc/boot/offset2
-rw-r--r--arch/ppc/boot/size2
-rw-r--r--arch/ppc/chrp_defconfig96
-rw-r--r--arch/ppc/chrpboot/Makefile6
-rw-r--r--arch/ppc/chrpboot/main.c4
-rw-r--r--arch/ppc/chrpboot/nonstdio.h18
-rw-r--r--arch/ppc/chrpboot/zlib.c2143
-rw-r--r--arch/ppc/chrpboot/zlib.h432
-rw-r--r--arch/ppc/coffboot/Makefile13
-rw-r--r--arch/ppc/coffboot/misc.S11
-rw-r--r--arch/ppc/coffboot/zlib.c4
-rw-r--r--arch/ppc/common_defconfig204
-rw-r--r--arch/ppc/config.in52
-rw-r--r--arch/ppc/defconfig71
-rw-r--r--arch/ppc/kernel/Makefile11
-rw-r--r--arch/ppc/kernel/align.c4
-rw-r--r--arch/ppc/kernel/apus_setup.c199
-rw-r--r--arch/ppc/kernel/chrp_setup.c62
-rw-r--r--arch/ppc/kernel/feature.c249
-rw-r--r--arch/ppc/kernel/find_name.c4
-rw-r--r--arch/ppc/kernel/head.S358
-rw-r--r--arch/ppc/kernel/idle.c26
-rw-r--r--arch/ppc/kernel/irq.c561
-rw-r--r--arch/ppc/kernel/misc.S93
-rw-r--r--arch/ppc/kernel/openpic.c77
-rw-r--r--arch/ppc/kernel/pci.c18
-rw-r--r--arch/ppc/kernel/pmac_pci.c10
-rw-r--r--arch/ppc/kernel/pmac_setup.c201
-rw-r--r--arch/ppc/kernel/pmac_support.c3
-rw-r--r--arch/ppc/kernel/ppc_defs.h69
-rw-r--r--arch/ppc/kernel/ppc_htab.c150
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c18
-rw-r--r--arch/ppc/kernel/prep_pci.c66
-rw-r--r--arch/ppc/kernel/prep_setup.c96
-rw-r--r--arch/ppc/kernel/process.c39
-rw-r--r--arch/ppc/kernel/prom.c903
-rw-r--r--arch/ppc/kernel/residual.c85
-rw-r--r--arch/ppc/kernel/setup.c215
-rw-r--r--arch/ppc/kernel/signal.c14
-rw-r--r--arch/ppc/kernel/smp.c114
-rw-r--r--arch/ppc/kernel/syscalls.c2
-rw-r--r--arch/ppc/kernel/time.c9
-rw-r--r--arch/ppc/kernel/totalmp.c109
-rw-r--r--arch/ppc/lib/locks.c18
-rw-r--r--arch/ppc/lib/string.S84
-rw-r--r--arch/ppc/mbx_defconfig1
-rw-r--r--arch/ppc/mm/fault.c2
-rw-r--r--arch/ppc/mm/init.c221
-rw-r--r--arch/ppc/pmac_defconfig153
-rw-r--r--arch/ppc/prep_defconfig106
-rw-r--r--arch/sparc/Makefile47
-rw-r--r--arch/sparc/boot/Makefile31
-rw-r--r--arch/sparc/boot/btfixupprep.c85
-rw-r--r--arch/sparc/config.in9
-rw-r--r--arch/sparc/defconfig73
-rw-r--r--arch/sparc/kernel/Makefile8
-rw-r--r--arch/sparc/kernel/auxio.c7
-rw-r--r--arch/sparc/kernel/devices.c43
-rw-r--r--arch/sparc/kernel/ebus.c331
-rw-r--r--arch/sparc/kernel/entry.S5
-rw-r--r--arch/sparc/kernel/init_task.c2
-rw-r--r--arch/sparc/kernel/irq.c233
-rw-r--r--arch/sparc/kernel/pcic.c762
-rw-r--r--arch/sparc/kernel/process.c63
-rw-r--r--arch/sparc/kernel/setup.c13
-rw-r--r--arch/sparc/kernel/signal.c298
-rw-r--r--arch/sparc/kernel/smp.c28
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c58
-rw-r--r--arch/sparc/kernel/sun4c_irq.c7
-rw-r--r--arch/sparc/kernel/sun4d_irq.c12
-rw-r--r--arch/sparc/kernel/sun4d_smp.c56
-rw-r--r--arch/sparc/kernel/sun4m_irq.c4
-rw-r--r--arch/sparc/kernel/sun4m_smp.c46
-rw-r--r--arch/sparc/kernel/sunos_ioctl.c4
-rw-r--r--arch/sparc/kernel/sys_sparc.c10
-rw-r--r--arch/sparc/kernel/sys_sunos.c34
-rw-r--r--arch/sparc/kernel/systbls.S346
-rw-r--r--arch/sparc/kernel/time.c45
-rw-r--r--arch/sparc/kernel/traps.c6
-rw-r--r--arch/sparc/lib/bitops.S90
-rw-r--r--arch/sparc/lib/copy_user.S146
-rw-r--r--arch/sparc/lib/debuglocks.c388
-rw-r--r--arch/sparc/lib/locks.S44
-rw-r--r--arch/sparc/mm/Makefile7
-rw-r--r--arch/sparc/mm/asyncd.c2
-rw-r--r--arch/sparc/mm/fault.c39
-rw-r--r--arch/sparc/mm/generic.c11
-rw-r--r--arch/sparc/mm/init.c2
-rw-r--r--arch/sparc/mm/io-unit.c50
-rw-r--r--arch/sparc/mm/srmmu.c125
-rw-r--r--arch/sparc/mm/sun4c.c23
-rw-r--r--arch/sparc/mm/turbosparc.S48
-rw-r--r--arch/sparc/prom/console.c26
-rw-r--r--arch/sparc/prom/tree.c65
-rw-r--r--arch/sparc/vmlinux.lds2
-rw-r--r--arch/sparc64/Makefile36
-rw-r--r--arch/sparc64/config.in16
-rw-r--r--arch/sparc64/defconfig52
-rw-r--r--arch/sparc64/kernel/Makefile45
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c7
-rw-r--r--arch/sparc64/kernel/binfmt_elf32.c118
-rw-r--r--arch/sparc64/kernel/check_asm.sh1
-rw-r--r--arch/sparc64/kernel/dtlb_backend.S2
-rw-r--r--arch/sparc64/kernel/ebus.c9
-rw-r--r--arch/sparc64/kernel/entry.S133
-rw-r--r--arch/sparc64/kernel/head.S5
-rw-r--r--arch/sparc64/kernel/ioctl32.c917
-rw-r--r--arch/sparc64/kernel/irq.c240
-rw-r--r--arch/sparc64/kernel/process.c126
-rw-r--r--arch/sparc64/kernel/psycho.c43
-rw-r--r--arch/sparc64/kernel/ptrace.c32
-rw-r--r--arch/sparc64/kernel/rtrap.S63
-rw-r--r--arch/sparc64/kernel/setup.c253
-rw-r--r--arch/sparc64/kernel/signal.c340
-rw-r--r--arch/sparc64/kernel/signal32.c367
-rw-r--r--arch/sparc64/kernel/smp.c88
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c61
-rw-r--r--arch/sparc64/kernel/sunos_ioctl32.c11
-rw-r--r--arch/sparc64/kernel/sys32.S109
-rw-r--r--arch/sparc64/kernel/sys_sparc.c117
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c1453
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c53
-rw-r--r--arch/sparc64/kernel/systbls.S14
-rw-r--r--arch/sparc64/kernel/time.c33
-rw-r--r--arch/sparc64/kernel/trampoline.S3
-rw-r--r--arch/sparc64/kernel/traps.c111
-rw-r--r--arch/sparc64/kernel/ttable.S12
-rw-r--r--arch/sparc64/kernel/unaligned.c32
-rw-r--r--arch/sparc64/kernel/winfixup.S117
-rw-r--r--arch/sparc64/lib/Makefile8
-rw-r--r--arch/sparc64/lib/VIScopy.S17
-rw-r--r--arch/sparc64/lib/VISsave.S4
-rw-r--r--arch/sparc64/lib/blockops.S90
-rw-r--r--arch/sparc64/lib/checksum.S7
-rw-r--r--arch/sparc64/lib/debuglocks.c278
-rw-r--r--arch/sparc64/lib/locks.S76
-rw-r--r--arch/sparc64/lib/strlen.S5
-rw-r--r--arch/sparc64/math-emu/Makefile6
-rw-r--r--arch/sparc64/mm/asyncd.c2
-rw-r--r--arch/sparc64/mm/fault.c77
-rw-r--r--arch/sparc64/mm/generic.c11
-rw-r--r--arch/sparc64/mm/init.c191
-rw-r--r--arch/sparc64/mm/ultra.S77
-rw-r--r--arch/sparc64/prom/misc.c15
-rw-r--r--arch/sparc64/prom/p1275.c301
-rw-r--r--arch/sparc64/solaris/Makefile6
-rw-r--r--arch/sparc64/solaris/conv.h17
-rw-r--r--arch/sparc64/solaris/fs.c299
-rw-r--r--arch/sparc64/solaris/misc.c354
-rw-r--r--arch/sparc64/solaris/socket.c463
-rw-r--r--arch/sparc64/solaris/socksys.c2
-rw-r--r--arch/sparc64/solaris/systbl.S76
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, &current->tss.fpr[reg]);
+ cvt_fd(&data.f, &current->tss.fpr[reg], &current->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(&current->tss.fpr[reg], &data.f);
+ cvt_df(&current->tss.fpr[reg], &data.f, &current->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 *)&current_set[1]);
-
+ dcbf((void *)&current_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, &regs[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, &regs[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 *)&regs[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(&current->tss.float_regs[0], &current->tss.fsr,
+ &current->tss.fpqueue[0], &current->tss.fpqdepth);
+ regs->psr &= ~(PSR_EF);
+ current->flags &= ~(PF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+ &current->tss.fpqueue[0], &current->tss.fpqdepth);
+ last_task_used_math = 0;
+ regs->psr &= ~(PSR_EF);
+ }
+#endif
+ memcpy(&fpregs->pr_fr.pr_regs[0],
+ &current->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],
+ &current->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(&current->tss.float_regs[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
+ err = __copy_from_user(&current->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(&current->tss.fpqueue[0],
- &fpu->si_fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
+ err |= __copy_from_user(&current->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],
- &current->tss.reg_window[window],
- sizeof(struct reg_window));
+ err |= __copy_to_user(&sc->sigc_wbuf[window],
+ &current->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], &current->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], &current->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], &current->tss.fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
+ err |= __copy_to_user(&fpu->si_fpqueue[0], &current->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], &regs->u_regs [UREG_G1], sizeof (long) * 7);
- copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
+ err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
+ err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->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], &current->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],
+ &current->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], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
- copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
+ err |= __copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
+ err |= __copy_to_user(&(*gr)[SVR4_O0], &regs->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(&current->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(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
- copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
- return 0;
+ err |= __copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1],
+ sizeof (long) * 7);
+ err |= __copy_from_user(&regs->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(&current->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(&current->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(&current->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(&current->mm->mmap_sem);
return retval;
}
@@ -146,6 +149,7 @@ asmlinkage int sunos_brk(unsigned long brk)
unsigned long rlim;
unsigned long newbrk, oldbrk;
+ down(&current->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(&current->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(&current->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, &current->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, &current->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(&current->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(&current->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],
- &current->tss.reg_window[window],
- sizeof(struct reg_window));
+ err |= copy_to_user(&sc->sigc_wbuf[window],
+ &current->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], &current->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],
+ &current->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(&current->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(&current->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(&current->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, &times->actime) ||
+ __get_user (t.modtime, &times->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(&current->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(&current->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(&current->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(&current->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 (&regs, 0, sizeof (regs));
- regs.tpc = pc;
- regs.tnpc = pc + 4;
- /* FIXME: Should set up regs->tstate? */
- unhandled_fault (address, current, &regs);
- /* 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 */