summaryrefslogtreecommitdiffstats
path: root/arch/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc')
-rw-r--r--arch/ppc/Makefile100
-rw-r--r--arch/ppc/boot/Makefile77
-rw-r--r--arch/ppc/boot/find_name.c47
-rw-r--r--arch/ppc/boot/head.S77
-rw-r--r--arch/ppc/boot/kbd.c166
-rw-r--r--arch/ppc/boot/misc.c247
-rw-r--r--arch/ppc/boot/mkprep.c32
-rw-r--r--arch/ppc/coffboot/.cvsignore7
-rw-r--r--arch/ppc/coffboot/Makefile50
-rw-r--r--arch/ppc/coffboot/crt0.S24
-rw-r--r--arch/ppc/coffboot/elfextract.c98
-rw-r--r--arch/ppc/coffboot/hack-coff.c79
-rw-r--r--arch/ppc/coffboot/ld.script68
-rw-r--r--arch/ppc/coffboot/main.c185
-rw-r--r--arch/ppc/coffboot/misc.S50
-rw-r--r--arch/ppc/coffboot/nonstdio.h18
-rw-r--r--arch/ppc/coffboot/rs6000.h243
-rw-r--r--arch/ppc/coffboot/start.c280
-rw-r--r--arch/ppc/coffboot/string.S206
-rw-r--r--arch/ppc/coffboot/zlib.c2143
-rw-r--r--arch/ppc/coffboot/zlib.h432
-rw-r--r--arch/ppc/config.in59
-rw-r--r--arch/ppc/defconfig250
-rw-r--r--arch/ppc/ignore65
-rw-r--r--arch/ppc/kernel/Makefile62
-rw-r--r--arch/ppc/kernel/align.c290
-rw-r--r--arch/ppc/kernel/bitops.c201
-rw-r--r--arch/ppc/kernel/checks.c57
-rw-r--r--arch/ppc/kernel/chrp_pci.c156
-rw-r--r--arch/ppc/kernel/chrp_setup.c180
-rw-r--r--arch/ppc/kernel/chrp_time.c132
-rw-r--r--arch/ppc/kernel/head.S302
-rw-r--r--arch/ppc/kernel/idle.c279
-rw-r--r--arch/ppc/kernel/irq.c630
-rw-r--r--arch/ppc/kernel/misc.S11
-rw-r--r--arch/ppc/kernel/mk_defs.c43
-rw-r--r--arch/ppc/kernel/openpic.c546
-rw-r--r--arch/ppc/kernel/pci-bridge.c428
-rw-r--r--arch/ppc/kernel/pci.c754
-rw-r--r--arch/ppc/kernel/pmac_pci.c423
-rw-r--r--arch/ppc/kernel/pmac_setup.c271
-rw-r--r--arch/ppc/kernel/pmac_support.c69
-rw-r--r--arch/ppc/kernel/pmac_time.c87
-rw-r--r--arch/ppc/kernel/ppc_asm.tmpl4
-rw-r--r--arch/ppc/kernel/ppc_defs.head3
-rw-r--r--arch/ppc/kernel/ppc_htab.c221
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c140
-rw-r--r--arch/ppc/kernel/prep_pci.c436
-rw-r--r--arch/ppc/kernel/prep_setup.c294
-rw-r--r--arch/ppc/kernel/prep_time.c239
-rw-r--r--arch/ppc/kernel/process.c430
-rw-r--r--arch/ppc/kernel/prom.c524
-rw-r--r--arch/ppc/kernel/ptrace.c17
-rw-r--r--arch/ppc/kernel/residual.c144
-rw-r--r--arch/ppc/kernel/setup.c268
-rw-r--r--arch/ppc/kernel/signal.c138
-rw-r--r--arch/ppc/kernel/syscalls.c247
-rw-r--r--arch/ppc/kernel/time.c268
-rw-r--r--arch/ppc/kernel/time.h74
-rw-r--r--arch/ppc/kernel/traps.c109
-rw-r--r--arch/ppc/lib/Makefile43
-rw-r--r--arch/ppc/lib/checksum.S192
-rw-r--r--arch/ppc/lib/strcase.c12
-rw-r--r--arch/ppc/lib/string.S345
-rw-r--r--arch/ppc/mkdiff8
-rw-r--r--arch/ppc/mkdist13
-rw-r--r--arch/ppc/mktar9
-rw-r--r--arch/ppc/mm/Makefile27
-rw-r--r--arch/ppc/mm/extable.c65
-rw-r--r--arch/ppc/mm/fault.c121
-rw-r--r--arch/ppc/mm/init.c580
-rw-r--r--arch/ppc/pmac_defconfig274
-rw-r--r--arch/ppc/prep_defconfig250
-rw-r--r--arch/ppc/vmlinux.lds85
74 files changed, 13172 insertions, 2332 deletions
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index ac2719977..6c81701d9 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -1,6 +1,3 @@
-#
-# ppc/Makefile
-#
# This file is included by the global makefile so that you can add your own
# architecture-specific flags and dependencies. Remember to do have actions
# for "archclean" and "archdep" for cleaning up and making dependencies for
@@ -12,29 +9,28 @@
#
# Copyright (C) 1994 by Linus Torvalds
# Changes for PPC by Gary Thomas
-# Modified by Cort Dougan
+# Rewritten by Cort Dougan and Paul Mackerras
#
+ifeq ($(CONFIG_PMAC),y)
+KERNELBASE =0xc0000000
+else
+KERNELBASE =0x90000000
+endif
+
# PowerPC (cross) tools
-SUFFIX =
-AS = as$(SUFFIX)
-ASFLAGS =
-LD = ld$(SUFFIX)
-LINKFLAGS = -T arch/ppc/ld.script -Ttext 0x90000000
-HOSTCC = gcc
-CC = gcc$(SUFFIX)
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE = ppc-linux-elf-
+else
+CHECKS = checks
+endif
+
+ASFLAGS =
+LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELBASE) -Bstatic
CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
-CFLAGS = $(CFLAGSINC) \
- -Wstrict-prototypes -fomit-frame-pointer \
- -fno-builtin \
- -finhibit-size-directive \
- -O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
-# -fverbose-asm
+CFLAGS := $(CFLAGS) -D__powerpc__ -fsigned-char -msoft-float -pipe \
+ -fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring
CPP = $(CC) -E $(CFLAGS)
-AR = ar$(SUFFIX)
-RANLIB = ranlib$(SUFFIX)
-STRIP = strip$(SUFFIX)
-NM = nm$(SUFFIX)
ifdef CONFIG_601
CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
@@ -55,59 +51,35 @@ SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
+ifdef CONFIG_XMON
+SUBDIRS += arch/ppc/xmon
+CORE_FILES += arch/ppc/xmon/x.o
+endif
+
+ifdef CONFIG_PMAC
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/coffboot
+else
+# PReP and CHRP systems
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+endif
checks:
@$(MAKE) -C arch/$(ARCH)/kernel checks
-netboot: checks vmlinux
- @$(MAKEBOOT) netboot
-
-znetboot: checks vmlinux
- @$(MAKEBOOT) znetboot
+BOOT_TARGETS = netboot znetboot zImage floppy install \
+ vmlinux.coff znetboot.initrd zImage.initrd
-#rcpboot: checks vmlinux
-# @$(MAKEBOOT) rcpboot
+$(BOOT_TARGETS): $(CHECKS) vmlinux
+ @$(MAKEBOOT) $@
-zImage: checks vmlinux
- @$(MAKEBOOT) zImage
-
-floppy: checks vmlinux
- @$(MAKEBOOT) floppy
-
-install: checks vmlinux
- @$(MAKEBOOT) install
-
-vmlinux.coff : checks vmlinux
- $(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
-
-arch/ppc/kernel: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
-
-arch/ppc/mm: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/mm
-
-arch/ppc/lib: dummy
- $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
-
-diffs:
- arch/ppc/mkdiff
-
-tar:
- arch/ppc/mktar
+tags:
+ etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
archclean:
- rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
- rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
- rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+ rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h
+ rm -f arch/ppc/kernel/checks
@$(MAKEBOOT) clean
archdep:
- $(MAKE) -C arch/ppc/boot fastdep
- $(MAKE) -C arch/ppc/kernel fastdep
- $(MAKE) -C arch/ppc/mm fastdep
- $(MAKE) -C arch/ppc/lib fastdep
-
-tags :
- etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c
+ $(MAKEBOOT) fastdep
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index 5dcac750e..a731ec2a0 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -22,58 +22,81 @@
$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
-ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
GZIP_FLAGS = -v9
SYSTEM = $(TOPDIR)/vmlinux
-
-OBJECTS = head.o inflate.o unzip.o misc.o vreset.o
-
+OBJECTS := head.o inflate.o unzip.o misc.o vreset.o kbd.o
CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJCOPY_ARGS = -O elf32-powerpc
+
all: $(TOPDIR)/zImage
mkprep : mkprep.c
$(HOSTCC) $(CFLAGSINC) -o mkprep mkprep.c
+piggyback : piggyback.c
+ $(HOSTCC) $(CFLAGSINC) -o piggyback piggyback.c
+
find_name : find_name.c
$(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
-mk_type41: mk_type41.c
- $(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
-
-piggyback: piggyback.c
- $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-
floppy: $(TOPDIR)/vmlinux zImage
dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
-netboot : $(TOPDIR)/vmlinux mkprep
- mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+floppy.initrd: $(TOPDIR)/vmlinux zImage
+ dd if=$(TOPDIR)/zImage.initrd of=/dev/fd0H1440 bs=64b
+
+znetboot : zImage mkprep
+ cp $(TOPDIR)/zImage /usr/local/tftpboot/vmlinux
-znetboot : zvmlinux mkprep
- mkprep zvmlinux $(TOPDIR)/znetboot
- cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
+znetboot.initrd : zImage.initrd mkprep
+ cp $(TOPDIR)/zImage.initrd /usr/local/tftpboot/vmlinux
-rcpboot : znetboot
- rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
+#
+# This really needs to go away. Perhaps a
+# zImage.prep and zImage.chrp might be better.
+# Once we're able to get a lilo-ish program
+# on prep systems this won't be a problem.
+# -- Cort
+#
+ifdef CONFIG_CHRP
+zImage: zvmlinux
+ cp zvmlinux $(TOPDIR)/zImage
+zImage.initrd: zvmlinux.initrd
+ cp zvmlinux.initrd $(TOPDIR)/zImage.initrd
+
+zvmlinux: $(OBJECTS) $(SYSTEM) find_name vmlinux.gz piggyback
+ ./piggyback < vmlinux.gz | $(AS) -o piggy.o
+ $(LD) $(ZLINKFLAGS) -o $@ $(OBJECTS) piggy.o
+ rm -f piggy.o
+else
zImage: zvmlinux mkprep
mkprep -pbp zvmlinux $(TOPDIR)/zImage
-install: zImage
- dd if=$(TOPDIR)/zImage of=/dev/sda4
- ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
- cp $(TOPDIR)/System.map $(INSTALL_PATH)/
+zImage.initrd: zvmlinux.initrd mkprep
+ mkprep -pbp zvmlinux.initrd $(TOPDIR)/zImage.initrd
-zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name
- mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
- $(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
- rm -f piggy.o
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name vmlinux.gz
+ $(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
+ zvmlinux.tmp $@
+ rm zvmlinux.tmp
+endif
+
+vmlinux.gz: $(TOPDIR)/vmlinux
+ dd bs=64k skip=1 if=$(TOPDIR)/vmlinux | gzip -vf9 - > vmlinux.gz
+
+zvmlinux.initrd: zvmlinux
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+ zvmlinux $@
clean:
- rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
- rm -f $(TOPDIR)/{zImage,znetboot,netboot}
+ rm -f vmlinux* znetboot* zImage* zvmlinux* mkprep find_name
+ rm -f $(TOPDIR)/{zImage*,znetboot*,zvmlinux*,vmlinux*}
fastdep:
$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
diff --git a/arch/ppc/boot/find_name.c b/arch/ppc/boot/find_name.c
new file mode 100644
index 000000000..23646fb69
--- /dev/null
+++ b/arch/ppc/boot/find_name.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <asm/page.h>
+#include <sys/mman.h>
+/*
+ * Finds a given address in the System.map and prints it out
+ * with its neighbors. -- Cort
+ */
+
+void main(int argc, char **argv)
+{
+ unsigned long addr, cmp, i;
+ FILE *f;
+ char *ptr;
+ char s[256], last[256];
+
+ if ( argc < 2 )
+ {
+ fprintf(stderr, "Usage: %s <address>\n", argv[0]);
+ exit(-1);
+ }
+
+ for ( i = 1 ; argv[i] ; i++ )
+ {
+ sscanf( argv[i], "%0x", &addr );
+ /* adjust if addr is relative to kernelbase */
+ if ( addr < PAGE_OFFSET )
+ addr += PAGE_OFFSET;
+
+ if ( (f = fopen( "System.map", "r" )) == NULL )
+ {
+ perror("fopen()\n");
+ exit(-1);
+ }
+
+ while ( !feof(f) )
+ {
+ fgets(s, 255 , f);
+ sscanf( s, "%0x", &cmp );
+ if ( addr < cmp )
+ break;
+ strcpy( last, s);
+ }
+
+ printf( "%s", last);
+ }
+ fclose(f);
+}
diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S
index 6b25cb157..2cfda5cbe 100644
--- a/arch/ppc/boot/head.S
+++ b/arch/ppc/boot/head.S
@@ -13,17 +13,6 @@
start:
bl start_
start_:
-/* TEMP - No residual data on BeBox (yet) */
-#if 0
-#define IS_BE_BOX 0x42654278 /* 'BeBx' */
- lis r2,IS_BE_BOX>>16
- ori r2,r2,IS_BE_BOX&0xFFFF
- cmp 0,r30,r2
- bne notBeBox
- li r3,0
-#endif
-notBeBox:
-/* TEMP */
mr r11,r3 /* Save pointer to residual data */
mfmsr r3 /* Turn off interrupts */
li r4,0
@@ -48,7 +37,9 @@ notBeBox:
mtlr r21
mtctr r22
bctr /* Jump to code */
-/* Relocate code to final resting spot */
+/*
+ * no matter where we're loaded, move ourselves to -Ttext address
+ */
relocate:
mflr r3 /* Compute code bias */
subi r3,r3,4
@@ -98,13 +89,26 @@ start_ldr:
mr r5,r6 /* Checksum */
mr r6,r11 /* Residual data */
bl decompress_kernel
- /*mr r29,r3*/ /* R3 = TotalMemory */
- /*lis r28,hold_residual@h
- ori r28,r28,hold_residual@l*/
+
/* changed to use r3 (as firmware does) for kernel
as ptr to residual -- Cort*/
- li r5,0x100 /* Kernel code starts here */
- mtlr r5
+ lis r6,cmd_line@h
+ ori r6,r6,cmd_line@l
+ subi r7,r6,1
+00: lbzu r2,1(r7)
+ cmpi 0,r2,0
+ bne 00b
+
+ /* r4,r5 have initrd_start, size */
+ lis r2,initrd_start@h
+ ori r2,r2,initrd_start@l
+ lwz r4,0(r2)
+ lis r2,initrd_end@h
+ ori r2,r2,initrd_end@l
+ lwz r5,0(r2)
+
+ li r9,0x00c /* Kernel code starts here */
+ mtlr r9
blr
hang:
b hang
@@ -142,6 +146,45 @@ _put_HID0:
blr
/*
+ * Delay for a number of microseconds
+ * -- Use the BUS timer (assumes 66MHz)
+ */
+ .globl udelay
+udelay:
+ mfspr r4,PVR
+ srwi r4,r4,16
+ cmpi 0,r4,1 /* 601 ? */
+ bne .udelay_not_601
+00: li r0,86 /* Instructions / microsecond? */
+ mtctr r0
+10: addi r0,r0,0 /* NOP */
+ bdnz 10b
+ subic. r3,r3,1
+ bne 00b
+ blr
+
+.udelay_not_601:
+ mulli r4,r3,1000 /* nanoseconds */
+ addi r4,r4,59
+ li r5,60
+ divw r4,r4,r5 /* BUS ticks */
+1: mftbu r5
+ mftb r6
+ mftbu r7
+ cmp 0,r5,r7
+ bne 1b /* Get [synced] base time */
+ addc r9,r6,r4 /* Compute end time */
+ addze r8,r5
+2: mftbu r5
+ cmp 0,r5,r8
+ blt 2b
+ bgt 3f
+ mftb r6
+ cmp 0,r6,r9
+ blt 2b
+3: blr
+
+/*
* This space [buffer] is used to forceably flush the data cache when
* running in copyback mode. This is necessary IFF the data cache could
* contain instructions for which the instruction cache has stale data.
diff --git a/arch/ppc/boot/kbd.c b/arch/ppc/boot/kbd.c
new file mode 100644
index 000000000..6c0065b00
--- /dev/null
+++ b/arch/ppc/boot/kbd.c
@@ -0,0 +1,166 @@
+/* Keyboard handler */
+
+#include <../drivers/char/defkeymap.c> /* yeah I know it's bad */
+
+#define L 0x0001 /* locking function */
+#define SHF 0x0002 /* keyboard shift */
+#define ALT 0x0004 /* alternate shift -- alternate chars */
+#define NUM 0x0008 /* numeric shift cursors vs. numeric */
+#define CTL 0x0010 /* control shift -- allows ctl function */
+#define CPS 0x0020 /* caps shift -- swaps case of letter */
+#define ASCII 0x0040 /* ascii code for this key */
+#define STP 0x0080 /* stop output */
+#define FUNC 0x0100 /* function key */
+#define SCROLL 0x0200 /* scroll lock key */
+
+unsigned char shfts, ctls, alts, caps, num, stp;
+
+#define KBDATAP 0x60 /* kbd data port */
+#define KBSTATUSPORT 0x61 /* kbd status */
+#define KBSTATP 0x64 /* kbd status port */
+#define KBINRDY 0x01
+#define KBOUTRDY 0x02
+
+#define _x__ 0x00 /* Unknown / unmapped */
+
+const unsigned short action[] = {
+ 0, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 0- 7 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 8-15 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 16-23 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, CTL, ASCII, ASCII, /* scan 24-31 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 32-39 */
+ ASCII, ASCII, SHF, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 40-47 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, SHF, ASCII, /* scan 48-55 */
+ ALT, ASCII, CPS, FUNC, FUNC, FUNC, FUNC, FUNC, /* scan 56-63 */
+ FUNC, FUNC, FUNC, FUNC, FUNC, NUM,SCROLL, ASCII, /* scan 64-71 */
+ ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 72-79 */
+ ASCII, ASCII, ASCII, ASCII, 0, 0, 0, 0, /* scan 80-87 */
+ 0,0,0,0,0,0,0,0, /* scan 88-95 */
+ 0,0,0,0,0,0,0,0, /* scan 96-103 */
+ 0,0,0,0,0,0,0,0, /* scan 104-111 */
+ 0,0,0,0,0,0,0,0, /* scan 112-119 */
+ 0,0,0,0,0,0,0,0, /* scan 120-127 */
+};
+
+static int
+kbd(noblock)
+ int noblock;
+{
+ unsigned char dt, brk, act;
+ int first = 1;
+loop:
+ if (noblock) {
+ if ((inb(KBSTATP) & KBINRDY) == 0)
+ return (-1);
+ } else while((inb(KBSTATP) & KBINRDY) == 0) ;
+
+ dt = inb(KBDATAP);
+
+ brk = dt & 0x80; /* brk == 1 on key release */
+ dt = dt & 0x7f; /* keycode */
+
+ act = action[dt];
+ if (/*act&SHF*/ dt == 54)
+ shfts = brk ? 0 : 1;
+ if (/*act&ALT*/ dt == 48)
+ alts = brk ? 0 : 1;
+ if (/*act&NUM*/ dt == 69)
+ if (act&L) {
+ /* NUM lock */
+ if(!brk)
+ num = !num;
+ } else
+ num = brk ? 0 : 1;
+ if (/*act&CTL*/ dt == 29)
+ ctls = brk ? 0 : 1;
+ if (/*act&CPS*/ dt == 58)
+ if (act&L) {
+ /* CAPS lock */
+ if(!brk)
+ caps = !caps;
+ } else
+ caps = brk ? 0 : 1;
+ if (0/*act&STP*/)
+ if (act&L) {
+ if(!brk)
+ stp = !stp;
+ } else
+ stp = brk ? 0 : 1;
+
+ if ((act&ASCII) && !brk) {
+ unsigned char chr;
+ if (shfts)
+ chr = shift_map[dt];
+ else if (ctls)
+ chr = ctrl_map[dt];
+ else
+ chr = plain_map[dt];
+ if (alts)
+ chr |= 0x80;
+
+ if (caps && (chr >= 'a' && chr <= 'z'))
+ chr -= 'a' - 'A' ;
+ if ( chr == 0x01 ) chr = '\n'; /* hack */
+#define CTRL(s) (s & 0x1F)
+ if ((chr == '\r') || (chr == '\n') || (chr == CTRL('A')) || (chr == CTRL('S')))
+ {
+ /* Wait for key up */
+ while (1)
+ {
+ while((inb(KBSTATP) & KBINRDY) == 0) ;
+ dt = inb(KBDATAP);
+ if (dt & 0x80) /* key up */ break;
+ }
+ }
+ return (chr);
+ }
+ if (first && brk) return (0); /* Ignore initial 'key up' codes */
+ goto loop;
+}
+
+static
+scankbd(void) {
+ return (kbd(1) != -1);
+}
+
+static
+kbdreset(void)
+{
+ unsigned char c;
+ int i;
+
+ /* Send self-test */
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBSTATP,0xAA);
+ while ((inb(KBSTATP) & KBINRDY) == 0) ; /* wait input ready */
+ if ((c = inb(KBDATAP)) != 0x55)
+ {
+ puts("Keyboard self test failed - result:");
+ puthex(c);
+ puts("\n");
+ }
+ /* Enable interrupts and keyboard controller */
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBSTATP,0x60);
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBDATAP,0x45);
+ for (i = 0; i < 10000; i++) udelay(1);
+ while (inb(KBSTATP) & KBOUTRDY) ;
+ outb(KBSTATP,0xAE);
+}
+
+static int kbd_reset = 0;
+
+CRT_getc(void)
+{
+ int c;
+ if (!kbd_reset) {kbdreset(); kbd_reset++; }
+ while ((c = kbd(0)) == 0) ;
+ return(c);
+}
+
+CRT_tstc(void)
+{
+ if (!kbd_reset) {kbdreset(); kbd_reset++; }
+ return ((inb(KBSTATP) & KBINRDY) != 0);
+}
diff --git a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c
index a983ea106..4d2a723f5 100644
--- a/arch/ppc/boot/misc.c
+++ b/arch/ppc/boot/misc.c
@@ -8,13 +8,23 @@
* puts by Nick Holloway 1993
*
* Adapted for PowerPC by Gary Thomas
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu)
*/
#include "gzip.h"
#include "lzw.h"
#include "asm/residual.h"
+#include <elf.h>
RESIDUAL hold_residual;
+unsigned long initrd_start = 0, initrd_end = 0;
+char *zimage_start;
+int zimage_size;
+extern char input_data[];
+extern int input_len;
+void cksum_text(void);
+void verify_data(unsigned long load_addr);
+
void dump_buf(unsigned char *p, int s);
#define EOF -1
@@ -26,8 +36,7 @@ unsigned outcnt;
unsigned insize;
unsigned inptr;
-extern char input_data[];
-extern int input_len;
+char cmd_line[256];
int input_ptr;
@@ -56,6 +65,9 @@ int lines, cols;
int orig_x, orig_y;
void puts(const char *);
+void putc(const char c);
+void puthex(unsigned long val);
+void _bcopy(char *src, char *dst, int len);
void *malloc(int size)
{
@@ -77,7 +89,7 @@ void *malloc(int size)
*/
if (free_mem_ptr < (long)&end) {
- if (free_mem_ptr > (long)&input_data[input_ptr])
+ if (free_mem_ptr > (long)&zimage_start[input_ptr])
error("\nOut of memory\n");
return p;
@@ -87,7 +99,7 @@ void *malloc(int size)
#endif
return p;
puts("large kernel, low 1M tight...");
- free_mem_ptr = (long)input_data;
+ free_mem_ptr = (long)zimage_start;
}
}
@@ -115,6 +127,53 @@ static void scroll()
vidmem[i] = ' ';
}
+tstc(void)
+{
+ return (CRT_tstc() );
+}
+
+getc(void)
+{
+ while (1) {
+ if (CRT_tstc()) return (CRT_getc());
+ }
+}
+
+void
+putc(const char c)
+{
+ int x,y;
+
+ x = orig_x;
+ y = orig_y;
+
+ if ( c == '\n' ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ scroll();
+ y--;
+ }
+ } else if (c == '\b') {
+ if (x > 0) {
+ x--;
+ }
+ } else {
+ vidmem [ ( x + cols * y ) * 2 ] = c;
+ if ( ++x >= cols ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ scroll();
+ y--;
+ }
+ }
+ }
+
+ cursor(x, y);
+
+ orig_x = x;
+ orig_y = y;
+}
+
void puts(const char *s)
{
int x,y;
@@ -229,10 +288,10 @@ puts("*");
insize = 0;
do {
len = INBUFSIZ-insize;
- if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
+ if (len > (zimage_size-input_ptr+1)) len=zimage_size-input_ptr+1;
if (len == 0 || len == EOF) break;
- for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
+ for (i=0;i<len;i++) inbuf[insize+i] = zimage_start[input_ptr+i];
insize += len;
input_ptr += len;
} while (insize < INBUFSIZ);
@@ -313,7 +372,15 @@ void error(char *x)
unsigned long
decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
{
- unsigned long TotalMemory;
+ int timer;
+ char *cp, ch;
+ Elf32_Ehdr *eh;
+ Elf32_Shdr *sh, *strtab_shdr;
+ char *strtab;
+ unsigned long i;
+ extern unsigned long start(void);
+
+
output_data = (char *)0x0; /* Points to 0 */
lines = 25;
cols = 80;
@@ -339,33 +406,135 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
clear_bufs();
makecrc();
- puts("Loaded at "); puthex(load_addr); puts(", "); puthex(num_words); puts(" words");
- puts(", cksum = "); puthex(cksum); puts("\n");
+ puts("Cksum: "); puthex(cksum); puts("\n");
+ puts("Loaded at: "); puthex(load_addr); puts(" "); puthex(num_words+load_addr);
+ puts("\n");
+ puts("Boot code relocated to: "); puthex((unsigned long)start); puts(" ");
+ puthex((unsigned long)(num_words+start));
+ puts("\n");
if (residual) {
- _bcopy(residual, &hold_residual, sizeof(hold_residual));
- puts("Residual data at "); puthex(residual); puts("\n");
- show_residual_data(residual);
- TotalMemory = residual->TotalMemory;
- } else {
- TotalMemory = 0x01000000;
+ _bcopy((char *)residual, (char *)&hold_residual, sizeof(hold_residual));
+ puts("Residual data at: "); puthex((unsigned long)residual); puts(" ");
+ puthex((unsigned long)((unsigned long)(residual->ResidualLength) + residual)); puts("\n");
+ puts("Residual data relocated to: "); puthex((unsigned long)&hold_residual); puts("\n");
}
- puts("Uncompressing Linux...");
+ /*
+ * Take care of initrd if we have one
+ */
+ /*
+ * the _actual_ load addr is 64k (elf hdr size) lower but the
+ * firmware gives us the starting exec point not the load ptr
+ * -- Cort
+ */
+ eh = (Elf32_Ehdr *)(load_addr - 65536);
+ sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+ /*puts("Entry point: "); puthex(eh->e_entry); puts("\n");*/
+
+ /* find string table */
+ for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+ {
+ /*puts("Section: "); puthex(i);
+ puts(" type: "); puthex(sh->sh_type);
+ puts(" offset: "); puthex(sh->sh_offset);
+ puts("\n");*/
+
+ if ( sh->sh_type == SHT_STRTAB )
+ {
+ strtab_shdr = sh;
+ strtab = (char *)(sh->sh_offset + (unsigned long)eh);
+ /*puts("Found strtab at: "); puthex((unsigned long)strtab);
+ puts("\n");*/
+ break;
+ }
+ }
- method = get_method(0);
+ /* find the initrd and image sections */
+ if ( strtab_shdr )
+ {
+ sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+ for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+ {
+ if ( !memcmp("initrd", (char *)(strtab+sh->sh_name), 6 ) )
+ {
+ initrd_start = (unsigned long)eh + sh->sh_offset;
+ initrd_end = initrd_start + sh->sh_size;
+ puts("Found initrd at: "); puthex(initrd_start);
+ puts(" "); puthex(initrd_end);
+ puts("\n");
+ }
+ if ( !memcmp("image", (char *)(strtab+sh->sh_name), 5 ) )
+ {
+ zimage_start = (char *)((unsigned long)eh + sh->sh_offset);
+ zimage_size = sh->sh_size;
+ puts("Found zimage at: "); puthex((unsigned long)zimage_start);
+ puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
+ puts("\n");
+ }
+ }
+ }
+ else
+ {
+ puts("Couldn't find string table for boot image!\n");
+ }
+
+ /* relocate initrd */
+ if ( initrd_start )
+ {
+ memcpy ((void *)0x00D00000,(void *)initrd_start,
+ initrd_end - initrd_start );
+ initrd_end = 0x00D00000 + initrd_end - initrd_start;
+ initrd_start = 0x00D00000;
+ puts("Moved initrd to: "); puthex(initrd_start);
+ puts(" "); puthex(initrd_end); puts("\n");
+ }
- work(0, 0);
+ CRT_tstc(); /* Forces keyboard to be initialized */
+ puts("\nLinux/PPC load: ");
+ timer = 0;
+ cp = cmd_line;
+ while (timer++ < 5*1000) {
+ if (tstc()) {
+ while ((ch = getc()) != '\n' && ch != '\r') {
+ if (ch == '\b') {
+ if (cp != cmd_line) {
+ cp--;
+ puts("\b \b");
+ }
+ } else {
+ *cp++ = ch;
+ putc(ch);
+ }
+ }
+ break; /* Exit 'timer' loop */
+ }
+ udelay(1000); /* 1 msec */
+ }
+ *cp = 0;
+ puts("\n");
+
+ /* mappings on early boot can only handle 16M */
+ if ( (int)(&cmd_line[0]) > (16<<20))
+ puts("cmd_line > 16M\n");
+ if ( (int)&hold_residual > (16<<20))
+ puts("hold_residual > 16M\n");
+ if ( initrd_start > (16<<20))
+ puts("initrd_start > 16M\n");
+
+
+ puts("Uncompressing Linux...");
+ method = get_method(0);
+ work(0, 0);
puts("done.\n");
+
puts("Now booting the kernel\n");
- /*return (TotalMemory);*/ /* Later this can be a pointer to saved residual data */
- return &hold_residual;
+ return (unsigned long)&hold_residual;
}
show_residual_data(RESIDUAL *res)
{
puts("Residual data: "); puthex(res->ResidualLength); puts(" bytes\n");
- puts("Total memory: "); puthex(res->TotalMemory); puts("\n");
#if 0
puts("Residual structure = "); puthex(sizeof(*res)); puts(" bytes\n");
dump_buf(&hold_residual, 32);
@@ -407,14 +576,14 @@ cksum_data()
{
unsigned int *ptr, len, cksum, cnt;
cksum = cnt = 0;
- ptr = input_data;
+ ptr = (unsigned int *)zimage_start;
puts("Checksums: ");
- for (len = 0; len < input_len; len += 4) {
+ for (len = 0; len < zimage_size; len += 4) {
cksum ^= *ptr++;
if (len && ((len & 0x0FFF) == 0)) {
if (cnt == 0) {
puts("\n [");
- puthex(ptr-1);
+ puthex((unsigned long)ptr-1);
puts("] ");
}
puthex(cksum);
@@ -429,7 +598,7 @@ cksum_data()
puts("Data cksum = "); puthex(cksum); puts("\n");
}
-cksum_text()
+void cksum_text(void)
{
extern int start, etext;
unsigned int *ptr, len, text_len, cksum, cnt;
@@ -442,7 +611,7 @@ cksum_text()
if (len && ((len & 0x0FFF) == 0)) {
if (cnt == 0) {
puts("\n [");
- puthex(ptr-1);
+ puthex((unsigned long)ptr-1);
puts("] ");
}
puthex(cksum);
@@ -457,24 +626,24 @@ cksum_text()
puts("TEXT cksum = "); puthex(cksum); puts("\n");
}
-verify_data(unsigned long load_addr)
+void verify_data(unsigned long load_addr)
{
extern int start, etext;
unsigned int *orig_ptr, *copy_ptr, len, errors;
errors = 0;
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
errors++;
}
}
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
- dump_buf(copy_ptr-1, 128);
- dump_buf(orig_ptr-1, 128);
+ dump_buf((unsigned char *) (copy_ptr-1), 128);
+ dump_buf((unsigned char *) (orig_ptr-1), 128);
puts("Total errors = "); puthex(errors*4); puts("\n");
while (1) ;
}
@@ -486,9 +655,9 @@ test_data(unsigned long load_addr)
extern int start, etext;
unsigned int *orig_ptr, *copy_ptr, len, errors;
errors = 0;
- copy_ptr = input_data;
- orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
- for (len = 0; len < input_len; len += 4) {
+ copy_ptr = (unsigned int *)zimage_start;
+ orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+ for (len = 0; len < zimage_size; len += 4) {
if (*copy_ptr++ != *orig_ptr++) {
errors++;
}
@@ -532,7 +701,7 @@ void dump_buf(unsigned char *p, int s)
}
while (s > 0)
{
- puthex(p); puts(": ");
+ puthex((unsigned long)p); puts(": ");
for (i = 0; i < 16; i++)
{
if (i < s)
diff --git a/arch/ppc/boot/mkprep.c b/arch/ppc/boot/mkprep.c
index 417334670..06b08df98 100644
--- a/arch/ppc/boot/mkprep.c
+++ b/arch/ppc/boot/mkprep.c
@@ -131,17 +131,18 @@ int main(int argc, char *argv[])
argptr++;
/* skip elf header in input file */
- lseek(in_fd, elfhdr_size, SEEK_SET);
+ if ( !prep )
+ lseek(in_fd, elfhdr_size, SEEK_SET);
/* write prep partition if necessary */
if ( prep )
- write_prep_partition( in_fd, out_fd );
+ write_prep_partition( in_fd, out_fd );
/* write input image to bootimage */
if ( asmoutput )
- write_asm_data( in_fd, out_fd );
+ write_asm_data( in_fd, out_fd );
else
- copy_image(in_fd, out_fd);
+ copy_image(in_fd, out_fd);
return 0;
}
@@ -161,28 +162,11 @@ void write_prep_partition(int in, int out)
}
bzero( block, sizeof block );
-
- /* set entry point and boot image size */
- *entry = cpu_to_le32(0x400);
- /* need use size - elfheader? */
+ /* set entry point and boot image size skipping over elf header */
+ *entry = cpu_to_le32(0x400+65536);
*length = cpu_to_le32(info.st_size+0x400);
- /*
- * Writes the "boot record", which contains the partition table, to the
- * diskette, followed by the dummy PC boot block and load image descriptor
- * block. It returns the number of bytes it has written to the load
- * image.
- *
- * The boot record is the first block of the diskette and identifies the
- * "PReP" partition. The "PReP" partition contains the "load image" starting
- * at offset zero within the partition. The first block of the load image is
- * a dummy PC boot block. The second block is the "load image descriptor"
- * which contains the size of the load image and the entry point into the
- * image. The actual boot image starts at offset 1024 bytes (third sector)
- * in the partition.
- */
-
/* sets magic number for msdos partition (used by linux) */
block[510] = 0x55;
block[511] = 0xAA;
@@ -220,7 +204,7 @@ void write_prep_partition(int in, int out)
/* This has to be 0 on the PowerStack? */
pe->beginning_sector = cpu_to_le32(0);
#endif
-/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+ pe->number_of_sectors = cpu_to_le32(2*18*80-1);
write( out, block, sizeof(block) );
write( out, entry, sizeof(*entry) );
diff --git a/arch/ppc/coffboot/.cvsignore b/arch/ppc/coffboot/.cvsignore
new file mode 100644
index 000000000..45968cd8d
--- /dev/null
+++ b/arch/ppc/coffboot/.cvsignore
@@ -0,0 +1,7 @@
+.depend
+vmlinux.coff.initrd
+coffboot
+elfextract
+hack-coff
+vmlinux.coff
+zImage
diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile
new file mode 100644
index 000000000..e145411c6
--- /dev/null
+++ b/arch/ppc/coffboot/Makefile
@@ -0,0 +1,50 @@
+# Makefile for making XCOFF bootable images for booting on PowerMacs
+# using Open Firmware.
+#
+# Paul Mackerras January 1997
+
+# PowerPC (cross) tools
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE =powerpc-eabi-
+endif
+
+HOSTCC = gcc
+HOSTCFLAGS = -O -I$(TOPDIR)/include
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+CFLAGS = -O -fno-builtin -I$(TOPDIR)/include
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
+ --add-section=image=zImage
+LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+GZIP = gzip -9
+
+OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+LIBS = $(TOPDIR)/lib/lib.a
+
+vmlinux.coff: coffboot hack-coff zImage
+ $(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
+ ./hack-coff $@
+
+vmlinux.coff.initrd: coffboot hack-coff zImage ramdisk.image.gz
+ $(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+ coffboot $@
+ ./hack-coff $@
+
+coffboot: $(OBJS) ld.script
+ $(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+
+zImage: $(TOPDIR)/vmlinux elfextract
+ ./elfextract $(TOPDIR)/vmlinux | $(GZIP) >zImage
+
+hack-coff: hack-coff.c
+ $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
+
+elfextract: elfextract.c
+ $(HOSTCC) $(HOSTCFLAGS) -o elfextract elfextract.c
+
+clean:
+ rm -f elfextract hack-coff coffboot zImage vmlinux.coff
+
+fastdep:
diff --git a/arch/ppc/coffboot/crt0.S b/arch/ppc/coffboot/crt0.S
new file mode 100644
index 000000000..43ae4e0ec
--- /dev/null
+++ b/arch/ppc/coffboot/crt0.S
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+ .text
+ .globl _start
+_start:
+ .long __start,0,0
+
+ .globl __start
+__start:
+ lis 9,_start@h
+ lis 8,_etext@ha
+ addi 8,8,_etext@l
+1: dcbf 0,9
+ icbi 0,9
+ addi 9,9,0x20
+ cmplwi 0,9,8
+ blt 1b
+ b start
diff --git a/arch/ppc/coffboot/elfextract.c b/arch/ppc/coffboot/elfextract.c
new file mode 100644
index 000000000..1b50ca475
--- /dev/null
+++ b/arch/ppc/coffboot/elfextract.c
@@ -0,0 +1,98 @@
+/*
+ * Extract the loadable program segment from an elf file.
+ *
+ * Copyright 1996 Paul Mackerras.
+ *
+ * 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 <stdio.h>
+#include <linux/elf.h>
+
+FILE *fi, *fo;
+char *ni, *no;
+char buf[65536];
+
+void
+rd(void *buf, int len)
+{
+ int nr;
+
+ nr = fread(buf, 1, len, fi);
+ if (nr == len)
+ return;
+ if (ferror(fi))
+ fprintf(stderr, "%s: read error\n", ni);
+ else
+ fprintf(stderr, "%s: short file\n", ni);
+ exit(1);
+}
+
+main(int ac, char **av)
+{
+ unsigned nb, len;
+ Elf32_Ehdr eh;
+ Elf32_Phdr ph;
+
+ if (ac > 3 || ac > 1 && av[1][0] == '-') {
+ fprintf(stderr, "Usage: %s [elf-file [image-file]]\n", av[0]);
+ exit(0);
+ }
+
+ fi = stdin;
+ ni = "(stdin)";
+ fo = stdout;
+ no = "(stdout)";
+
+ if (ac > 1) {
+ ni = av[1];
+ fi = fopen(ni, "rb");
+ if (fi == NULL) {
+ perror(ni);
+ exit(1);
+ }
+ }
+
+ rd(&eh, sizeof(eh));
+ if (eh.e_ident[EI_MAG0] != ELFMAG0
+ || eh.e_ident[EI_MAG1] != ELFMAG1
+ || eh.e_ident[EI_MAG2] != ELFMAG2
+ || eh.e_ident[EI_MAG3] != ELFMAG3) {
+ fprintf(stderr, "%s: not an ELF file\n", ni);
+ exit(1);
+ }
+
+ fseek(fi, eh.e_phoff + (eh.e_phnum - 1) * sizeof(ph), 0);
+ rd(&ph, sizeof(ph));
+ if (ph.p_type != PT_LOAD) {
+ fprintf(stderr, "%s: doesn't have a loadable segment\n", ni);
+ exit(1);
+ }
+
+ if (ac > 2) {
+ no = av[2];
+ fo = fopen(no, "wb");
+ if (fo == NULL) {
+ perror(no);
+ exit(1);
+ }
+ }
+
+ fseek(fi, ph.p_offset, 0);
+ for (len = ph.p_filesz; len != 0; len -= nb) {
+ nb = len;
+ if (nb > sizeof(buf))
+ nb = sizeof(buf);
+ rd(buf, nb);
+ if (fwrite(buf, 1, nb, fo) != nb) {
+ fprintf(stderr, "%s: write error\n", no);
+ exit(1);
+ }
+ }
+
+ fclose(fo);
+ fclose(fi);
+ exit(0);
+}
diff --git a/arch/ppc/coffboot/hack-coff.c b/arch/ppc/coffboot/hack-coff.c
new file mode 100644
index 000000000..3dfa8d800
--- /dev/null
+++ b/arch/ppc/coffboot/hack-coff.c
@@ -0,0 +1,79 @@
+/*
+ * hack-coff.c - hack the header of an xcoff file to fill in
+ * a few fields needed by the Open Firmware xcoff loader on
+ * Power Macs but not initialized by objcopy.
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include "rs6000.h"
+
+#define AOUT_MAGIC 0x010b
+
+#define get_16be(x) ((((unsigned char *)(x))[0] << 8) \
+ + ((unsigned char *)(x))[1])
+#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \
+ ((unsigned char *)(x))[1] = (v) & 0xff)
+#define get_32be(x) ((((unsigned char *)(x))[0] << 24) \
+ + (((unsigned char *)(x))[1] << 16) \
+ + (((unsigned char *)(x))[2] << 8) \
+ + ((unsigned char *)(x))[3])
+
+main(int ac, char **av)
+{
+ int fd;
+ int i, nsect;
+ int aoutsz;
+ struct external_filehdr fhdr;
+ AOUTHDR aout;
+ struct external_scnhdr shdr;
+
+ if (ac != 2) {
+ fprintf(stderr, "Usage: hack-coff coff-file\n");
+ exit(1);
+ }
+ if ((fd = open(av[1], 2)) == -1) {
+ perror(av[2]);
+ exit(1);
+ }
+ if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
+ goto readerr;
+ i = get_16be(fhdr.f_magic);
+ if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
+ fprintf(stderr, "%s: not an xcoff file\n", av[1]);
+ exit(1);
+ }
+ aoutsz = get_16be(fhdr.f_opthdr);
+ if (read(fd, &aout, aoutsz) != aoutsz)
+ goto readerr;
+ nsect = get_16be(fhdr.f_nscns);
+ for (i = 0; i < nsect; ++i) {
+ if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
+ goto readerr;
+ if (strcmp(shdr.s_name, ".text") == 0) {
+ put_16be(aout.o_snentry, i+1);
+ put_16be(aout.o_sntext, i+1);
+ } else if (strcmp(shdr.s_name, ".data") == 0) {
+ put_16be(aout.o_sndata, i+1);
+ } else if (strcmp(shdr.s_name, ".bss") == 0) {
+ put_16be(aout.o_snbss, i+1);
+ }
+ }
+ put_16be(aout.magic, AOUT_MAGIC);
+ if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
+ || write(fd, &aout, aoutsz) != aoutsz) {
+ fprintf(stderr, "%s: write error\n", av[1]);
+ exit(1);
+ }
+ close(fd);
+ exit(0);
+
+readerr:
+ fprintf(stderr, "%s: read error or file too short\n", av[1]);
+ exit(1);
+}
diff --git a/arch/ppc/coffboot/ld.script b/arch/ppc/coffboot/ld.script
new file mode 100644
index 000000000..2469ed65d
--- /dev/null
+++ b/arch/ppc/coffboot/ld.script
@@ -0,0 +1,68 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) } =0
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ *(.got1)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ _etext = .;
+ PROVIDE (etext = .);
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
+
diff --git a/arch/ppc/coffboot/main.c b/arch/ppc/coffboot/main.c
new file mode 100644
index 000000000..ab0ee6c4a
--- /dev/null
+++ b/arch/ppc/coffboot/main.c
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+#include "nonstdio.h"
+#include "rs6000.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x) (*(unsigned short *)(x))
+#define get_32be(x) (*(unsigned *)(x))
+
+#define RAM_START 0xc0000000
+#define RAM_END 0xc0800000 /* only 8M mapped with BATs */
+
+#define RAM_FREE 0xc0540000 /* after image of coffboot */
+
+char *avail_ram;
+char *end_avail;
+
+coffboot(int a1, int a2, void *prom)
+{
+ void *options;
+ unsigned loadbase;
+ struct external_filehdr *eh;
+ struct external_scnhdr *sp;
+ struct external_scnhdr *isect, *rsect;
+ int ns, oh, i;
+ unsigned sa, len;
+ void *dst;
+ unsigned char *im;
+ unsigned initrd_start, initrd_size;
+
+ printf("coffboot starting\n");
+ options = finddevice("/options");
+ if (options == (void *) -1)
+ exit();
+ if (getprop(options, "load-base", &loadbase, sizeof(loadbase))
+ != sizeof(loadbase)) {
+ printf("error getting load-base\n");
+ exit();
+ }
+ setup_bats();
+
+ eh = (struct external_filehdr *) loadbase;
+ ns = get_16be(eh->f_nscns);
+ oh = get_16be(eh->f_opthdr);
+
+ sp = (struct external_scnhdr *) (loadbase + sizeof(struct external_filehdr) + oh);
+ isect = rsect = NULL;
+ for (i = 0; i < ns; ++i, ++sp) {
+ if (strcmp(sp->s_name, "image") == 0)
+ isect = sp;
+ else if (strcmp(sp->s_name, "initrd") == 0)
+ rsect = sp;
+ }
+ if (isect == NULL) {
+ printf("image section not found\n");
+ exit();
+ }
+
+ if (rsect != NULL && (initrd_size = get_32be(rsect->s_size)) != 0) {
+ initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+ a1 = initrd_start;
+ a2 = initrd_size;
+ printf("initial ramdisk at %x (%u bytes)\n",
+ initrd_start, initrd_size);
+ memcpy((char *) initrd_start,
+ (char *) (loadbase + get_32be(rsect->s_scnptr)),
+ initrd_size);
+ end_avail = (char *) initrd_start;
+ } else {
+ end_avail = (char *) RAM_END;
+ }
+
+ im = (unsigned char *)(loadbase + get_32be(isect->s_scnptr));
+ len = get_32be(isect->s_size);
+ dst = (void *) RAM_START;
+
+ if (im[0] == 0x1f && im[1] == 0x8b) {
+ void *cp = (void *) RAM_FREE;
+ avail_ram = (void *) (RAM_FREE + ((len + 7) & -8));
+ memcpy(cp, im, len);
+ printf("gunzipping... ");
+ gunzip(dst, 0x400000, cp, &len);
+ printf("done\n");
+
+ } else {
+ memmove(dst, im, len);
+ }
+
+ flush_cache(dst, len);
+
+ sa = *(unsigned *)dst + RAM_START;
+ printf("start address = 0x%x\n", sa);
+
+#if 0
+ pause();
+#endif
+ (*(void (*)())sa)(a1, a2, prom);
+
+ printf("returned?\n");
+
+ pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+ void *p = avail_ram;
+
+ size *= items;
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ printf("oops... out of memory\n");
+ pause();
+ }
+ return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+#define DEFLATED 8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+ z_stream s;
+ int r, i, flags;
+
+ /* skip header */
+ i = 10;
+ flags = src[3];
+ if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+ printf("bad gzipped data\n");
+ exit();
+ }
+ if ((flags & EXTRA_FIELD) != 0)
+ i = 12 + src[10] + (src[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (src[i++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ i += 2;
+ if (i >= *lenp) {
+ printf("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.zalloc = zalloc;
+ s.zfree = zfree;
+ r = inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ printf("inflateInit2 returned %d\n", r);
+ exit();
+ }
+ s.next_in = src + i;
+ s.avail_in = *lenp - i;
+ s.next_out = dst;
+ s.avail_out = dstlen;
+ r = inflate(&s, Z_FINISH);
+ if (r != Z_OK && r != Z_STREAM_END) {
+ printf("inflate returned %d\n", r);
+ exit();
+ }
+ *lenp = s.next_out - (unsigned char *) dst;
+ inflateEnd(&s);
+}
diff --git a/arch/ppc/coffboot/misc.S b/arch/ppc/coffboot/misc.S
new file mode 100644
index 000000000..ae08ee2fa
--- /dev/null
+++ b/arch/ppc/coffboot/misc.S
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+ .text
+
+/*
+ * Use the BAT0 registers to map the 1st 8MB of RAM to 0xc0000000.
+ */
+ .globl setup_bats
+setup_bats:
+ mfpvr 3
+ rlwinm 3,3,16,16,31 /* r3 = 1 for 601, 4 for 604 */
+ cmpi 0,3,1
+ lis 4,0xc000
+ 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 */
+ li 5,2
+ mtdbatu 0,4
+ mtdbatl 0,5
+5: mtibatu 0,4
+ mtibatl 0,5
+ isync
+ blr
+
+/*
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+ .global flush_cache
+flush_cache:
+ addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */
+ rlwinm. 4,4,27,5,31
+ mtctr 4
+ beqlr
+1: dcbf 0,3
+ icbi 0,3
+ addi 3,3,0x20
+ bdnz 1b
+ sync
+ isync
+ blr
diff --git a/arch/ppc/coffboot/nonstdio.h b/arch/ppc/coffboot/nonstdio.h
new file mode 100644
index 000000000..664b8384a
--- /dev/null
+++ b/arch/ppc/coffboot/nonstdio.h
@@ -0,0 +1,18 @@
+/*
+ * 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/coffboot/rs6000.h b/arch/ppc/coffboot/rs6000.h
new file mode 100644
index 000000000..0def1d95d
--- /dev/null
+++ b/arch/ppc/coffboot/rs6000.h
@@ -0,0 +1,243 @@
+/* IBM RS/6000 "XCOFF" file definitions for BFD.
+ Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+ FIXME: Can someone provide a transliteration of this name into ASCII?
+ Using the following chars caused a compiler warning on HIUX (so I replaced
+ them with octal escapes), and isn't useful without an understanding of what
+ character set it is.
+ Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM
+ and John Gilmore of Cygnus Support. */
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+ char f_magic[2]; /* magic number */
+ char f_nscns[2]; /* number of sections */
+ char f_timdat[4]; /* time & date stamp */
+ char f_symptr[4]; /* file pointer to symtab */
+ char f_nsyms[4]; /* number of symtab entries */
+ char f_opthdr[2]; /* sizeof(optional hdr) */
+ char f_flags[2]; /* flags */
+};
+
+ /* IBM RS/6000 */
+#define U802WRMAGIC 0730 /* writeable text segments **chh** */
+#define U802ROMAGIC 0735 /* readonly sharable text segments */
+#define U802TOCMAGIC 0737 /* readonly text segments and TOC */
+
+#define BADMAG(x) \
+ ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
+ (x).f_magic != U802TOCMAGIC)
+
+#define FILHDR struct external_filehdr
+#define FILHSZ 20
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+
+typedef struct
+{
+ unsigned char magic[2]; /* type of file */
+ unsigned char vstamp[2]; /* version stamp */
+ unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */
+ unsigned char dsize[4]; /* initialized data " " */
+ unsigned char bsize[4]; /* uninitialized data " " */
+ unsigned char entry[4]; /* entry pt. */
+ unsigned char text_start[4]; /* base of text used for this file */
+ unsigned char data_start[4]; /* base of data used for this file */
+ unsigned char o_toc[4]; /* address of TOC */
+ unsigned char o_snentry[2]; /* section number of entry point */
+ unsigned char o_sntext[2]; /* section number of .text section */
+ unsigned char o_sndata[2]; /* section number of .data section */
+ unsigned char o_sntoc[2]; /* section number of TOC */
+ unsigned char o_snloader[2]; /* section number of .loader section */
+ unsigned char o_snbss[2]; /* section number of .bss section */
+ unsigned char o_algntext[2]; /* .text alignment */
+ unsigned char o_algndata[2]; /* .data alignment */
+ unsigned char o_modtype[2]; /* module type (??) */
+ unsigned char o_cputype[2]; /* cpu type */
+ unsigned char o_maxstack[4]; /* max stack size (??) */
+ unsigned char o_maxdata[4]; /* max data size (??) */
+ unsigned char o_resv2[12]; /* reserved */
+}
+AOUTHDR;
+
+#define AOUTSZ 72
+#define SMALL_AOUTSZ (28)
+#define AOUTHDRSZ 72
+
+#define RS6K_AOUTHDR_OMAGIC 0x0107 /* old: text & data writeable */
+#define RS6K_AOUTHDR_NMAGIC 0x0108 /* new: text r/o, data r/w */
+#define RS6K_AOUTHDR_ZMAGIC 0x010B /* paged: text r/o, both page-aligned */
+
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+ char s_name[8]; /* section name */
+ char s_paddr[4]; /* physical address, aliased s_nlib */
+ char s_vaddr[4]; /* virtual address */
+ char s_size[4]; /* section size */
+ char s_scnptr[4]; /* file ptr to raw data for section */
+ char s_relptr[4]; /* file ptr to relocation */
+ char s_lnnoptr[4]; /* file ptr to line numbers */
+ char s_nreloc[2]; /* number of relocation entries */
+ char s_nlnno[2]; /* number of line number entries*/
+ char s_flags[4]; /* flags */
+};
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT ".text"
+#define _DATA ".data"
+#define _BSS ".bss"
+#define _PAD ".pad"
+#define _LOADER ".loader"
+
+#define SCNHDR struct external_scnhdr
+#define SCNHSZ 40
+
+/* XCOFF uses a special .loader section with type STYP_LOADER. */
+#define STYP_LOADER 0x1000
+
+/* XCOFF uses a special .debug section with type STYP_DEBUG. */
+#define STYP_DEBUG 0x2000
+
+/* XCOFF handles line number or relocation overflow by creating
+ another section header with STYP_OVRFLO set. */
+#define STYP_OVRFLO 0x8000
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+ union {
+ char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
+ char l_paddr[4]; /* (physical) address of line number */
+ } l_addr;
+ char l_lnno[2]; /* line number */
+};
+
+
+#define LINENO struct external_lineno
+#define LINESZ 6
+
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN 8 /* # characters in a symbol name */
+#define E_FILNMLEN 14 /* # characters in a file name */
+#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
+
+struct external_syment
+{
+ union {
+ char e_name[E_SYMNMLEN];
+ struct {
+ char e_zeroes[4];
+ char e_offset[4];
+ } e;
+ } e;
+ char e_value[4];
+ char e_scnum[2];
+ char e_type[2];
+ char e_sclass[1];
+ char e_numaux[1];
+};
+
+
+
+#define N_BTMASK (017)
+#define N_TMASK (060)
+#define N_BTSHFT (4)
+#define N_TSHIFT (2)
+
+
+union external_auxent {
+ struct {
+ char x_tagndx[4]; /* str, un, or enum tag indx */
+ union {
+ struct {
+ char x_lnno[2]; /* declaration line number */
+ char x_size[2]; /* str/union/array size */
+ } x_lnsz;
+ char x_fsize[4]; /* size of function */
+ } x_misc;
+ union {
+ struct { /* if ISFCN, tag, or .bb */
+ char x_lnnoptr[4]; /* ptr to fcn line # */
+ char x_endndx[4]; /* entry ndx past block end */
+ } x_fcn;
+ struct { /* if ISARY, up to 4 dimen. */
+ char x_dimen[E_DIMNUM][2];
+ } x_ary;
+ } x_fcnary;
+ char x_tvndx[2]; /* tv index */
+ } x_sym;
+
+ union {
+ char x_fname[E_FILNMLEN];
+ struct {
+ char x_zeroes[4];
+ char x_offset[4];
+ } x_n;
+ } x_file;
+
+ struct {
+ char x_scnlen[4]; /* section length */
+ char x_nreloc[2]; /* # relocation entries */
+ char x_nlinno[2]; /* # line numbers */
+ } x_scn;
+
+ struct {
+ char x_tvfill[4]; /* tv fill value */
+ char x_tvlen[2]; /* length of .tv */
+ char x_tvran[2][2]; /* tv range */
+ } x_tv; /* info about .tv section (in auxent of symbol .tv)) */
+
+ struct {
+ unsigned char x_scnlen[4];
+ unsigned char x_parmhash[4];
+ unsigned char x_snhash[2];
+ unsigned char x_smtyp[1];
+ unsigned char x_smclas[1];
+ unsigned char x_stab[4];
+ unsigned char x_snstab[2];
+ } x_csect;
+
+};
+
+#define SYMENT struct external_syment
+#define SYMESZ 18
+#define AUXENT union external_auxent
+#define AUXESZ 18
+#define DBXMASK 0x80 /* for dbx storage mask */
+#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
+
+
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+
+struct external_reloc {
+ char r_vaddr[4];
+ char r_symndx[4];
+ char r_size[1];
+ char r_type[1];
+};
+
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
diff --git a/arch/ppc/coffboot/start.c b/arch/ppc/coffboot/start.c
new file mode 100644
index 000000000..363e65962
--- /dev/null
+++ b/arch/ppc/coffboot/start.c
@@ -0,0 +1,280 @@
+/*
+ * 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.
+ */
+#include <stdarg.h>
+
+int (*prom)();
+
+void *chosen_handle;
+void *stdin;
+void *stdout;
+void *stderr;
+
+void exit(void);
+void *finddevice(const char *name);
+int getprop(void *phandle, const char *name, void *buf, int buflen);
+
+void
+start(int a1, int a2, void *promptr)
+{
+ prom = (int (*)()) promptr;
+ chosen_handle = finddevice("/chosen");
+ if (chosen_handle == (void *) -1)
+ exit();
+ if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
+ exit();
+ stderr = stdout;
+ if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
+ exit();
+
+ coffboot(a1, a2, promptr);
+ for (;;)
+ exit();
+}
+
+int
+write(void *handle, void *ptr, int nb)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *ihandle;
+ void *addr;
+ int len;
+ int actual;
+ } args;
+
+ args.service = "write";
+ args.nargs = 3;
+ args.nret = 1;
+ args.ihandle = handle;
+ args.addr = ptr;
+ args.len = nb;
+ args.actual = -1;
+ (*prom)(&args);
+ return args.actual;
+}
+
+int
+read(void *handle, void *ptr, int nb)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *ihandle;
+ void *addr;
+ int len;
+ int actual;
+ } args;
+
+ args.service = "read";
+ args.nargs = 3;
+ args.nret = 1;
+ args.ihandle = handle;
+ args.addr = ptr;
+ args.len = nb;
+ args.actual = -1;
+ (*prom)(&args);
+ return args.actual;
+}
+
+void
+exit()
+{
+ struct prom_args {
+ char *service;
+ } args;
+
+ for (;;) {
+ args.service = "exit";
+ (*prom)(&args);
+ }
+}
+
+void
+pause()
+{
+ struct prom_args {
+ char *service;
+ } args;
+
+ args.service = "enter";
+ (*prom)(&args);
+}
+
+void *
+finddevice(const char *name)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ const char *devspec;
+ void *phandle;
+ } args;
+
+ args.service = "finddevice";
+ args.nargs = 1;
+ args.nret = 1;
+ args.devspec = name;
+ args.phandle = (void *) -1;
+ (*prom)(&args);
+ return args.phandle;
+}
+
+int
+getprop(void *phandle, const char *name, void *buf, int buflen)
+{
+ struct prom_args {
+ char *service;
+ int nargs;
+ int nret;
+ void *phandle;
+ const char *name;
+ void *buf;
+ int buflen;
+ int size;
+ } args;
+
+ args.service = "getprop";
+ args.nargs = 4;
+ args.nret = 1;
+ args.phandle = phandle;
+ args.name = name;
+ args.buf = buf;
+ args.buflen = buflen;
+ args.size = -1;
+ (*prom)(&args);
+ return args.size;
+}
+
+int
+putc(int c, void *f)
+{
+ char ch = c;
+
+ if (c == '\n')
+ putc('\r', f);
+ return write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+putchar(int c)
+{
+ return putc(c, stdout);
+}
+
+int
+fputs(char *str, void *f)
+{
+ int n = strlen(str);
+
+ return write(f, str, n) == n? 0: -1;
+}
+
+int
+readchar()
+{
+ char ch;
+
+ for (;;) {
+ switch (read(stdin, &ch, 1)) {
+ case 1:
+ return ch;
+ case -1:
+ printk("read(stdin) returned -1\r\n");
+ return -1;
+ }
+ }
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int
+getchar()
+{
+ int c;
+
+ if (lineleft == 0) {
+ lineptr = line;
+ for (;;) {
+ c = readchar();
+ if (c == -1 || c == 4)
+ break;
+ if (c == '\r' || c == '\n') {
+ *lineptr++ = '\n';
+ putchar('\n');
+ break;
+ }
+ switch (c) {
+ case 0177:
+ case '\b':
+ if (lineptr > line) {
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ --lineptr;
+ }
+ break;
+ case 'U' & 0x1F:
+ while (lineptr > line) {
+ putchar('\b');
+ putchar(' ');
+ putchar('\b');
+ --lineptr;
+ }
+ break;
+ default:
+ if (lineptr >= &line[sizeof(line) - 1])
+ putchar('\a');
+ else {
+ putchar(c);
+ *lineptr++ = c;
+ }
+ }
+ }
+ lineleft = lineptr - line;
+ lineptr = line;
+ }
+ if (lineleft == 0)
+ return -1;
+ --lineleft;
+ return *lineptr++;
+}
+
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+static char sprint_buf[1024];
+
+void
+printk(char *fmt, ...)
+{
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vsprintf(sprint_buf, fmt, args);
+ va_end(args);
+ write(stdout, sprint_buf, n);
+}
+
+int
+printf(char *fmt, ...)
+{
+ va_list args;
+ int n;
+
+ va_start(args, fmt);
+ n = vsprintf(sprint_buf, fmt, args);
+ va_end(args);
+ write(stdout, sprint_buf, n);
+ return n;
+}
diff --git a/arch/ppc/coffboot/string.S b/arch/ppc/coffboot/string.S
new file mode 100644
index 000000000..ba83591b7
--- /dev/null
+++ b/arch/ppc/coffboot/string.S
@@ -0,0 +1,206 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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.
+ */
+#define r0 0
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+
+ .globl strcpy
+strcpy:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strncpy
+strncpy:
+ cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ blr
+
+ .globl strcat
+strcat:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r5)
+ cmpwi 0,r0,0
+ bne 1b
+ addi r5,r5,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strcmp
+strcmp:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r5)
+ cmpwi 1,r3,0
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ beqlr 1
+ beq 1b
+ blr
+
+ .globl strlen
+strlen:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ blr
+
+ .globl memset
+memset:
+ rlwimi r4,r4,8,16,23
+ rlwimi r4,r4,16,0,15
+ addi r6,r3,-4
+ cmplwi 0,r5,4
+ blt 7f
+ stwu r4,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r5,r0,r5
+ subf r6,r0,r6
+ rlwinm r0,r5,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r4,4(r6)
+ bdnz 1b
+6: andi. r5,r5,3
+7: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r6,3
+8: stbu r4,1(r6)
+ bdnz 8b
+ blr
+
+ .globl bcopy
+bcopy:
+ mr r6,r3
+ mr r3,r4
+ mr r4,r6
+ b memcpy
+
+ .globl memmove
+memmove:
+ cmplw 0,r3,r4
+ bgt backwards_memcpy
+ /* fall through */
+
+ .globl memcpy
+memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ 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)
+ lwzu r8,8(r4)
+ stw r7,4(r6)
+ stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,4(r4)
+ addi r5,r5,-4
+ stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+ stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+ stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl backwards_memcpy
+backwards_memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ add r6,r3,r5
+ add r4,r4,r5
+ beq 2f
+ andi. r0,r6,3
+ mtctr r7
+ bne 5f
+1: lwz r7,-4(r4)
+ lwzu r8,-8(r4)
+ stw r7,-4(r6)
+ stwu r8,-8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,-4(r4)
+ subi r5,r5,4
+ stwu r0,-4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+4: lbzu r0,-1(r4)
+ stbu r0,-1(r6)
+ bdnz 4b
+ blr
+5: mtctr r0
+6: lbzu r7,-1(r4)
+ stbu r7,-1(r6)
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl memcmp
+memcmp:
+ cmpwi 0,r5,0
+ blelr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r6)
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ bdnzt 2,1b
+ blr
diff --git a/arch/ppc/coffboot/zlib.c b/arch/ppc/coffboot/zlib.c
new file mode 100644
index 000000000..12d07df41
--- /dev/null
+++ b/arch/ppc/coffboot/zlib.c
@@ -0,0 +1,2143 @@
+/*
+ * 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/08/30 04:51:48 ralf 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/coffboot/zlib.h b/arch/ppc/coffboot/zlib.h
new file mode 100644
index 000000000..f4ab77617
--- /dev/null
+++ b/arch/ppc/coffboot/zlib.h
@@ -0,0 +1,432 @@
+/* $Id: zlib.h,v 1.1 1997/08/30 04:51:49 ralf 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/config.in b/arch/ppc/config.in
index 9df35fa24..1cea7ce3f 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -1,36 +1,44 @@
-#
+# $Id: config.in,v 1.19 1997/09/04 01:54:26 davem Exp $
# For a description of the syntax of this configuration file,
# see the Configure script.
#
mainmenu_name "Linux/PowerPC Kernel Configuration"
-if [ "`uname`" != "Linux" ]; then
+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
-bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
-bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
-bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+bool 'Build PowerMac Kernel (not PReP or CHRP)?' CONFIG_PMAC
+bool 'Build PReP Kernel (not PowerMac or CHRP)?' CONFIG_PREP
+bool 'Build CHRP Kernel (not PReP or PowerMac)?' CONFIG_CHRP
+
choice 'Processor type' \
- "Common CONFIG_MCOMMON \
- 601 CONFIG_M601 \
- 603 CONFIG_M603 \
- 604 CONFIG_M604" Common
+ "Common CONFIG_COMMON \
+ 601 CONFIG_601 \
+ 603 CONFIG_603 \
+ 604 CONFIG_604" Common
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
fi
-
-mainmenu_option next_comment
define_bool CONFIG_PCI y
-bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+if [ "$CONFIG_PREP" = "y" ]; then
+ bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+fi
bool 'Networking support' CONFIG_NET
bool 'Sysctl support' CONFIG_SYSCTL
bool 'System V IPC' CONFIG_SYSVIPC
@@ -39,8 +47,24 @@ bool 'System V IPC' CONFIG_SYSVIPC
define_bool CONFIG_BINFMT_ELF y
define_bool CONFIG_KERNEL_ELF y
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
+
+if [ "$CONFIG_PMAC" = "y" ]; then
+ define_bool CONFIG_PMAC_CONSOLE y
+ define_bool CONFIG_MAC_KEYBOARD y
+ define_bool CONFIG_MAC_FLOPPY y
+ bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+ bool 'Include xmon kernel debugger' CONFIG_XMON
+fi
+
+if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then
+ bool 'Support for ATI Mach64 display cards' CONFIG_ATY_VIDEO
+ bool 'Support for IMS Twin Turbo display card' CONFIG_IMSTT_VIDEO
+else
+ define_bool CONFIG_VGA_CONSOLE y
+fi
+endmenu
source drivers/pnp/Config.in
source drivers/block/Config.in
@@ -83,6 +107,7 @@ fi
endmenu
source fs/Config.in
+
source drivers/char/Config.in
mainmenu_option next_comment
@@ -93,12 +118,12 @@ if [ "$CONFIG_SOUND" != "n" ]; then
fi
endmenu
-mainmenu_option next_comment
+#mainmenu_option next_comment
#comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
#bool 'Kernel profiling support' CONFIG_PROFILE
#if [ "$CONFIG_PROFILE" = "y" ]; then
# int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
#fi
-endmenu
+#endmenu
diff --git a/arch/ppc/defconfig b/arch/ppc/defconfig
new file mode 100644
index 000000000..ea39e83ea
--- /dev/null
+++ b/arch/ppc/defconfig
@@ -0,0 +1,250 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+CONFIG_MCOMMON=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_VGA_CONSOLE=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=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_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+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
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# 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_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN 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=y
+# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
+CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
+CONFIG_SCSI_NCR53C8XX_SYNC=5
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 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_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SOFTCURSOR is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER 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_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff --git a/arch/ppc/ignore b/arch/ppc/ignore
new file mode 100644
index 000000000..693fff61a
--- /dev/null
+++ b/arch/ppc/ignore
@@ -0,0 +1,65 @@
+.config
+compile.h
+.version
+.objects
+.blurb
+*.cort
+*.paul
+*.old
+.defines
+version.h
+find_name
+checks
+#*
+.objects
+.object_files
+System.map
+asm
+.menuconfig*
+CVS
+ppc_defs.h
+mk_defs
+mkprep
+*.s
+.depend
+.hdepend
+*~
+*.o
+znetboot
+zvmlinux
+vmlinux
+zImage
+hack-coff
+coffboot
+vmlinux.coff
+.depend
+.cvsignore
+RCS
+SCCS
+CVS.adm
+RCSLOG
+cvslog.*
+tags
+TAGS
+.make.state
+.nse_depinfo
+*~
+#*
+.#*
+,*
+_$*
+*$
+*.old
+*.bak
+*.BAK
+*.orig
+*.rej
+*.a
+*.olb
+*.o
+*.obj
+*.so
+*.exe
+*.Z
+*.elc
+*.ln
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 941cd9e38..6fd50a6fb 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -7,39 +7,21 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.S.s:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
.S.o:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
- $(AS) $(ASFLAGS) -o $*.o $*.s
- rm $*.s
+ $(CC) -D__ASSEMBLY__ -c $< -o $*.o
-HOST_CC = gcc
-
-OBJS = misc.o port_io.o pci.o traps.o process.o \
- signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
+O_TARGET := kernel.o
+O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
+ align.o ptrace.o irq.o openpic.o bitops.o ppc_htab.o idle.o \
+ time.o prep_time.o pmac_time.o chrp_time.o \
+ setup.o prep_setup.o pmac_setup.o pmac_support.o chrp_setup.o \
+ pci.o prep_pci.o pmac_pci.o chrp_pci.o \
+ residual.o prom.o
+OX_OBJS := ppc_ksyms.o
all: head.o kernel.o
-head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
-
-ifeq ($(CONFIG_PREP),y)
-OBJS += prep_setup.o prep_time.o
-endif
-
-ifeq ($(CONFIG_PMAC),y)
-OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
-endif
-
-ifeq ($(CONFIG_MODULES),y)
-OBJS = ksyms.o
-endif
+head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
ppc_defs.h: mk_defs.c ppc_defs.head \
$(TOPDIR)/include/asm/mmu.h \
@@ -52,25 +34,7 @@ ppc_defs.h: mk_defs.c ppc_defs.head \
rm mk_defs.s
checks: checks.c
- $(HOSTCC) ${CFLAGS} -o checks checks.c
- checks
-
-kernel.o: $(OBJS)
- $(LD) -r -o kernel.o $(OBJS)
+ $(HOSTCC) -fno-builtin -I$(TOPDIR)/include -D__KERNEL__ -o checks checks.c
+ ./checks
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
- $(CPP) -M *.S *.c > .depend
-
-modules:
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
new file mode 100644
index 000000000..39cb04f77
--- /dev/null
+++ b/arch/ppc/kernel/align.c
@@ -0,0 +1,290 @@
+/*
+ * align.c - handle alignment exceptions for the Power PC.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+struct aligninfo {
+ unsigned char len;
+ unsigned char flags;
+};
+
+#define INVALID { 0, 0 }
+
+#define LD 1 /* load */
+#define ST 2 /* store */
+#define SE 4 /* sign-extend value */
+#define F 8 /* to/from fp regs */
+#define U 0x10 /* update index register */
+#define M 0x20 /* multiple load/store */
+#define S 0x40 /* single-precision fp, or byte-swap value */
+#define HARD 0x80 /* string, stwcx. */
+
+/*
+ * The PowerPC stores certain bits of the instruction that caused the
+ * alignment exception in the DSISR register. This array maps those
+ * bits to information about the operand length and what the
+ * instruction would do.
+ */
+static struct aligninfo aligninfo[128] = {
+ { 4, LD }, /* 00 0 0000: lwz / lwarx */
+ INVALID, /* 00 0 0001 */
+ { 4, ST }, /* 00 0 0010: stw */
+ INVALID, /* 00 0 0011 */
+ { 2, LD }, /* 00 0 0100: lhz */
+ { 2, LD+SE }, /* 00 0 0101: lha */
+ { 2, ST }, /* 00 0 0110: sth */
+ { 4, LD+M }, /* 00 0 0111: lmw */
+ { 4, LD+F+S }, /* 00 0 1000: lfs */
+ { 8, LD+F }, /* 00 0 1001: lfd */
+ { 4, ST+F+S }, /* 00 0 1010: stfs */
+ { 8, ST+F }, /* 00 0 1011: stfd */
+ INVALID, /* 00 0 1100 */
+ INVALID, /* 00 0 1101 */
+ INVALID, /* 00 0 1110 */
+ INVALID, /* 00 0 1111 */
+ { 4, LD+U }, /* 00 1 0000: lwzu */
+ INVALID, /* 00 1 0001 */
+ { 4, ST+U }, /* 00 1 0010: stwu */
+ INVALID, /* 00 1 0011 */
+ { 2, LD+U }, /* 00 1 0100: lhzu */
+ { 2, LD+SE+U }, /* 00 1 0101: lhau */
+ { 2, ST+U }, /* 00 1 0110: sthu */
+ { 4, ST+M }, /* 00 1 0111: stmw */
+ { 4, LD+F+S+U }, /* 00 1 1000: lfsu */
+ { 8, LD+F+U }, /* 00 1 1001: lfdu */
+ { 4, ST+F+S+U }, /* 00 1 1010: stfsu */
+ { 8, ST+F+U }, /* 00 1 1011: stfdu */
+ INVALID, /* 00 1 1100 */
+ INVALID, /* 00 1 1101 */
+ INVALID, /* 00 1 1110 */
+ INVALID, /* 00 1 1111 */
+ INVALID, /* 01 0 0000 */
+ INVALID, /* 01 0 0001 */
+ INVALID, /* 01 0 0010 */
+ INVALID, /* 01 0 0011 */
+ INVALID, /* 01 0 0100 */
+ INVALID, /* 01 0 0101: lwax?? */
+ INVALID, /* 01 0 0110 */
+ INVALID, /* 01 0 0111 */
+ { 0, LD+HARD }, /* 01 0 1000: lswx */
+ { 0, LD+HARD }, /* 01 0 1001: lswi */
+ { 0, ST+HARD }, /* 01 0 1010: stswx */
+ { 0, ST+HARD }, /* 01 0 1011: stswi */
+ INVALID, /* 01 0 1100 */
+ INVALID, /* 01 0 1101 */
+ INVALID, /* 01 0 1110 */
+ INVALID, /* 01 0 1111 */
+ INVALID, /* 01 1 0000 */
+ INVALID, /* 01 1 0001 */
+ INVALID, /* 01 1 0010 */
+ INVALID, /* 01 1 0011 */
+ INVALID, /* 01 1 0100 */
+ INVALID, /* 01 1 0101: lwaux?? */
+ INVALID, /* 01 1 0110 */
+ INVALID, /* 01 1 0111 */
+ INVALID, /* 01 1 1000 */
+ INVALID, /* 01 1 1001 */
+ INVALID, /* 01 1 1010 */
+ INVALID, /* 01 1 1011 */
+ INVALID, /* 01 1 1100 */
+ INVALID, /* 01 1 1101 */
+ INVALID, /* 01 1 1110 */
+ INVALID, /* 01 1 1111 */
+ INVALID, /* 10 0 0000 */
+ INVALID, /* 10 0 0001 */
+ { 0, ST+HARD }, /* 10 0 0010: stwcx. */
+ INVALID, /* 10 0 0011 */
+ INVALID, /* 10 0 0100 */
+ INVALID, /* 10 0 0101 */
+ INVALID, /* 10 0 0110 */
+ INVALID, /* 10 0 0111 */
+ { 4, LD+S }, /* 10 0 1000: lwbrx */
+ INVALID, /* 10 0 1001 */
+ { 4, ST+S }, /* 10 0 1010: stwbrx */
+ INVALID, /* 10 0 1011 */
+ { 2, LD+S }, /* 10 0 1100: lhbrx */
+ INVALID, /* 10 0 1101 */
+ { 2, ST+S }, /* 10 0 1110: sthbrx */
+ INVALID, /* 10 0 1111 */
+ INVALID, /* 10 1 0000 */
+ INVALID, /* 10 1 0001 */
+ INVALID, /* 10 1 0010 */
+ INVALID, /* 10 1 0011 */
+ INVALID, /* 10 1 0100 */
+ INVALID, /* 10 1 0101 */
+ INVALID, /* 10 1 0110 */
+ INVALID, /* 10 1 0111 */
+ INVALID, /* 10 1 1000 */
+ INVALID, /* 10 1 1001 */
+ INVALID, /* 10 1 1010 */
+ INVALID, /* 10 1 1011 */
+ INVALID, /* 10 1 1100 */
+ INVALID, /* 10 1 1101 */
+ INVALID, /* 10 1 1110 */
+ { 0, ST+HARD }, /* 10 1 1111: dcbz */
+ { 4, LD }, /* 11 0 0000: lwzx */
+ INVALID, /* 11 0 0001 */
+ { 4, ST }, /* 11 0 0010: stwx */
+ INVALID, /* 11 0 0011 */
+ { 2, LD }, /* 11 0 0100: lhzx */
+ { 2, LD+SE }, /* 11 0 0101: lhax */
+ { 2, ST }, /* 11 0 0110: sthx */
+ INVALID, /* 11 0 0111 */
+ { 4, LD+F+S }, /* 11 0 1000: lfsx */
+ { 8, LD+F }, /* 11 0 1001: lfdx */
+ { 4, ST+F+S }, /* 11 0 1010: stfsx */
+ { 8, ST+F }, /* 11 0 1011: stfdx */
+ INVALID, /* 11 0 1100 */
+ INVALID, /* 11 0 1101 */
+ INVALID, /* 11 0 1110 */
+ INVALID, /* 11 0 1111 */
+ { 4, LD+U }, /* 11 1 0000: lwzux */
+ INVALID, /* 11 1 0001 */
+ { 4, ST+U }, /* 11 1 0010: stwux */
+ INVALID, /* 11 1 0011 */
+ { 2, LD+U }, /* 11 1 0100: lhzux */
+ { 2, LD+SE+U }, /* 11 1 0101: lhaux */
+ { 2, ST+U }, /* 11 1 0110: sthux */
+ INVALID, /* 11 1 0111 */
+ { 4, LD+F+S+U }, /* 11 1 1000: lfsux */
+ { 8, LD+F+U }, /* 11 1 1001: lfdux */
+ { 4, ST+F+S+U }, /* 11 1 1010: stfsux */
+ { 8, ST+F+U }, /* 11 1 1011: stfdux */
+ INVALID, /* 11 1 1100 */
+ INVALID, /* 11 1 1101 */
+ INVALID, /* 11 1 1110 */
+ INVALID, /* 11 1 1111 */
+};
+
+#define SWAP(a, b) (t = (a), (a) = (b), (b) = t)
+
+int
+fix_alignment(struct pt_regs *regs)
+{
+ int instr, nb, flags;
+ int i, t;
+ int reg, areg;
+ unsigned char *addr;
+ union {
+ long l;
+ float f;
+ double d;
+ unsigned char v[8];
+ } data;
+
+ instr = (regs->dsisr >> 10) & 0x7f;
+ nb = aligninfo[instr].len;
+ if (nb == 0)
+ return 0; /* too hard or invalid instruction bits */
+ flags = aligninfo[instr].flags;
+ addr = (unsigned char *) regs->dar;
+ reg = (regs->dsisr >> 5) & 0x1f; /* source/dest register */
+
+ /* Verify the address of the operand */
+ if (user_mode(regs)) {
+ if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+ return -EFAULT; /* bad address */
+ }
+
+ if ((flags & F) && last_task_used_math == current)
+ giveup_fpu();
+
+ if (flags & M)
+ return 0; /* too hard for now */
+
+ /* If we read the operand, copy it in */
+ if (flags & LD) {
+ if (nb == 2) {
+ data.v[0] = data.v[1] = 0;
+ if (__get_user(data.v[2], addr)
+ || __get_user(data.v[3], addr+1))
+ return -EFAULT;
+ } else {
+ for (i = 0; i < nb; ++i)
+ if (__get_user(data.v[i], addr+i))
+ return -EFAULT;
+ }
+ }
+
+ switch (flags & ~U) {
+ case LD+SE:
+ if (data.v[2] >= 0x80)
+ data.v[0] = data.v[1] = -1;
+ /* fall through */
+ case LD:
+ regs->gpr[reg] = data.l;
+ break;
+ case LD+S:
+ if (nb == 2) {
+ SWAP(data.v[2], data.v[3]);
+ } else {
+ SWAP(data.v[0], data.v[3]);
+ SWAP(data.v[1], data.v[2]);
+ }
+ regs->gpr[reg] = data.l;
+ break;
+ case ST:
+ data.l = regs->gpr[reg];
+ break;
+ case ST+S:
+ data.l = regs->gpr[reg];
+ if (nb == 2) {
+ SWAP(data.v[2], data.v[3]);
+ } else {
+ SWAP(data.v[0], data.v[3]);
+ SWAP(data.v[1], data.v[2]);
+ }
+ break;
+ case LD+F:
+ current->tss.fpr[reg] = data.d;
+ break;
+ case ST+F:
+ data.d = current->tss.fpr[reg];
+ break;
+ /* these require some floating point conversions... */
+ /* note that giveup_fpu enables the FPU for the kernel */
+ /* we'd like to use the assignment, but we have to compile
+ * the kernel with -msoft-float so it doesn't use the
+ * fp regs for copying 8-byte objects. */
+ case LD+F+S:
+ giveup_fpu();
+ cvt_fd(&data.f, &current->tss.fpr[reg]);
+ /* current->tss.fpr[reg] = data.f; */
+ break;
+ case ST+F+S:
+ giveup_fpu();
+ cvt_df(&current->tss.fpr[reg], &data.f);
+ /* data.f = current->tss.fpr[reg]; */
+ break;
+ default:
+ printk("align: can't handle flags=%x\n", flags);
+ return 0;
+ }
+
+ if (flags & ST) {
+ if (nb == 2) {
+ if (__put_user(data.v[2], addr)
+ || __put_user(data.v[3], addr+1))
+ return -EFAULT;
+ } else {
+ for (i = 0; i < nb; ++i)
+ if (__put_user(data.v[i], addr+i))
+ return -EFAULT;
+ }
+ }
+
+ if (flags & U) {
+ areg = regs->dsisr & 0x1f; /* register to update */
+ regs->gpr[areg] = regs->dar;
+ }
+
+ return 1;
+}
diff --git a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c
new file mode 100644
index 000000000..fb5a19e3a
--- /dev/null
+++ b/arch/ppc/kernel/bitops.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/kernel.h>
+#include <asm/bitops.h>
+
+/*
+ * I left these here since the problems with "cc" make it difficult to keep
+ * them in bitops.h -- Cort
+ */
+void set_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "set_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ or %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+void clear_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "clear_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ andc %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+void change_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "change_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ xor %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+int test_and_set_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_set_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ or %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+int test_and_clear_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_clear_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ andc %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+int test_and_change_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_change_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ xor %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+/* I put it in bitops.h -- Cort */
+#if 0
+int ffz(unsigned int x)
+{
+ int n;
+
+ x = ~x & (x+1); /* set LS zero to 1, other bits to 0 */
+ __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+ return 31 - n;
+}
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+int find_first_zero_bit(void * addr, int size)
+{
+ unsigned int * p = ((unsigned int *) addr);
+ unsigned int result = 0;
+ unsigned int tmp;
+
+ if (size == 0)
+ return 0;
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+int find_next_zero_bit(void * addr, int size, int offset)
+{
+ unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+ unsigned int result = offset & ~31UL;
+ unsigned int tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if (offset) {
+ tmp = *(p++);
+ tmp |= ~0UL >> (32-offset);
+ if (size < 32)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+found_first:
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+#endif
diff --git a/arch/ppc/kernel/checks.c b/arch/ppc/kernel/checks.c
new file mode 100644
index 000000000..312229552
--- /dev/null
+++ b/arch/ppc/kernel/checks.c
@@ -0,0 +1,57 @@
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+
+/*
+ * Do various before compile checks of data structures
+ * -- Cort
+ */
+int main(void)
+{
+ int ret = 0;
+#if 0
+ if ( sizeof(struct thread_struct) % 16 )
+ {
+ printf("Thread struct is not modulo 16 bytes: "
+ "%d bytes total, %d bytes off\n",
+ sizeof(struct thread_struct),
+ sizeof(struct thread_struct)%16);
+ ret = -1;
+ }
+#endif
+
+ if ( sizeof(struct pt_regs) % 16 )
+ {
+ printf("pt_regs struct is not modulo 16 bytes: "
+ "%d bytes total, %d bytes off\n",
+ sizeof(struct pt_regs),
+ sizeof(struct pt_regs)%16);
+ ret = -1;
+
+ }
+
+ printf("Task size : %d bytes\n"
+ "Tss size : %d bytes\n"
+ "pt_regs size : %d bytes\n"
+ "Kernel stack size: %d bytes\n",
+ sizeof(struct task_struct), sizeof(struct thread_struct),
+ sizeof(struct pt_regs),
+ sizeof(union task_union) - sizeof(struct task_struct));
+ return ret;
+}
diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c
new file mode 100644
index 000000000..8af9ba9d6
--- /dev/null
+++ b/arch/ppc/kernel/chrp_pci.c
@@ -0,0 +1,156 @@
+/*
+ * CHRP pci routines.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/openpic.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hydra.h>
+
+/* LongTrail */
+#define pci_config_addr(bus, dev, offset) \
+ (0xfec00000 | ((bus)<<16) | ((dev)<<8) | (offset))
+
+int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ if (bus > 7) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
+ if (offset == PCI_INTERRUPT_LINE) {
+ /* PCI interrupts are controlled by the OpenPIC */
+ if (*val)
+ *val = openpic_to_irq(*val);
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ if (bus > 7) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ if (bus > 7) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ if (bus > 7)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int chrp_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
+{
+ int num, devfn;
+ unsigned int x, vendev;
+
+ if (vendor == 0xffff)
+ return PCIBIOS_BAD_VENDOR_ID;
+ vendev = (dev_id << 16) + vendor;
+ num = 0;
+ for (devfn = 0; devfn < 32; devfn++) {
+ chrp_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
+ if (x == vendev) {
+ if (index == num) {
+ *bus_ptr = 0;
+ *dev_fn_ptr = devfn<<3;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int chrp_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+ int devnr, x, num;
+
+ num = 0;
+ for (devnr = 0; devnr < 32; devnr++) {
+ chrp_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
+ if ((x>>8) == class_code) {
+ if (index == num) {
+ *bus_ptr = 0;
+ *dev_fn_ptr = devnr<<3;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(volatile struct Hydra *find_hydra(void))
+{
+ u_char bus, dev;
+ volatile struct Hydra *hydra = 0;
+ if (chrp_pcibios_find_device(PCI_VENDOR_ID_APPLE,
+ PCI_DEVICE_ID_APPLE_HYDRA, 0, &bus, &dev)
+ == PCIBIOS_SUCCESSFUL)
+ chrp_pcibios_read_config_dword(bus, dev, PCI_BASE_ADDRESS_0,
+ (unsigned int *)&hydra);
+ return hydra;
+}
+
+__initfunc(void hydra_post_openpic_init(void))
+{
+ openpic_set_sense(HYDRA_INT_SCSI_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCCA_TX_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCCA_RX_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCCB_TX_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCCB_RX_DMA, 0);
+ openpic_set_sense(HYDRA_INT_SCSI, 1);
+ openpic_set_sense(HYDRA_INT_SCCA, 1);
+ openpic_set_sense(HYDRA_INT_SCCB, 1);
+ openpic_set_sense(HYDRA_INT_VIA, 1);
+ openpic_set_sense(HYDRA_INT_ADB, 1);
+ openpic_set_sense(HYDRA_INT_ADB_NMI, 0);
+}
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
new file mode 100644
index 000000000..0a5544b96
--- /dev/null
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -0,0 +1,180 @@
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* for the mac fs */
+kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+extern unsigned char aux_device_present;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+#endif
+
+
+extern char saved_command_line[256];
+
+long TotalMemory;
+
+int
+chrp_get_cpuinfo(char *buffer)
+{
+ int pvr = _get_PVR();
+ int len;
+ char *model;
+
+ switch (pvr>>16)
+ {
+ case 1:
+ model = "601";
+ break;
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ case 9:
+ model = "604e";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+
+ len = sprintf(buffer, "PowerPC %s rev %d.%d\n", model,
+ (pvr & 0xff00) >> 8, pvr & 0xff);
+
+ len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
+ (loops_per_sec+2500)/500000,
+ ((loops_per_sec+2500)/5000) % 100);
+
+#if 0
+ /*
+ * Ooh's and aah's info about zero'd pages in idle task
+ */
+ {
+ extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
+ len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
+ "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
+ zerototal, (zerototal*PAGE_SIZE)>>10,
+ zerocount, (zerocount*PAGE_SIZE)>>10,
+ zeropage_hits,zeropage_calls,
+ /* : 1 below is so we don't div by zero */
+ (zeropage_hits*100) /
+ ((zeropage_calls)?zeropage_calls:1));
+ }
+#endif
+ return len;
+}
+
+__initfunc(void
+chrp_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+ unsigned long * memory_end_p))
+{
+ extern char cmd_line[];
+ extern char _etext[], _edata[], _end[];
+ extern int panic_timeout;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ strcpy( saved_command_line, cmd_line );
+ *cmdline_p = cmd_line;
+
+ *memory_start_p = (unsigned long) Hash+Hash_size;
+ (unsigned long *)*memory_end_p = (unsigned long *)(TotalMemory+KERNELBASE);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_sec = 50000000;
+
+ /* reboot on panic */
+ panic_timeout = 180;
+
+ init_task.mm->start_code = PAGE_OFFSET;
+ init_task.mm->end_code = (unsigned long) _etext;
+ init_task.mm->end_data = (unsigned long) _edata;
+ init_task.mm->brk = (unsigned long) _end;
+
+ aux_device_present = 0xaa;
+
+ switch ( _machine )
+ {
+ case _MACH_chrp:
+ ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+ break;
+ }
+
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+ ROOT_DEV = to_kdev_t(0x0200); /* floppy */
+ rd_prompt = 1;
+ rd_doload = 1;
+ rd_image_start = 0;
+#endif
+ /* 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
+
+ printk("Boot arguments: %s\n", cmd_line);
+
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+}
diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c
new file mode 100644
index 000000000..bf58953cd
--- /dev/null
+++ b/arch/ppc/kernel/chrp_time.c
@@ -0,0 +1,132 @@
+/*
+ * linux/arch/i386/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * Adapted for PowerPC (PreP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * copied and modified from intel version
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+int chrp_cmos_clock_read(int addr)
+{
+ outb(addr>>8, NVRAM_AS1);
+ outb(addr, NVRAM_AS0);
+ return (inb(NVRAM_DATA));
+}
+
+void chrp_cmos_clock_write(unsigned long val, int addr)
+{
+ outb(addr>>8, NVRAM_AS1);
+ outb(addr, NVRAM_AS0);
+ outb(val,NVRAM_DATA);
+ return;
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+int chrp_set_rtc_time(unsigned long nowtime)
+{
+ unsigned char save_control, save_freq_select;
+ struct rtc_time tm;
+
+ to_tm(nowtime, &tm);
+
+ save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
+
+ chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+ chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ tm.tm_year -= 1900;
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_year);
+ }
+ chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+ chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+ chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+ chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+ chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+ chrp_cmos_clock_write(tm.tm_year,RTC_YEAR);
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ chrp_cmos_clock_write(save_control, RTC_CONTROL);
+ chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+
+ if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+ time_state = TIME_OK;
+ return 0;
+}
+
+unsigned long chrp_get_rtc_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = chrp_cmos_clock_read(RTC_SECONDS);
+ min = chrp_cmos_clock_read(RTC_MINUTES);
+ hour = chrp_cmos_clock_read(RTC_HOURS);
+ day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH);
+ mon = chrp_cmos_clock_read(RTC_MONTH);
+ year = chrp_cmos_clock_read(RTC_YEAR);
+ } while (sec != chrp_cmos_clock_read(RTC_SECONDS));
+ if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 25f2dd8a0..3038e8cc1 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -45,14 +45,13 @@
#define TOPHYS(x) (x - KERNELBASE)
-
/* this is a very kludgey way of loading up the BATs on the
prep system. I'll kill this horrible macro and write
something clean when I have a chance -- Cort
*/
#define LOAD_BATS(RA,RB) \
mfspr RA,PVR ; \
- srwi r5,r5,16 ; \
+ srwi RA,RA,16 ; \
cmpi 0,RA,1 ; \
beq 199f ; \
/* load bats for 60x */ ; \
@@ -132,21 +131,10 @@
mtspr DBAT3L,RB ; \
200:
-
-
-
.text
.globl _stext
_stext:
-#ifdef CONFIG_PREP
- . = 0x100
-_GLOBAL(HardReset)
- b _start
-
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_PMAC
/*
* _start is defined this way because the XCOFF loader in the OpenFirmware
* on the powermac expects the entry point to be a procedure descriptor.
@@ -156,7 +144,7 @@ _GLOBAL(HardReset)
_start:
.long TOPHYS(__start),0,0
-/*
+/* PMAC
* Enter here with the kernel text, data and bss loaded starting at
* 0, running with virtual == physical mapping.
* r5 points to the prom entry point (the client interface handler
@@ -165,41 +153,71 @@ _start:
* pointer (r1) points to just below the end of the half-meg region
* from 0x380000 - 0x400000, which is mapped in already.
*/
+/* 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
+ * of the regs is:
+ * r3: ptr to residual data
+ * r4: initrd_start or if no initrd then 0
+ * r5: initrd_end - unused if r4 is 0
+ * r6: Start of command line string
+ * r7: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort
+ */
+
.globl __start
__start:
/*
- * Use the first pair of BAT registers to map the 1st 8MB
+ * Use the first pair of BAT registers to map the 1st 16MB
* of RAM to KERNELBASE.
*/
- mfspr r9,PVR
- rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
- cmpi 0,r9,1
- lis r7,KERNELBASE@h
- bne 4f
- ori r7,r7,4 /* set up BAT registers for 601 */
- li r8,0x7f
- b 5f
-4: ori r7,r7,0xff /* set up BAT registers for 604 */
- li r8,2
- mtspr DBAT0U,r7
- mtspr DBAT0L,r8
-5: mtspr IBAT0U,r7
- mtspr IBAT0L,r8
- isync
-
+ 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
+ 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
/*
- * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
- * refer to addresses of data items, procedures, etc. normally.
+ * 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
*/
- lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
- addi r7,r7,start_here@l
- mtlr r7
- blr
-#endif /* CONFIG_PMAC */
-
-
-
+ mfmsr r0
+ ori r0,r0,MSR_DR|MSR_IR
+ mtspr SRR1,r0
+ lis r0,start_here@h
+ ori r0,r0,start_here@l
+ 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
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
+ */
+#define STACK_UNDERHEAD 64
/*
* Macros for storing registers into and loading registers from
@@ -286,10 +304,8 @@ label: \
.long hdlr; \
.long int_return
-#ifndef CONFIG_PREP
/* System reset */
STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif /* ndef CONFIG_PREP */
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -319,7 +335,7 @@ DataAccess:
/* Instruction access exception */
. = 0x400
-InstructionAccess:
+InstructionAccess:
EXCEPTION_PROLOG
andis. r0,r23,0x4000 /* no pte found? */
beq 1f /* if so, try to put a PTE */
@@ -338,7 +354,7 @@ InstructionAccess:
.long int_return
/* External interrupt */
- STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+ STD_EXCEPTION(0x500, HardwareInterrupt, do_IRQ)
/* Alignment exception */
. = 0x600
@@ -376,21 +392,7 @@ FPUnavailable:
.long KernelFP
.long int_return
-/* Decrementer */
-#ifdef CONFIG_PREP
-/* - ignored for now... */
-_ORG(0x0900)
- mtspr SPRG0,r1
- lis r1,0x7FFF
- ori r1,r1,0xFFFF
- mtspr DEC,r1
- mfspr r1,SPRG0
- rfi
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_PMAC
STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
-#endif /* CONFIG_PMAC */
-
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
@@ -596,11 +598,6 @@ transfer_to_handler:
andi. r23,r23,MSR_PR
mfspr r23,SPRG3 /* if from user, fix up tss */
beq 2f
-#ifdef CONFIG_PMAC
- lwz r24,GPR1(r21)
- stw r22,LAST_PC(r23)
- stw r24,USER_STACK(r23)
-#endif /* CONFIG_PMAC */
addi r24,r1,STACK_FRAME_OVERHEAD
stw r24,PT_REGS(r23)
2: addi r2,r23,-TSS /* set r2 to current */
@@ -630,7 +627,7 @@ load_up_fpu:
REST_32FPRS(0, r5)
/* use last_task_used_math instead of fpu_tss */
- lis r3,last_task_used_math@h/*a*/
+ lis r3,last_task_used_math@ha
addis r3,r3,-KERNELBASE@h
subi r4,r5,TSS
addis r4,r4,KERNELBASE@h
@@ -654,7 +651,7 @@ load_up_fpu:
REST_GPR(20, r21)
REST_2GPRS(22, r21)
lwz r21,GPR21(r21)
- SYNC
+ SYNC
rfi
/*
@@ -682,14 +679,15 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
.globl hash_page
hash_page:
/* Get PTE (linux-style) and check access */
- lwz r5,PG_TABLES(r5) /* task's page tables */
- lis r2,-KERNELBASE@h
- add r5,r5,r2 /* convert to phys addr */
+ lwz r5,MM-TSS(r5)
+ addis r5,r5,-KERNELBASE@h /* get physical current->mm */
+ lwz r5,PGD(r5) /* get current->mm->pgd */
+ addis r5,r5,-KERNELBASE@h /* convert to phys addr */
rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
lwz r5,0(r5) /* get pmd entry */
rlwinm. r5,r5,0,0,19 /* extract address of pte page */
beqlr- /* return if no mapping */
- add r2,r5,r2
+ addis r2,r5,-KERNELBASE@h
rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
lwz r6,0(r2) /* get linux-style pte */
ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
@@ -819,58 +817,62 @@ start_here:
rlwinm r9,r9,16,16,31
cmpi 0,r9,1
beq 4f /* not needed for 601 */
- mfspr r7,HID0
- andi. r0,r7,HID0_DCE
- ori r7,r7,HID0_ICE|HID0_DCE
- ori r8,r7,HID0_ICFI
+ 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: sync
- mtspr HID0,r8 /* enable and invalidate caches */
+3:
+ /* turn on dpm for 603 */
+ cmpi 0,r9,3
+ bne 10f
+ oris r11,r11,HID0_DPM@h
+10:
sync
- mtspr HID0,r7 /* enable caches */
+ mtspr HID0,r8 /* enable and invalidate caches */
+ mtspr HID0,r11 /* enable caches */
sync
isync
cmpi 0,r9,4 /* check for 604 */
cmpi 1,r9,9 /* or 604e */
cror 2,2,6
bne 4f
- ori r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
- mtspr HID0,r7 /* superscalar exec & br history tbl */
+ ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+ mtspr HID0,r11 /* superscalar exec & br history tbl */
4:
/* ptr to current */
lis r2,init_task_union@h
ori r2,r2,init_task_union@l
/* ptr to phys current tss */
- addis r3,r2,-KERNELBASE@h
- addi r3,r3,TSS /* init task's TSS */
- mtspr SPRG3,r3
+ addis r11,r2,-KERNELBASE@h
+ addi r11,r11,TSS /* init task's TSS */
+ mtspr SPRG3,r11
/* stack */
addi r1,r2,TASK_UNION_SIZE
li r0,0
stwu r0,-STACK_FRAME_OVERHEAD(r1)
/* Clear out the BSS */
- lis r7,_end@ha
- addi r7,r7,_end@l
+ lis r11,_end@ha
+ addi r11,r11,_end@l
lis r8,__bss_start@ha
addi r8,r8,__bss_start@l
- subf r7,r8,r7
- addi r7,r7,3
- rlwinm. r7,r7,30,2,31
+ subf r11,r8,r11
+ addi r11,r11,3
+ rlwinm. r11,r11,30,2,31
beq 2f
addi r8,r8,-4
- mtctr r7
+ mtctr r11
li r0,0
3: stwu r0,4(r8)
bdnz 3b
2:
/*
- * Initialize the prom stuff (powermacs only) and the MMU.
+ * Initialize the prom stuff and the MMU.
*/
-#ifdef CONFIG_PMAC
+ bl identify_machine
bl prom_init
-#endif /* CONFIG_PMAC */
bl MMU_init
/*
@@ -889,11 +891,6 @@ start_here:
rfi
/* Load up the kernel context */
2:
-#ifdef CONFIG_PREP
- /* reload the bats now that MMU_init() has setup them up -- Cort */
- LOAD_BATS(r3,r0)
-#endif
-
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
mtspr SDR1,r6
@@ -905,8 +902,19 @@ start_here:
addi r3,r3,1 /* increment VSID */
addis r4,r4,0x1000 /* address of next segment */
bdnz 3b
-#ifdef CONFIG_PMAC
- li r0,0 /* zot the BATs */
+
+ lis r3,_machine@ha
+ addis r3,r3,-KERNELBASE@h
+ lwz r0,_machine@l(r3)
+ cmpi 0,r0,_MACH_Pmac
+ beq 99f
+
+/* on prep reload the bats now that MMU_init() has setup them up -- Cort */
+ LOAD_BATS(r3,r14)
+ b 100f
+
+/* on pmac clear the bats out */
+99: li r0,0 /* zot the BATs */
#if 1
mtspr IBAT0U,r0
mtspr IBAT0L,r0
@@ -925,7 +933,7 @@ start_here:
mtspr IBAT3L,r0
mtspr DBAT3U,r0
mtspr DBAT3L,r0
-#endif
+100:
/* Now turn on the MMU for real! */
li r4,MSR_KERNEL
lis r3,start_kernel@h
@@ -934,60 +942,29 @@ start_here:
mtspr SRR1,r4
rfi /* enable MMU and jump to start_kernel */
-#ifdef CONFIG_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
- * of the regs is:
- * R3: End of image
- * R4: Start of image - 0x400
- * R11: Start of command line string
- * R12: End of command line string
- *
- * This just gets a minimal mmu environment setup so we can call
- * start_here() to do the real work.
- * -- Cort
- */
- .globl __start
-__start:
- .globl _start
-_start:
- lis r7,0xF000 /* To mask upper 4 bits */
-/* save pointer to residual data */
- lis r1,resptr@h
- ori r1,r1,resptr@l
- addis r1,r1,-KERNELBASE@h
- stw r3,0(r1)
-/* save argument string */
- li r0,0 /* Null terminate string */
- stb r0,0(r12)
- lis r1,cmd_line@h
- ori r1,r1,cmd_line@l
- addis r1,r1,-KERNELBASE@h
- subi r1,r1,1
- subi r11,r11,1
-00: lbzu r0,1(r11)
- cmpi 0,r0,0
- stbu r0,1(r1)
- bne 00b
-/* setup the msr with sane values */
- li r0,MSR_
- mtmsr r0
-/* turn on the mmu with bats covering kernel enough to get started */
- LOAD_BATS(r3,r0)
+
+ .globl reset_SDR1
+reset_SDR1:
+ lis r6,_SDR1@ha
+ lwz r6,_SDR1@l(r6)
mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
+ li r4,MSR_IR|MSR_DR
+ andc r3,r3,r4
+ lis r4,2f@h
+ addis r4,r4,-KERNELBASE@h
+ ori r4,r4,2f@l
+ mtspr SRR0,r4
mtspr SRR1,r3
- lis r3,10f@h
- ori r3,r3,10f@l
+ rfi
+2: /* load new SDR1 */
+ tlbia
+ mtspr SDR1,r6
+ /* turn the mmu back on */
+ li r4,MSR_KERNEL
+ mflr r3
mtspr SRR0,r3
- SYNC
- rfi /* enables MMU */
-10: lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
- addi r7,r7,start_here@l
- mtlr r7
- blr
-#endif /* CONFIG_PREP */
+ mtspr SRR1,r4
+ rfi
/*
* FP unavailable trap from kernel - print a message, but let
@@ -1022,31 +999,23 @@ giveup_fpu_unmapped:
giveup_fpu:
li r6,0
1:
- addis r3,r6,last_task_used_math@h/*a*/
+ addis r3,r6,last_task_used_math@ha
lwz r4,last_task_used_math@l(r3)
-#if 0
- addis r3,r6,fpu_tss@ha
- lwz r4,fpu_tss@l(r3)
-#endif
mfmsr r5
ori r5,r5,MSR_FP
SYNC
mtmsr r5 /* enable use of fpu now */
SYNC
cmpi 0,r4,0
+ beqlr- /* if no previous owner, done */
add r4,r4,r6
- beqlr /* if no previous owner, done */
addi r4,r4,TSS /* want TSS of last_task_used_math */
li r5,0
stw r5,last_task_used_math@l(r3)
-#if 0
- stw r5,fpu_tss@l(r3)
-#endif
SAVE_32FPRS(0, r4)
mffs fr0
stfd fr0,TSS_FPSCR-4(r4)
lwz r5,PT_REGS(r4)
- lwz r5,PT_REGS(r4)
add r5,r5,r6
lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
li r4,MSR_FP
@@ -1268,7 +1237,7 @@ int_return:
cmpi 0,r4,0
beq+ 1f
addi r3,r1,STACK_FRAME_OVERHEAD
- bl handle_IRQ
+ bl do_IRQ
b 3b
1: lis r4,bh_mask@ha
lwz r4,bh_mask@l(r4)
@@ -1341,7 +1310,7 @@ _GLOBAL(fake_interrupt)
li r0,0x0fac
stw r0,TRAP(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
- bl handle_IRQ
+ bl do_IRQ
addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
lwz r0,4(r1)
mtlr r0
@@ -1384,11 +1353,11 @@ _GLOBAL(flush_instruction_cache)
* and invalidate the corresponding instruction cache blocks.
* This is a no-op on the 601.
*
- * store_cache_range(unsigned long start, unsigned long stop)
+ * flush_icache_range(unsigned long start, unsigned long stop)
*/
CACHE_LINE_SIZE = 32
LG_CACHE_LINE_SIZE = 5
-_GLOBAL(store_cache_range)
+_GLOBAL(flush_icache_range)
mfspr r5,PVR
rlwinm r5,r5,16,16,31
cmpi 0,r5,1
@@ -1521,7 +1490,6 @@ _GLOBAL(flush_hash_page)
_GLOBAL(__main)
blr
-#ifdef CONFIG_PMAC
/*
* These exception handlers are used when we have called a prom
* routine after we have taken over the exception vectors and MMU.
@@ -1716,7 +1684,6 @@ enter_prom:
lwz r31,28(r1)
lwz r1,0(r1)
blr
-#endif
/*
* We put a few things here that have to be page-aligned.
@@ -1726,7 +1693,6 @@ enter_prom:
.data
.globl sdata
sdata:
- .space 2*4096
.globl empty_zero_page
empty_zero_page:
.space 4096
@@ -1735,7 +1701,6 @@ empty_zero_page:
swapper_pg_dir:
.space 4096
-#ifdef CONFIG_PREP
/*
* This space gets a copy of optional info passed to us by the bootstrap
* Used to pass parameters into the kernel like root=/dev/sda1, etc.
@@ -1743,5 +1708,4 @@ swapper_pg_dir:
.globl cmd_line
cmd_line:
.space 512
-#endif /* CONFIG_PREP */
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
new file mode 100644
index 000000000..bfe1a4146
--- /dev/null
+++ b/arch/ppc/kernel/idle.c
@@ -0,0 +1,279 @@
+/*
+ * $Id: idle.c,v 1.4 1997/08/23 22:46:01 cort Exp $
+ *
+ * Idle daemon for PowerPC. Idle daemon will handle any action
+ * that needs to be taken when the system becomes idle.
+ *
+ * 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.
+ */
+#define __KERNEL_SYSCALLS__
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+#include <asm/processor.h>
+
+int zero_paged(void *unused);
+int power_saved(void *unused);
+
+asmlinkage int sys_idle(void)
+{
+ int ret = -EPERM;
+
+ if (current->pid != 0)
+ goto out;
+
+ /*
+ * want one per cpu since it would be nice to have all
+ * processors who aren't doing anything
+ * zero-ing pages since this daemon is lock-free
+ * -- Cort
+ */
+ kernel_thread(zero_paged, NULL, 0);
+ /* no powersaving modes on 601 */
+ /*if( (_get_PVR()>>16) != 1 )
+ kernel_thread(power_saved, NULL, 0);*/
+
+ /* endless loop with no priority at all */
+ current->priority = -100;
+ current->counter = -100;
+ for (;;)
+ {
+ schedule();
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
+unsigned long zerocount = 0; /* # currently pre-zero'd pages */
+unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0; /* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+unsigned long zeropage_calls = 0;/* # zero'd pages request that've been made */
+static struct wait_queue * page_zerod_wait = NULL;
+#define PAGE_THRESHOLD 96 /* how many pages to keep pre-zero'd */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
+{
+ unsigned long page;
+
+ atomic_inc((atomic_t *)&zeropage_calls);
+ if ( zero_list )
+ {
+ /* atomically remove this page from the list */
+ asm ( "101:lwarx %1,0,%2\n" /* reserve zero_list */
+ " lwz %0,0(%1)\n" /* get next -- new zero_list */
+ " stwcx. %0,0,%2\n" /* update zero_list */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list), "=&r" (page)
+ : "r" (&zero_list)
+ : "cc" );
+ /* we can update zerocount after the fact since it is not
+ * used for anything but control of a loop which doesn't
+ * matter since it won't effect anything if it zero's one
+ * less page -- Cort
+ */
+ atomic_inc((atomic_t *)&zeropage_hits);
+ atomic_dec((atomic_t *)&zerocount);
+ wake_up(&page_zerod_wait);
+ resched_force();
+
+ /* zero out the pointer to next in the page */
+ *(unsigned long *)page = 0;
+ return page;
+ }
+ return 0;
+}
+
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+
+int zero_paged(void *unused)
+{
+ extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+ pgd_t *dir;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ sprintf(current->comm, "zero_paged (idle)");
+ current->blocked = ~0UL;
+
+ printk("Started zero_paged\n");
+
+ __sti();
+ while ( 1 )
+ {
+ /* don't want to be pre-empted by swapper or power_saved */
+ current->priority = -98;
+ current->counter = -98;
+ /* we don't want to run until we have something to do */
+ while ( zerocount >= PAGE_THRESHOLD )
+ sleep_on(&page_zerod_wait);
+ /*
+ * Mark a page as reserved so we can mess with it
+ * If we're interrupted we keep this page and our place in it
+ * since we validly hold it and it's reserved for us.
+ */
+ pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+ if ( !pageptr )
+ {
+ printk("!pageptr in zero_paged\n");
+ goto retry;
+ }
+
+ if ( resched_needed() )
+ schedule();
+
+ /*
+ * Make the page no cache so we don't blow our cache with 0's
+ */
+ dir = pgd_offset( init_task.mm, pageptr );
+ if (dir)
+ {
+ pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+ if (pmd && pmd_present(*pmd))
+ {
+ pte = pte_offset(pmd, pageptr & PAGE_MASK);
+ if (pte && pte_present(*pte))
+ {
+ pte_uncache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+ }
+ }
+ }
+
+ /*
+ * Important here to not take time away from real processes.
+ */
+ for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+ {
+ if ( resched_needed() )
+ schedule();
+ *(unsigned long *)(bytecount + pageptr) = 0;
+ }
+
+ /*
+ * If we finished zero-ing out a page add this page to
+ * the zero_list atomically -- we can't use
+ * down/up since we can't sleep in idle.
+ * Disabling interrupts is also a bad idea since we would
+ * steal time away from real processes.
+ * We can also have several zero_paged's running
+ * on different processors so we can't interfere with them.
+ * So we update the list atomically without locking it.
+ * -- Cort
+ */
+ /* turn cache on for this page */
+ pte_cache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+
+ /* atomically add this page to the list */
+ asm ( "101:lwarx %0,0,%1\n" /* reserve zero_list */
+ " stw %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+ " sync\n" /* let store settle */
+#endif
+ " mr %0,%2\n" /* update zero_list in reg */
+ " stwcx. %2,0,%1\n" /* update zero_list in mem */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list)
+ : "r" (&zero_list), "r" (pageptr)
+ : "cc" );
+ /*
+ * This variable is used in the above loop and nowhere
+ * else so the worst that could happen is we would
+ * zero out one more or one less page than we want
+ * per processor on the machine. This is because
+ * we could add our page to the list but not have
+ * zerocount updated yet when another processor
+ * reads it. -- Cort
+ */
+ atomic_inc((atomic_t *)&zerocount);
+ atomic_inc((atomic_t *)&zerototal);
+retry:
+ schedule();
+ }
+}
+
+int power_saved(void *unused)
+{
+ unsigned long msr, hid0;
+ sprintf(current->comm, "power_saved (idle)");
+ current->blocked = ~0UL;
+
+ printk("Power saving daemon started\n");
+
+ __sti();
+ while (1)
+ {
+ /* don't want to be pre-empted by swapper */
+ current->priority = -99;
+ current->counter = -99;
+ /* go ahead and wakeup page_zerod() */
+ wake_up(&page_zerod_wait);
+ schedule();
+ asm volatile(
+ /* clear powersaving modes and set nap mode */
+ "mfspr %3,1008 \n\t"
+ "andc %3,%3,%4 \n\t"
+ "or %3,%3,%5 \n\t"
+ "mtspr 1008,%3 \n\t"
+ /* enter the mode */
+ "mfmsr %0 \n\t"
+ "oris %0,%0,%2 \n\t"
+ "sync \n\t"
+ "mtmsr %0 \n\t"
+ "isync \n\t"
+ : "=&r" (msr)
+ : "0" (msr), "i" (MSR_POW>>16),
+ "r" (hid0),
+ "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+ "r" (HID0_NAP));
+ /*
+ * The ibm carolina spec says that the eagle memory
+ * controller will detect the need for a snoop
+ * and wake up the processor so we don't need to
+ * check for cache operations that need to be
+ * snooped. The ppc book says the run signal
+ * must be asserted while napping for this though.
+ *
+ * Paul, what do you know about the pmac here?
+ * -- Cort
+ */
+ schedule();
+ }
+}
+
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index 171bfaa5c..da3c53697 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -1,13 +1,13 @@
/*
* arch/ppc/kernel/irq.c
*
- * Power Macintosh version
- * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
* Derived from arch/i386/kernel/irq.c
* Copyright (C) 1992 Linus Torvalds
* Adapted from arch/i386 by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu)
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
*
* This file contains the code used by various IRQ handling routines:
* asking for different IRQ's should be done through these routines
@@ -15,11 +15,7 @@
* shouldn't result in any weird surprises, and installing new handlers
* should be easier.
*/
-
-/*
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * Naturally it's not a 1:1 relation, but there are similarities.
- */
+
#include <linux/ptrace.h>
#include <linux/errno.h>
@@ -30,121 +26,164 @@
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/config.h>
-
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/openpic.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/openpic.h>
+
+#include <asm/hydra.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
-#define IRQ_FLAG ((unsigned *)0xf3000020)
-#define IRQ_ENABLE ((unsigned *)0xf3000024)
-#define IRQ_ACK ((unsigned *)0xf3000028)
-#define IRQ_LEVEL ((unsigned *)0xf300002c)
-
-#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
-
-#undef SHOW_IRQ 1
+#undef SHOW_IRQ
+#define OPENPIC_DEBUG
unsigned lost_interrupts = 0;
-
unsigned int local_irq_count[NR_CPUS];
-static struct irqaction irq_action[32];
+static struct irqaction irq_action[NR_IRQS];
+static int spurious_interrupts = 0;
+int __ppc_bh_counter;
+static unsigned int cached_irq_mask = 0xffffffff;
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+
+#define cached_21 (((char *)(&cached_irq_mask))[3])
+#define cached_A1 (((char *)(&cached_irq_mask))[2])
/*
- * This contains the irq mask for both irq controllers
+ * These are set to the appropriate functions by init_IRQ()
*/
-static unsigned int cached_irq_mask = 0xffff;
+void (*mask_and_ack_irq)(int irq_nr);
+void (*set_irq_mask)(int irq_nr);
-#define cached_21 (((char *)(&cached_irq_mask))[0])
-#define cached_A1 (((char *)(&cached_irq_mask))[1])
+/* prep */
+#define PREP_IRQ_MASK (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
+extern unsigned long route_pci_interrupts(void);
-int __ppc_bh_counter;
+/* pmac */
+#define IRQ_FLAG ((unsigned *)0xf3000020)
+#define IRQ_ENABLE ((unsigned *)0xf3000024)
+#define IRQ_ACK ((unsigned *)0xf3000028)
+#define IRQ_LEVEL ((unsigned *)0xf300002c)
+#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
+#define PMAC_IRQ_MASK (~ld_le32(IRQ_ENABLE))
-void *null_handler(int,void *,struct pt_regs *);
+/* chrp */
+volatile struct Hydra *Hydra = NULL;
-/*
- * disable and enable intrs in software. This is used
- * from the non-realtime parts of Linux to disable interrupts.
- * The realtime part disables/enables intrs in the hardware.
- * -- Cort
- */
-unsigned long soft_intr_enable = 1;
-void _soft_cli(void)
+void i8259_mask_and_ack_irq(int irq_nr)
{
- soft_intr_enable = 0;
+ spin_lock(&irq_controller_lock);
+ cached_irq_mask |= 1 << irq_nr;
+ if (irq_nr > 7) {
+ inb(0xA1); /* DUMMY */
+ outb(cached_A1,0xA1);
+ outb(0x62,0x20); /* Specific EOI to cascade */
+ /*outb(0x20,0xA0);*/
+ outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
+ } else {
+ inb(0x21); /* DUMMY */
+ outb(cached_21,0x21);
+ /*outb(0x20,0x20);*/
+ outb(0x60|irq_nr,0x20); /* specific eoi */
+
+ }
+ spin_unlock(&irq_controller_lock);
}
-void _soft_sti(void)
+void pmac_mask_and_ack_irq(int irq_nr)
{
- soft_intr_enable = 1;
- if ( lost_interrupts )
- {
- printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
- fake_interrupt();
- }
+ spin_lock(&irq_controller_lock);
+ cached_irq_mask |= 1 << irq_nr;
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+ out_le32(IRQ_ACK, 1U << irq_nr);
+ spin_unlock(&irq_controller_lock);
}
-void *
-null_handler(int a, void *b, struct pt_regs *regs)
+void chrp_mask_and_ack_irq(int irq_nr)
{
- /*printk("irq.c: null_handler() called. Should not have happened.\n");*/
+ /* spinlocks are done by i8259_mask_and_ack() - Cort */
+ if (is_8259_irq(irq_nr))
+ i8259_mask_and_ack_irq(irq_nr);
+ openpic_eoi(0);
}
-void
-disable_irq(unsigned int irq_nr)
-{
- int s = _disable_interrupts();
- unsigned char mask;
-#ifdef CONFIG_PMAC
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
-#else /* CONFIG_PMAC */
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8)
- {
- cached_21 |= mask;
- outb(cached_21,0x21);
- } else
- {
- cached_A1 |= mask;
+void i8259_set_irq_mask(int irq_nr)
+{
+ if (irq_nr > 7) {
outb(cached_A1,0xA1);
- }
-#endif /* CONFIG_PMAC */
- _enable_interrupts(s);
+ } else {
+ outb(cached_21,0x21);
+ }
}
-void
-enable_irq(unsigned int irq_nr)
+void pmac_set_irq_mask(int irq_nr)
{
- int s = _disable_interrupts();
-#ifdef CONFIG_PMAC
- unsigned bit = 1U << irq_nr;
-
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
- out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
-
+ /* this could be being enabled or disabled - so use cached_irq_mask */
+ out_le32(IRQ_ENABLE, ~cached_irq_mask /* enable all unmasked */ );
/*
* Unfortunately, setting the bit in the enable register
* when the device interrupt is already on *doesn't* set
* the bit in the flag register or request another interrupt.
*/
- if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
- lost_interrupts |= bit;
-#else /* CONFIG_PMAC */
- if (irq_nr < 8) {
- cached_21 &= ~(1 << (irq_nr & 7));
- outb(cached_21,0x21);
+ if ((ld_le32(IRQ_LEVEL) & (1UL<<irq_nr)) && !(ld_le32(IRQ_FLAG) & (1UL<<irq_nr)))
+ lost_interrupts |= (1UL<<irq_nr);
+}
+
+void chrp_set_irq_mask(int irq_nr)
+{
+ if (is_8259_irq(irq_nr)) {
+ i8259_set_irq_mask(irq_nr);
} else
{
- cached_A1 &= ~(1 << (irq_nr-8 & 7));
- outb(cached_A1,0xA1);
- }
-#endif /* CONFIG_PMAC */
+ /* disable? */
+ if ( cached_irq_mask & (1UL<<irq_nr) )
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+ /* enable */
+ else
+ openpic_disable_irq(irq_to_openpic(irq_nr));
+ }
+}
+
+/*
+ * These have to be protected by the spinlock
+ * before being called.
+ */
+static inline void mask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask |= 1 << irq_nr;
+ set_irq_mask(irq_nr);
+}
- _enable_interrupts(s);
+static inline void unmask_irq(unsigned int irq_nr)
+{
+ cached_irq_mask &= ~(1 << irq_nr);
+ set_irq_mask(irq_nr);
}
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_controller_lock, flags);
+ mask_irq(irq_nr);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+ synchronize_irq();
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_controller_lock, flags);
+ unmask_irq(irq_nr);
+ spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
int get_irq_list(char *buf)
{
@@ -153,7 +192,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)
continue;
len += sprintf(buf+len, "%2d: %10u %s",
i, kstat.interrupts[i], action->name);
@@ -162,152 +201,143 @@ int get_irq_list(char *buf)
}
len += sprintf(buf+len, "\n");
}
-/*
- * Linus - should you add NMI counts here ?????
- */
#ifdef __SMP_PROF__
len+=sprintf(buf+len, "IPI: %8lu received\n",
ipi_count);
-#endif
+#endif
+ len += sprintf(buf+len, "99: %10u spurious or short\n",
+ spurious_interrupts);
return len;
}
-asmlinkage void handle_IRQ(struct pt_regs *regs)
+asmlinkage void do_IRQ(struct pt_regs *regs)
{
int irq;
- unsigned bits;
+ unsigned long bits;
struct irqaction *action;
int cpu = smp_processor_id();
+ int status;
hardirq_enter(cpu);
-#ifdef CONFIG_PMAC
- bits = ld_le32(IRQ_FLAG) | lost_interrupts;
- lost_interrupts = 0;
-
- for (irq = NR_IRQS; irq >= 0; --irq)
- if (bits & (1U << irq))
- break;
-#else /* CONFIG_PMAC */
-#if 1
- if ( lost_interrupts )
- {
- irq = ffz(~lost_interrupts);
- lost_interrupts &= ~irq;
- goto retry;
- }
- outb(0x0C, 0x20);
- irq = inb(0x20) & 7;
- if (irq == 2)
+
+ /*
+ * I'll put this ugly mess of code into a function
+ * such as get_pending_irq() or some such clear thing
+ * so we don't have a switch in the irq code and
+ * the chrp code is merged a bit with the prep.
+ * -- Cort
+ */
+ switch ( _machine )
{
-retry_cascade:
- outb(0x0C, 0xA0);
- irq = inb(0xA0);
- /* if no intr left */
- if ( !(irq & 128 ) )
+ case _MACH_Pmac:
+ bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+ lost_interrupts = 0;
+ for (irq = NR_IRQS - 1; irq >= 0; --irq)
+ if (bits & (1U << irq))
+ break;
+ break;
+ case _MACH_chrp:
+ irq = openpic_irq(0);
+ if (irq == IRQ_8259_CASCADE)
+ {
+ /*
+ * This magic address generates a PCI IACK cycle.
+ *
+ * This should go in the above mask/ack code soon. -- Cort
+ */
+ irq = (*(volatile unsigned char *)0xfec80000) & 0x0f;
+ }
+ else if (irq >= 64)
+ {
+ /*
+ * OpenPIC interrupts >64 will be used for other purposes
+ * like interprocessor interrupts and hardware errors
+ */
+#ifdef OPENPIC_DEBUG
+ printk("OpenPIC interrupt %d\n", irq);
+#endif
+ if (irq==99)
+ spurious_interrupts++;
+ }
+ else {
+ /*
+ * Here we should process IPI timer
+ * for now the interrupt is dismissed.
+ */
goto out;
- irq = (irq&7) + 8;
- }
-retry:
+ }
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
+#if 1
+ outb(0x0C, 0x20);
+ irq = inb(0x20) & 7;
+ if (irq == 2)
+ {
+retry_cascade:
+ outb(0x0C, 0xA0);
+ irq = inb(0xA0);
+ /* if no intr left */
+ if ( !(irq & 128 ) )
+ goto out;
+ irq = (irq&7) + 8;
+ }
+ bits = 1UL << irq;
#else
- /* get the irr from the intr controller */
- outb(0x0A, 0x20);
- bits = inb(0x20);
- /* handle cascade */
- if ( bits )
- {
- bits &= 4;
- outb(0x0A, 0xA0);
- bits = inb(0xA0)<<8;
+ /*
+ * get the isr from the intr controller since
+ * the bit in the irr has been cleared
+ */
+ outb(0x0a, 0x20);
+ bits = inb(0x20)&0xff;
+ /* handle cascade */
+ if ( bits & 4 )
+ {
+ bits &= ~4UL;
+ outb(0x0a, 0xA0);
+ bits |= inb(0xA0)<<8;
+ }
+ /* ignore masked irqs */
+ bits &= ~cached_irq_mask;
+#endif
+ break;
}
- /* get lost interrupts */
- bits |= lost_interrupts;
- /* save intrs that are masked out */
- lost_interrupts = bits & cached_irq_mask;
- /* get rid of intrs being masked */
- bits &= ~cached_irq_mask;
- /* non-specifc eoi */
- outb(0x20,0x20);
- if ( bits & 0xff00 )
- outb(0x20,0xA0);
-
- printk("bits %04X lost %04X mask %04x\n",
- bits, lost_interrupts,cached_irq_mask);
-
- for (irq = NR_IRQS; irq >= 0; --irq)
- if (bits & (1U << irq))
- break;
-#endif
-#endif /* CONFIG_PMAC */
if (irq < 0) {
- printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+ printk("Bogus interrupt from PC = %lx\n", regs->nip);
goto out;
}
-#ifdef CONFIG_PMAC
- out_le32(IRQ_ACK, 1U << irq);
-#else /* CONFIG_PMAC */
- /* mask out the irq while handling it */
- disable_irq(irq);
- /*
- * send eoi to interrupt controller right away or lower
- * priority intrs would be ignored even if with intrs enabled
- */
- if (irq > 7)
- {
- outb(0xE0|(irq-8), 0xA0);
- outb(0xE2, 0x20);
- } else
- {
- outb(0xE0|irq, 0x20);
- }
-#endif /* !CONFIG_PMAC */
+ mask_and_ack_irq(irq);
- /*
- * now that we've acked the irq, if intrs are disabled in software
- * we're in the real-time system and non-rt linux has disabled them
- * so we just queue it up and return -- Cort
- */
- if ( ! soft_intr_enable )
- {
- lost_interrupts |= 1UL << irq;
- /* can't printk - kernel expects intrs off! */
- /*printk("irq %d while intrs soft disabled\n", irq);*/
- goto out;
- }
-
- action = irq + irq_action;
+ status = 0;
+ action = irq_action + irq;
kstat.interrupts[irq]++;
- if (action->handler) {
- action->handler(irq, action->dev_id, regs);
- _disable_interrupts(); /* in case the handler turned them on */
+ if ( action && action->handler)
+ {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ /*if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);*/
+ __cli(); /* in case the handler turned them on */
+ spin_lock(&irq_controller_lock);
+ unmask_irq(irq);
+ spin_unlock(&irq_controller_lock);
} else {
+ if ( irq == 7 ) /* i8259 gives us irq 7 on 'short' intrs */
+ spurious_interrupts++;
disable_irq( irq );
}
-#ifdef CONFIG_PREP
- /* re-enable if the interrupt was good and isn't one-shot */
- if ( action->handler && !(action->flags & SA_ONESHOT) )
- enable_irq(irq);
+
/* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
- if ( irq > 7 )
+ if ( is_prep && (irq > 7) )
goto retry_cascade;
-#endif
-
- hardirq_exit(cpu);
- /*
- * This should be conditional: we should really get
- * a return code from the irq handler to tell us
- * whether the handler wants us to do software bottom
- * half handling or not..
- */
- if (1)
- if (bh_active & bh_mask)
- do_bottom_half();
- return;
+ /* do_bottom_half is called if necessary from int_return in head.S */
out:
hardirq_exit(cpu);
-
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -315,13 +345,13 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
{
struct irqaction * action;
unsigned long flags;
-
-#ifdef SHOW_IRQ
+
+#ifdef SHOW_IRQ
printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
irq,handler,devname,dev_id);
#endif /* SHOW_IRQ */
-
- if (irq > NR_IRQS)
+
+ if (irq >= NR_IRQS)
return -EINVAL;
action = irq + irq_action;
if (action->handler)
@@ -339,17 +369,16 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
restore_flags(flags);
return 0;
}
-
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction * action = irq + irq_action;
unsigned long flags;
-#ifdef SHOW_IRQ
+#ifdef SHOW_IRQ
printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
#endif /* SHOW_IRQ */
-
- if (irq > NR_IRQS) {
+
+ if (irq >= NR_IRQS) {
printk("Trying to free IRQ%d\n",irq);
return;
}
@@ -370,114 +399,119 @@ void free_irq(unsigned int irq, void *dev_id)
unsigned long probe_irq_on (void)
{
- unsigned int i, irqs = 0, irqmask;
- unsigned long delay;
-
- /* first, snaffle up any unassigned irqs */
- for (i = 15; i > 0; i--) {
- if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
- enable_irq(i);
- irqs |= (1 << i);
- }
- }
-
- /* wait for spurious interrupts to mask themselves out again */
- for (delay = jiffies + 2; delay > jiffies; ); /* min 10ms delay */
-
- /* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
- for (i = 15; i > 0; i--) {
- if (irqs & (1 << i) & irqmask) {
- irqs ^= (1 << i);
- free_irq(i, NULL);
- }
- }
-#ifdef DEBUG
- printk("probe_irq_on: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
- return irqs;
+ return 0;
}
int probe_irq_off (unsigned long irqs)
{
- unsigned int i, irqmask;
-
- irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
- for (i = 15; i > 0; i--) {
- if (irqs & (1 << i)) {
- free_irq(i, NULL);
- }
- }
-#ifdef SHOW_IRQ
- printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
- irqs &= irqmask;
- if (!irqs)
- return 0;
- i = ffz(~irqs);
- if (irqs != (irqs & (1 << i)))
- i = -i;
- return i;
+ return 0;
}
-void init_IRQ(void)
+__initfunc(static void i8259_init(void))
{
-#ifdef CONFIG_PMAC
- extern void xmon_irq(int, void *, struct pt_regs *);
-
- *IRQ_ENABLE = 0;
- request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
-#else /* CONFIG_PMAC */
- /* Initialize interrupt controllers */
+ /* init master interrupt controller */
outb(0x11, 0x20); /* Start init sequence */
outb(0x40, 0x21); /* Vector base */
-#if 1
- outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
-#else
+ /*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */
outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif
-
outb(0x01, 0x21); /* Select 8086 mode */
outb(0xFF, 0x21); /* Mask all */
-
+
+ /* init slave interrupt controller */
outb(0x11, 0xA0); /* Start init sequence */
outb(0x48, 0xA1); /* Vector base */
-#if 1
- outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
-#else
+ /*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */
outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif
outb(0x01, 0xA1); /* Select 8086 mode */
outb(0xFF, 0xA1); /* Mask all */
-
- /*
- * Program level mode for irq's that 'can' be level triggered.
- * This does not effect irq's 0,1,2 and 8 since they must be
- * edge triggered. This is not the PIC controller. The default
- * here is for edge trigger mode. -- Cort
- */
-#if 0
- outb(0xf8, 0x4d0); /* level triggered */
- outb(0xff, 0x4d1);
-#endif
-#if 0
- outb(0x00, 0x4D0); /* All edge triggered */
- outb(0xCF, 0x4D1); /* Trigger mode */
-#endif
outb(cached_A1, 0xA1);
outb(cached_21, 0x21);
- if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
- printk("Unable to get IRQ2 for cascade\n");
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
+ panic("Could not allocate cascade IRQ!");
enable_irq(2); /* Enable cascade interrupt */
-
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
- /* set timer to periodic mode */
- outb_p(0x34,TIMER_CONTROL); /* binary, mode 2, LSB/MSB, ch 0 */
- /* set the clock to ~100 Hz */
- outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
- outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
-
- route_pci_interrupts();
-#endif /* CONFIG_PMAC */
+}
+
+__initfunc(void init_IRQ(void))
+{
+ extern void xmon_irq(int, void *, struct pt_regs *);
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ mask_and_ack_irq = pmac_mask_and_ack_irq;
+ set_irq_mask = pmac_set_irq_mask;
+
+ *IRQ_ENABLE = 0;
+#ifdef CONFIG_XMON
+ request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#endif /* CONFIG_XMON */
+ break;
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ mask_and_ack_irq = i8259_mask_and_ack_irq;
+ set_irq_mask = i8259_set_irq_mask;
+
+ i8259_init();
+ route_pci_interrupts();
+ /*
+ * According to the Carolina spec from ibm irq's 0,1,2, and 8
+ * must be edge triggered. Also, the pci intrs must be level
+ * triggered and _only_ isa intrs can be level sensitive
+ * which are 3-7,9-12,14-15. 13 is special - it can be level.
+ *
+ * power on default is 0's in both regs - all edge.
+ *
+ * These edge/level control regs allow edge/level status
+ * to be decided on a irq basis instead of on a PIC basis.
+ * It's still pretty ugly.
+ * - Cort
+ */
+ {
+ unsigned char irq_mode1 = 0, irq_mode2 = 0;
+ irq_mode1 = 0; /* to get rid of compiler warnings */
+ /*
+ * On Carolina, irq 15 and 13 must be level (scsi/ide/net).
+ */
+ if ( _machine == _MACH_IBM )
+ irq_mode2 |= 0xa0;
+ /*
+ * Sound on the Powerstack reportedly needs to be edge triggered
+ */
+ if ( _machine == _MACH_Motorola )
+ {
+ /*irq_mode2 &= ~0x04L;
+ outb( irq_mode1 , 0x4d0 );
+ outb( irq_mode2 , 0x4d1 );*/
+ }
+
+ }
+ break;
+ case _MACH_chrp:
+ mask_and_ack_irq = chrp_mask_and_ack_irq;
+ set_irq_mask = chrp_set_irq_mask;
+ if ((Hydra = find_hydra())) {
+ printk("Hydra Mac I/O at %p\n", Hydra);
+ out_le32(&Hydra->Feature_Control, HYDRA_FC_SCC_CELL_EN |
+ HYDRA_FC_SCSI_CELL_EN |
+ HYDRA_FC_SCCA_ENABLE |
+ HYDRA_FC_SCCB_ENABLE |
+ HYDRA_FC_ARB_BYPASS |
+ HYDRA_FC_MPIC_ENABLE |
+ HYDRA_FC_SLOW_SCC_PCLK |
+ HYDRA_FC_MPIC_IS_MASTER);
+ OpenPIC = (volatile struct OpenPIC *)&Hydra->OpenPIC;
+ } else if (!OpenPIC /* && find_xxx */) {
+ printk("Unknown openpic implementation\n");
+ /* other OpenPIC implementations */
+ /* ... */
+ }
+ if (OpenPIC)
+ openpic_init();
+ else
+ panic("No OpenPIC found");
+ if (Hydra)
+ hydra_post_openpic_init();
+ i8259_init();
+ break;
+ }
}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 430cd7a5d..9c6d013b6 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -64,6 +64,7 @@ _GLOBAL(_hard_sti)
mtmsr r3 /* Update machine state */
blr
+#if 0
/*
* Restore 'flags'
* __restore_flags(long val)
@@ -79,11 +80,13 @@ _GLOBAL(__restore_flags)
mtmsr r3
isync
blr
-
+#endif
+
/*
* We were about to enable interrupts but we have to simulate
* some interrupts that were lost by enable_irq first.
*/
+ .globl do_lost_interrupts
do_lost_interrupts:
stwu r1,-16(r1)
mflr r0
@@ -243,7 +246,6 @@ _GLOBAL(_outsl)
bdnz 00b
blr
-#ifdef CONFIG_PMAC
_GLOBAL(ide_insw)
mtctr r5
subi r4,r4,2
@@ -259,7 +261,6 @@ _GLOBAL(ide_outsw)
sthx r5,0,r3
bdnz 00b
blr
-#endif
/*
* Extended precision shifts
@@ -298,7 +299,7 @@ _GLOBAL(abs)
_GLOBAL(_get_SP)
mr r3,r1 /* Close enough */
blr
-
+
_GLOBAL(_get_PVR)
mfspr r3,PVR
blr
@@ -308,6 +309,7 @@ cvt_fd:
lfs 0,0(r3)
stfd 0,0(r4)
blr
+
/*
* Fetch the current SR register
* get_SR(int index)
@@ -317,7 +319,6 @@ _GLOBAL(get_SR)
mr r3,r4
blr
-
_GLOBAL(cvt_df)
cvt_df:
lfd 0,0(r3)
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 3f404a37a..80f10c59e 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -29,7 +29,6 @@
void
main(void)
{
- /*DEFINE(KERNELBASE, KERNELBASE);*/
DEFINE(STATE, offsetof(struct task_struct, state));
DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
DEFINE(COUNTER, offsetof(struct task_struct, counter));
@@ -37,54 +36,20 @@ main(void)
DEFINE(SIGNAL, offsetof(struct task_struct, signal));
DEFINE(TSS, offsetof(struct task_struct, tss));
DEFINE(KSP, offsetof(struct thread_struct, ksp));
- DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
-#ifdef CONFIG_PMAC
- DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
- DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
-#endif
+ /*DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));*/
+ DEFINE(MM, offsetof(struct task_struct, mm));
+ DEFINE(PGD, offsetof(struct mm_struct, pgd));
DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
DEFINE(PF_TRACESYS, PF_TRACESYS);
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
-#if 0
- DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
- DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
- DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
- DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
- DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
- DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
- DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
- DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
- DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
- DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
- DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
- DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
- DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
- DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
- DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
- DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
- DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
- DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
- DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
- DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
- DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
- DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
- DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
- DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
- DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
- DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
- DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
- DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
- DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
- DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
- DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
-#endif
DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
/* Interrupt register frame */
DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+ /* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */
DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c
new file mode 100644
index 000000000..7eb5e5aa9
--- /dev/null
+++ b/arch/ppc/kernel/openpic.c
@@ -0,0 +1,546 @@
+/*
+ * arch/ppc/kernel/openpic.c -- OpenPIC Interrupt Handling
+ *
+ * Copyright (C) 1997 Geert Uytterhoeven
+ *
+ * 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.
+ */
+
+
+/*
+ * Note: Interprocessor Interrupt (IPI) and Timer support is incomplete
+ */
+
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/openpic.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+
+#define REGISTER_DEBUG
+#undef REGISTER_DEBUG
+
+
+#define VEC_TIMER 0x40 /* and up */
+#define VEC_IPI 0x50 /* and up */
+#define VEC_SOURCE 0x10 /* and up */
+#define VEC_SPURIOUS 99
+
+
+volatile struct OpenPIC *OpenPIC;
+
+static u_int Version;
+static u_int NumProcessors;
+static u_int NumSources;
+static u_int VendorID;
+static u_int DeviceID;
+static u_int Stepping;
+static u_int TimerFrequency;
+
+
+ /*
+ * Accesses to the current processor's registers
+ */
+
+#ifndef __powerpc__
+#define THIS_CPU Private
+#define CHECK_THIS_CPU do {} while (0)
+#else
+#define THIS_CPU Processor[cpu]
+#define CHECK_THIS_CPU check_arg_cpu(cpu)
+#endif
+
+
+ /*
+ * Sanity checks
+ */
+
+#if 1
+#define check_arg_ipi(ipi) \
+ if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
+ printk("openpic.c:%d: illegal ipi %d\n", __LINE__, ipi);
+#define check_arg_timer(timer) \
+ if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
+ printk("openpic.c:%d: illegal timer %d\n", __LINE__, timer);
+#define check_arg_vec(vec) \
+ if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
+ printk("openpic.c:%d: illegal vector %d\n", __LINE__, vec);
+#define check_arg_pri(pri) \
+ if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
+ printk("openpic.c:%d: illegal priority %d\n", __LINE__, pri);
+#define check_arg_irq(irq) \
+ if (irq < 0 || irq >= NumSources) \
+ printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);
+#define check_arg_cpu(cpu) \
+ if (cpu < 0 || cpu >= NumProcessors) \
+ printk("openpic.c:%d: illegal cpu %d\n", __LINE__, cpu);
+#else
+#define check_arg_ipi(ipi) do {} while (0)
+#define check_arg_timer(timer) do {} while (0)
+#define check_arg_vec(vec) do {} while (0)
+#define check_arg_pri(pri) do {} while (0)
+#define check_arg_irq(irq) do {} while (0)
+#define check_arg_cpu(cpu) do {} while (0)
+#endif
+
+
+ /*
+ * Dummy interrupt handler
+ */
+
+static void no_action(int ir1, void *dev, struct pt_regs *regs)
+{}
+
+
+ /*
+ * I/O functions
+ */
+
+#ifdef __i386__
+static inline u_int ld_le32(volatile u_int *addr)
+{
+ return *addr;
+}
+
+static inline void out_le32(volatile u_int *addr, u_int val)
+{
+ *addr = val;
+}
+#endif
+
+static inline u_int openpic_read(volatile u_int *addr)
+{
+ u_int val;
+
+ val = ld_le32(addr);
+#ifdef REGISTER_DEBUG
+ printk("openpic_read(0x%08x) = 0x%08x\n", (u_int)addr, val);
+#endif
+ return val;
+}
+
+static inline void openpic_write(volatile u_int *addr, u_int val)
+{
+#ifdef REGISTER_DEBUG
+ printk("openpic_write(0x%08x, 0x%08x)\n", (u_int)addr, val);
+#endif
+ out_le32(addr, val);
+}
+
+
+static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
+{
+ u_int val = openpic_read(addr);
+ return val & mask;
+}
+
+static inline void openpic_writefield(volatile u_int *addr, u_int mask,
+ u_int field)
+{
+ u_int val = openpic_read(addr);
+ openpic_write(addr, (val & ~mask) | (field & mask));
+}
+
+static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
+{
+ openpic_writefield(addr, mask, 0);
+}
+
+static inline void openpic_setfield(volatile u_int *addr, u_int mask)
+{
+ openpic_writefield(addr, mask, mask);
+}
+
+
+ /*
+ * Update a Vector/Priority register in a safe manner. The interrupt will
+ * be disabled.
+ */
+
+static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
+ u_int field)
+{
+ openpic_setfield(addr, OPENPIC_MASK);
+ /* wait until it's not in use */
+ while (openpic_read(addr) & OPENPIC_ACTIVITY);
+ openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+}
+
+
+/* -------- Global Operations ---------------------------------------------- */
+
+
+ /*
+ * Initialize the OpenPIC
+ */
+
+void openpic_init(void)
+{
+ u_int t, i;
+ const char *version, *vendor, *device;
+
+ if (!OpenPIC) {
+ printk("No OpenPIC present\n");
+ return;
+ }
+
+ t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
+ Version = t & OPENPIC_FEATURE_VERSION_MASK;
+ NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+ OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
+ NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+ OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
+
+ switch (Version) {
+ case 1:
+ version = "1.0";
+ break;
+ case 2:
+ version = "1.2";
+ break;
+ default:
+ version = "?.?";
+ break;
+ }
+ printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
+ NumProcessors, NumSources, OpenPIC);
+
+ t = openpic_read(&OpenPIC->Global.Vendor_Identification);
+ VendorID = t & OPENPIC_VENDOR_ID_VENDOR_ID_MASK;
+ DeviceID = (t & OPENPIC_VENDOR_ID_DEVICE_ID_MASK) >>
+ OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT;
+ Stepping = (t & OPENPIC_VENDOR_ID_STEPPING_MASK) >>
+ OPENPIC_VENDOR_ID_STEPPING_SHIFT;
+ switch (VendorID) {
+ case OPENPIC_VENDOR_ID_APPLE:
+ vendor = "Apple";
+ break;
+ default:
+ vendor = "Unknown";
+ break;
+ }
+ switch (DeviceID) {
+ case OPENPIC_DEVICE_ID_APPLE_HYDRA:
+ device = "Hydra";
+ break;
+ default:
+ device = "Unknown";
+ break;
+ }
+ printk("OpenPIC Vendor %d (%s), Device %d (%s), Stepping %d\n", VendorID,
+ vendor, DeviceID, device, Stepping);
+
+ TimerFrequency = openpic_read(&OpenPIC->Global.Timer_Frequency);
+ printk("OpenPIC timer frequency is ");
+ if (TimerFrequency)
+ printk("%d Hz\n", TimerFrequency);
+ else
+ printk("not set\n");
+
+ /* Initialize timer interrupts */
+ for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
+ /* Disabled, Priority 0 */
+ openpic_inittimer(i, 0, 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, VEC_IPI+i);
+ }
+
+ /* Initialize external interrupts */
+ /* SIOint (8259 cascade) is special */
+ openpic_initirq(0, 8, VEC_SOURCE, 1, 1); /* 0,1 gives interrupt storm */
+ /* Processor 0 */
+ openpic_mapirq(0, 1<<0);
+ for (i = 1; i < NumSources; i++) {
+ /* Enabled, Priority 8 */
+ openpic_initirq(i, 8, VEC_SOURCE+i, 0, 1);
+ /* Processor 0 */
+ openpic_mapirq(i, 1<<0);
+ }
+
+ /* Initialize the spurious interrupt */
+ openpic_set_spurious(VEC_SPURIOUS);
+
+ if (request_irq(IRQ_8259_CASCADE, no_action, SA_INTERRUPT,
+ "OpenPIC cascade", NULL))
+ printk("Unable to get OpenPIC IRQ 0 for cascade\n");
+ openpic_set_priority(0, 0);
+ openpic_disable_8259_pass_through();
+}
+
+
+ /*
+ * Reset the OpenPIC
+ */
+
+void openpic_reset(void)
+{
+ openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+ OPENPIC_CONFIG_RESET);
+}
+
+
+ /*
+ * Enable/disable 8259 Pass Through Mode
+ */
+
+void openpic_enable_8259_pass_through(void)
+{
+ openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
+ OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+void openpic_disable_8259_pass_through(void)
+{
+ openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+ OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+
+#ifndef __i386__
+ /*
+ * Find out the current interrupt
+ */
+
+u_int openpic_irq(u_int cpu)
+{
+ u_int vec;
+
+ check_arg_cpu(cpu);
+ vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
+ OPENPIC_VECTOR_MASK);
+#if 0
+if (vec != 22 /* SCSI */)
+printk("++openpic_irq: %d\n", vec);
+#endif
+ return vec;
+}
+#endif
+
+
+ /*
+ * Signal end of interrupt (EOI) processing
+ */
+
+#ifndef __powerpc__
+void openpic_eoi(void)
+#else
+void openpic_eoi(u_int cpu)
+#endif
+{
+#if 0
+printk("++openpic_eoi:\n");
+#endif
+ check_arg_cpu(cpu);
+ openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+}
+
+
+ /*
+ * Get/set the current task priority
+ */
+
+#ifndef __powerpc__
+u_int openpic_get_priority(void)
+#else
+u_int openpic_get_priority(u_int cpu)
+#endif
+{
+ CHECK_THIS_CPU;
+ return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+ OPENPIC_CURRENT_TASK_PRIORITY_MASK);
+}
+
+#ifndef __powerpc__
+void openpic_set_priority(u_int pri)
+#else
+void openpic_set_priority(u_int cpu, u_int pri)
+#endif
+{
+ CHECK_THIS_CPU;
+ check_arg_pri(pri);
+ openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+ OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
+}
+
+ /*
+ * Get/set the spurious vector
+ */
+
+u_int openpic_get_spurious(void)
+{
+ return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
+ OPENPIC_VECTOR_MASK);
+}
+
+void openpic_set_spurious(u_int vec)
+{
+ check_arg_vec(vec);
+ openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
+ vec);
+}
+
+
+ /*
+ * Initialize one or more CPUs
+ */
+
+void openpic_init_processor(u_int cpumask)
+{
+ openpic_write(&OpenPIC->Global.Processor_Initialization, cpumask);
+}
+
+
+/* -------- Interprocessor Interrupts -------------------------------------- */
+
+
+ /*
+ * Initialize an interprocessor interrupt (and disable it)
+ *
+ * ipi: OpenPIC interprocessor interrupt number
+ * pri: interrupt source priority
+ * vec: the vector it will produce
+ */
+
+void openpic_initipi(u_int ipi, u_int pri, u_int vec)
+{
+ check_arg_timer(ipi);
+ check_arg_pri(pri);
+ check_arg_vec(vec);
+ openpic_safe_writefield(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+ OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+ (pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+
+ /*
+ * Send an IPI to one or more CPUs
+ */
+
+#ifndef __powerpc__
+void openpic_cause_IPI(u_int ipi, u_int cpumask)
+#else
+void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask)
+#endif
+{
+ CHECK_THIS_CPU;
+ check_arg_ipi(ipi);
+ openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi), cpumask);
+}
+
+
+/* -------- Timer Interrupts ----------------------------------------------- */
+
+
+ /*
+ * Initialize a timer interrupt (and disable it)
+ *
+ * timer: OpenPIC timer number
+ * pri: interrupt source priority
+ * vec: the vector it will produce
+ */
+
+void openpic_inittimer(u_int timer, u_int pri, u_int vec)
+{
+ check_arg_timer(timer);
+ check_arg_pri(pri);
+ check_arg_vec(vec);
+ openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
+ OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+ (pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+
+ /*
+ * Map a timer interrupt to one or more CPUs
+ */
+
+void openpic_maptimer(u_int timer, u_int cpumask)
+{
+ check_arg_timer(timer);
+ openpic_write(&OpenPIC->Global.Timer[timer].Destination, cpumask);
+}
+
+
+/* -------- Interrupt Sources ---------------------------------------------- */
+
+
+ /*
+ * Enable/disable an interrupt source
+ */
+
+void openpic_enable_irq(u_int irq)
+{
+ check_arg_irq(irq);
+ openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+}
+
+void openpic_disable_irq(u_int irq)
+{
+ check_arg_irq(irq);
+ openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
+}
+
+
+ /*
+ * Initialize an interrupt source (and disable it!)
+ *
+ * irq: OpenPIC interrupt number
+ * pri: interrupt source priority
+ * vec: the vector it will produce
+ * pol: polarity (1 for positive, 0 for negative)
+ * sense: 1 for level, 0 for edge
+ */
+
+void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
+{
+ check_arg_irq(irq);
+ check_arg_pri(pri);
+ check_arg_vec(vec);
+ openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+ OPENPIC_SENSE_POLARITY | OPENPIC_SENSE_LEVEL,
+ (pri << OPENPIC_PRIORITY_SHIFT) | vec |
+ (pol ? OPENPIC_SENSE_POLARITY : 0) |
+ (sense ? OPENPIC_SENSE_LEVEL : 0));
+}
+
+
+ /*
+ * Map an interrupt source to one or more CPUs
+ */
+
+void openpic_mapirq(u_int irq, u_int cpumask)
+{
+ check_arg_irq(irq);
+ openpic_write(&OpenPIC->Source[irq].Destination, cpumask);
+}
+
+
+ /*
+ * Set the sense for an interrupt source (and disable it!)
+ *
+ * sense: 1 for level, 0 for edge
+ */
+
+void openpic_set_sense(u_int irq, int sense)
+{
+ check_arg_irq(irq);
+ openpic_safe_writefield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_SENSE_LEVEL,
+ (sense ? OPENPIC_SENSE_LEVEL : 0));
+}
+
+
diff --git a/arch/ppc/kernel/pci-bridge.c b/arch/ppc/kernel/pci-bridge.c
new file mode 100644
index 000000000..0e4420340
--- /dev/null
+++ b/arch/ppc/kernel/pci-bridge.c
@@ -0,0 +1,428 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+struct bridge_data {
+ volatile unsigned int *cfg_addr;
+ volatile unsigned char *cfg_data;
+ void *io_base;
+ int bus_number;
+ int max_bus;
+ struct bridge_data *next;
+ struct device_node *node;
+};
+
+static struct bridge_data **bridges, *bridge_list;
+static int max_bus;
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define APPLE_VENDID 0x106b
+#define BANDIT_DEVID 1
+#define BANDIT_REVID 3
+
+#define BANDIT_DEVNUM 11
+#define BANDIT_MAGIC 0x50
+#define BANDIT_COHERENT 0x40
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we can't use pcibios_*_config_* here because bridges[]
+ * is not initialized yet.
+ */
+static void init_bandit(struct bridge_data *bp)
+{
+ unsigned int vendev, magic;
+ int rev;
+
+ /* read the word at offset 0 in config space for device 11 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+ udelay(2);
+ vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+ if (vendev != (BANDIT_DEVID << 16) + APPLE_VENDID) {
+ printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+ return;
+ }
+
+ /* read the revision id */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+ udelay(2);
+ rev = in_8(bp->cfg_data);
+ if (rev != BANDIT_REVID)
+ printk(KERN_WARNING "Unknown revision %d for bandit at %p\n",
+ rev, bp->io_base);
+
+ /* read the word at offset 0x50 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+ udelay(2);
+ magic = in_le32((volatile unsigned int *)bp->cfg_data);
+ if ((magic & BANDIT_COHERENT) != 0)
+ return;
+ magic |= BANDIT_COHERENT;
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, magic);
+ printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %p\n",
+ bp->io_base);
+}
+
+unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
+{
+ int bus;
+ struct bridge_data *bridge;
+
+ bridge_list = 0;
+ max_bus = 0;
+ add_bridges(find_devices("bandit"), &mem_start);
+ add_bridges(find_devices("chaos"), &mem_start);
+ bridges = (struct bridge_data **) mem_start;
+ mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
+ memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
+ for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
+ for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
+ bridges[bus] = bridge;
+
+ return mem_start;
+}
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
+{
+ int *bus_range;
+ int len;
+ struct bridge_data *bp;
+
+ for (; dev != NULL; dev = dev->next) {
+ if (dev->n_addrs < 1) {
+ printk(KERN_WARNING "Can't use %s: no address\n",
+ dev->full_name);
+ continue;
+ }
+ bus_range = (int *) get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ dev->full_name);
+ continue;
+ }
+ if (bus_range[1] == bus_range[0])
+ printk(KERN_INFO "PCI bus %d", bus_range[0]);
+ else
+ printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
+ bus_range[1]);
+ printk(" controlled by %s at %x\n",
+ dev->name, dev->addrs[0].address);
+ bp = (struct bridge_data *) *mem_ptr;
+ *mem_ptr += sizeof(struct bridge_data);
+ bp->cfg_addr = (volatile unsigned int *)
+ (dev->addrs[0].address + 0x800000);
+ bp->cfg_data = (volatile unsigned char *)
+ (dev->addrs[0].address + 0xc00000);
+ bp->io_base = (void *) dev->addrs[0].address;
+ ioremap(dev->addrs[0].address, 0x800000);
+ bp->bus_number = bus_range[0];
+ bp->max_bus = bus_range[1];
+ bp->next = bridge_list;
+ bp->node = dev;
+ bridge_list = bp;
+ if (bp->max_bus > max_bus)
+ max_bus = bp->max_bus;
+
+ if (strcmp(dev->name, "bandit") == 0)
+ init_bandit(bp);
+ }
+}
+
+void *pci_io_base(unsigned int bus)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return 0;
+ return bp->io_base;
+}
+
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+ unsigned char *devfn_ptr)
+{
+ unsigned int *reg;
+ int len;
+
+ reg = (unsigned int *) get_property(dev, "reg", &len);
+ if (reg == 0 || len < 5 * sizeof(unsigned int)) {
+ /* doesn't look like a PCI device */
+ *bus_ptr = 0xff;
+ *devfn_ptr = 0xff;
+ return -1;
+ }
+ *bus_ptr = reg[0] >> 16;
+ *devfn_ptr = reg[0] >> 8;
+ return 0;
+}
+
+int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_8(bp->cfg_data + (offset & 3));
+
+ if (offset == PCI_INTERRUPT_LINE) {
+ /*
+ * Open Firmware often doesn't initialize this
+ * register properly, so we find the node and see
+ * if it has an AAPL,interrupts property.
+ */
+ struct device_node *node;
+ unsigned int *reg;
+
+ for (node = bp->node->child; node != 0; node = node->sibling) {
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
+ continue;
+ /* this is the node, see if it has interrupts */
+ if (node->n_intrs > 0)
+ *val = node->intrs[0];
+ break;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffffffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ *val = in_le32((volatile unsigned int *)bp->cfg_data);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_8(bp->cfg_data + (offset & 3), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x, vendev;
+ unsigned char h;
+
+ if (vendor == 0xffff)
+ return PCIBIOS_BAD_VENDOR_ID;
+ vendev = (dev_id << 16) + vendor;
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_VENDOR_ID, &x)
+ == PCIBIOS_SUCCESSFUL && x == vendev) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x;
+ unsigned char h;
+
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_CLASS_REVISION, &x)
+ == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(unsigned long route_pci_interrupts(void))
+{
+ return 0;
+}
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 612a24bff..49f2f37be 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1,630 +1,194 @@
/*
- * PCI support
- * -- rough emulation of "PCI BIOS" functions
- *
- * Note: these are very motherboard specific! Some way needs to
- * be worked out to handle the differences.
+ * $Id: pci.c,v 1.12 1997/08/27 05:05:28 cort Exp $
+ * Common pmac/prep/chrp pci routines. -- Cort
*/
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/bios32.h>
+#include <linux/kernel.h>
#include <linux/pci.h>
+/*#include <linux/bios32.h>*/
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/ptrace.h>
#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
-/*
- * PCI interrupt configuration. This is motherboard specific.
- */
-/* Which PCI interrupt line does a given device [slot] use? */
-/* Note: This really should be two dimensional based in slot/pin used */
-unsigned char *Motherboard_map;
-unsigned char *Motherboard_map_name;
-
-/* How is the 82378 PIRQ mapping setup? */
-unsigned char *Motherboard_routes;
-
-/* Tables for known hardware */
-
-/* Motorola PowerStack */
-static char Blackhawk_pci_IRQ_map[16] =
-{
- 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 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Blackhawk_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 9, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* Motorola MVME16xx */
-static char Genesis_pci_IRQ_map[16] =
-{
- 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 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Genesis_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 10, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* Motorola Series-E */
-static char Comet_pci_IRQ_map[16] =
-{
- 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 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 1, /* Slot 14 - Ethernet */
- 0, /* Slot 15 - unused */
-};
-
-static char Comet_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 10, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* BeBox */
-static char BeBox_pci_IRQ_map[16] =
-{
- 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 - unused */
- 16, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 0, /* Slot 14 - unused */
- 0, /* Slot 15 - unused */
-};
-
-static char BeBox_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 9, /* Line 1 */
- 11, /* Line 2 */
- 14, /* Line 3 */
- 15 /* Line 4 */
-};
-
-/* IBM Nobis */
-static char Nobis_pci_IRQ_map[16] =
-{
- 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 - unused */
- 3, /* Slot 12 - SCSI */
- 0, /* Slot 13 - unused */
- 0, /* Slot 14 - unused */
- 0, /* Slot 15 - unused */
-};
-
-static char Nobis_pci_IRQ_routes[] =
-{
- 0, /* Line 0 - Unused */
- 13, /* Line 1 */
- 13, /* Line 2 */
- 13, /* Line 3 */
- 13 /* Line 4 */
-};
-
+unsigned long io_base;
+unsigned long pci_dram_offset;
/*
- * ibm 830 (and 850?).
- * This is actually based on the Carolina motherboard
- * -- Cort
- */
-static char ibm8xx_pci_IRQ_map[23] = {
- 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 - FireCoral */
- 4, /* Slot 12 - Ethernet PCIINTD# */
- 2, /* Slot 13 - PCI Slot #2 */
- 2, /* Slot 14 - S3 Video PCIINTD# */
- 0, /* Slot 15 - onboard SCSI (INDI) [1] */
- 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
- 0, /* Slot 17 - unused */
- 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
- 0, /* Slot 19 - unused */
- 0, /* Slot 20 - unused */
- 0, /* Slot 21 - unused */
- 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-static char ibm8xx_pci_IRQ_routes[] = {
- 0, /* Line 0 - unused */
- 13, /* Line 1 */
- 10, /* Line 2 */
- 15, /* Line 3 */
- 15, /* Line 4 */
-};
-/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
- * it really needs some logic to set them to unique IRQ's, or even
- * add some logic to the drivers to ask an irq.c routine to re-map
- * the IRQ if it needs one to itself...
+ * It would be nice if we could create a include/asm/pci.h and have just
+ * function ptrs for all these in there, but that isn't the case.
+ * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*()
+ * which has been setup by pcibios_init(). This is all to avoid a check
+ * for pmac/prep every time we call one of these. It should also make the move
+ * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions
+ * and create pci.h
+ * -- Cort
*/
-static char Carolina_PIRQ_routes[] = {
- 0xad, /* INTB# = 10, INTA# = 13 */
- 0xff /* INTD# = 15, INTC# = 15 */
-};
-/* We have to turn on LEVEL mode for changed IRQ's */
-/* All PCI IRQ's need to be level mode, so this should be something
- * other than hard-coded as well... IRQ's are individually mappable
- * to either edge or level.
- */
-#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
-#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
-#define PCI_DEVICE_ID_IBM_CORAL 0x000a
-
-#undef PCI_DEBUG
-
-#ifdef PCI_STATS
-int PCI_conversions[2];
-#endif
-
-
-unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
-{
- return mem_start;
+int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+int (*ptr_pcibios_find_device)(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+int (*ptr_pcibios_find_class)(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+extern int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+extern int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+extern int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+extern int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int chrp_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+extern int chrp_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int chrp_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+extern int chrp_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+extern int chrp_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+extern int chrp_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+extern int chrp_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+extern int chrp_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int prep_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val);
+extern int prep_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val);
+extern int prep_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val);
+extern int prep_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val);
+extern int prep_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val);
+extern int prep_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val);
+extern int prep_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr);
+extern int prep_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val);
}
-
-int
-pcibios_present (void)
+int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
{
-#ifdef PCI_DEBUG
- printk("PCI [BIOS] present?\n");
-#endif
- return (1);
+ return ptr_pcibios_read_config_word(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int *val)
+int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
{
- unsigned long _val;
- unsigned long *ptr;
- dev >>= 3;
-#ifdef PCI_DEBUG
- printk("PCI Read config dword[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = le32_to_cpu(*ptr);
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short *val)
+int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
{
- unsigned short _val;
- unsigned short *ptr;
- dev >>= 3;
-#ifdef PCI_DEBUG
- printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = (unsigned short)0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = le16_to_cpu(*ptr);
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val);
}
-
-int
-pcibios_read_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char *val)
+int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
{
- unsigned char _val;
- volatile unsigned char *ptr;
- dev >>= 3;
- /* Note: the configuration registers don't always have this right! */
- if (offset == PCI_INTERRUPT_LINE)
- {
- if (Motherboard_map[dev] <= 4)
- {
- *val = Motherboard_routes[Motherboard_map[dev]];
- /*printk("dev %d map %d route %d\n",
- dev,Motherboard_map[dev],
- Motherboard_routes[Motherboard_map[dev]]);*/
- } else
- { /* Pseudo interrupts [for BeBox] */
- *val = Motherboard_map[dev];
- }
-#ifdef PCI_DEBUG
- printk("PCI Read Interrupt Line[%d.%d] = %d\n", bus, dev, *val);
-#endif
- return PCIBIOS_SUCCESSFUL;
- }
-#ifdef PCI_DEBUG
- printk("PCI Read config byte[%d.%d.%x] = ", bus, dev, offset);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- *val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
-#ifdef PCI_DEBUG
- printk("[%x] ", ptr);
-#endif
- _val = *ptr;
- }
-#ifdef PCI_DEBUG
- printk("%x\n", _val);
-#endif
- *val = _val;
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_word(bus,dev_fn,offset,val);
}
-
-int
-pcibios_write_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int val)
+int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
{
- unsigned long _val;
- unsigned long *ptr;
- dev >>= 3;
- _val = le32_to_cpu(val);
-#ifdef PCI_DEBUG
- printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
}
-
-int
-pcibios_write_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short val)
+int pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
{
- unsigned short _val;
- unsigned short *ptr;
- dev >>= 3;
- _val = le16_to_cpu(val);
-#ifdef PCI_DEBUG
- printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_find_device(vendor,dev_id,index,bus_ptr,dev_fn_ptr);
}
-
-int
-pcibios_write_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char val)
+int pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
{
- unsigned char _val;
- unsigned char *ptr;
- dev >>= 3;
- _val = val;
-#ifdef PCI_DEBUG
- printk("PCI Write config byte[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif
- if ((bus != 0) || (dev < 11) || (dev > 16))
- {
- return PCIBIOS_DEVICE_NOT_FOUND;
- } else
- {
- ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
- *ptr = _val;
- }
- return PCIBIOS_SUCCESSFUL;
+ return ptr_pcibios_find_class(class_code,index,bus_ptr,dev_fn_ptr);
}
-int
-pcibios_find_device (unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus,
- unsigned char *dev)
+int pcibios_present(void)
{
- unsigned long w, desired = (device_id << 16) | vendor;
- int devnr;
-
- if (vendor == 0xffff) {
- return PCIBIOS_BAD_VENDOR_ID;
- }
-
- for (devnr = 11; devnr < 16; devnr++)
- {
- pcibios_read_config_dword(0, devnr<<3, PCI_VENDOR_ID, &w);
- if (w == desired) {
- if (index == 0) {
- *bus = 0;
- *dev = devnr<<3;
- return PCIBIOS_SUCCESSFUL;
- }
- --index;
- }
- }
- return PCIBIOS_DEVICE_NOT_FOUND;
+ return 1;
}
-int
-pcibios_find_class (unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *dev)
-{
- int dev_nr, class, indx;
- indx = 0;
-#ifdef PCI_DEBUG
- printk("pcibios_find_class - class: %x, index: %x", class_code, index);
-#endif
- for (dev_nr = 11; dev_nr < 16; dev_nr++)
- {
- pcibios_read_config_dword(0, dev_nr<<3, PCI_CLASS_REVISION, &class);
- if ((class>>8) == class_code)
- {
- if (index == indx)
- {
- *bus = 0;
- *dev = dev_nr<<3;
-#ifdef PCI_DEBUG
- printk(" - device: %x\n", dev_nr);
-#endif
- return (0);
- }
- indx++;
- }
- }
-#ifdef PCI_DEBUG
- printk(" - not found\n");
-#endif
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-const char *pcibios_strerror(int error)
-{
- static char buf[32];
- switch (error)
- { case PCIBIOS_SUCCESSFUL:
- return ("PCI BIOS: no error");
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return ("PCI BIOS: function not supported");
- case PCIBIOS_BAD_VENDOR_ID:
- return ("PCI BIOS: bad vendor ID");
- case PCIBIOS_DEVICE_NOT_FOUND:
- return ("PCI BIOS: device not found");
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return ("PCI BIOS: bad register number");
- case PCIBIOS_SET_FAILED:
- return ("PCI BIOS: set failed");
- case PCIBIOS_BUFFER_TOO_SMALL:
- return ("PCI BIOS: buffer too small");
- default:
- sprintf(buf, "PCI BIOS: invalid error #%d", error);
- return(buf);
+__initfunc(unsigned long
+pcibios_init(unsigned long mem_start,unsigned long mem_end))
+{
+ switch (_machine) {
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ ptr_pcibios_read_config_byte = prep_pcibios_read_config_byte;
+ ptr_pcibios_read_config_word = prep_pcibios_read_config_word;
+ ptr_pcibios_read_config_dword = prep_pcibios_read_config_dword;
+ ptr_pcibios_write_config_byte = prep_pcibios_write_config_byte;
+ ptr_pcibios_write_config_word = prep_pcibios_write_config_word;
+ ptr_pcibios_write_config_dword = prep_pcibios_write_config_dword;
+ ptr_pcibios_find_device = prep_pcibios_find_device;
+ ptr_pcibios_find_class = prep_pcibios_find_class;
+ break;
+ case _MACH_Pmac:
+ ptr_pcibios_read_config_byte = pmac_pcibios_read_config_byte;
+ ptr_pcibios_read_config_word = pmac_pcibios_read_config_word;
+ ptr_pcibios_read_config_dword = pmac_pcibios_read_config_dword;
+ ptr_pcibios_write_config_byte = pmac_pcibios_write_config_byte;
+ ptr_pcibios_write_config_word = pmac_pcibios_write_config_word;
+ ptr_pcibios_write_config_dword = pmac_pcibios_write_config_dword;
+ ptr_pcibios_find_device = pmac_pcibios_find_device;
+ ptr_pcibios_find_class = pmac_pcibios_find_class;
+ break;
+ case _MACH_chrp:
+ ptr_pcibios_read_config_byte = chrp_pcibios_read_config_byte;
+ ptr_pcibios_read_config_word = chrp_pcibios_read_config_word;
+ ptr_pcibios_read_config_dword = chrp_pcibios_read_config_dword;
+ ptr_pcibios_write_config_byte = chrp_pcibios_write_config_byte;
+ ptr_pcibios_write_config_word = chrp_pcibios_write_config_word;
+ ptr_pcibios_write_config_dword = chrp_pcibios_write_config_dword;
+ ptr_pcibios_find_device = chrp_pcibios_find_device;
+ ptr_pcibios_find_class = chrp_pcibios_find_class;
+ break;
}
-}
-
-/*
- * Note: This routine has to access the PCI configuration space
- * for the PCI bridge chip (Intel 82378).
- */
-unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
-{
return mem_start;
}
-unsigned long route_pci_interrupts(void)
+__initfunc(unsigned long
+pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
{
- unsigned char *ibc_pirq = (unsigned char *)0x80800860;
- unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
- extern unsigned long isBeBox[];
- int i;
-
- if ( _machine == _MACH_Motorola)
- {
- switch (inb(0x800) & 0xF0)
- {
- case 0x10: /* MVME16xx */
- Motherboard_map_name = "Genesis";
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x20: /* Series E */
- Motherboard_map_name = "Series E";
- Motherboard_map = Comet_pci_IRQ_map;
- Motherboard_routes = Comet_pci_IRQ_routes;
- break;
- case 0x40: /* PowerStack */
- default: /* Can't hurt, can it? */
- Motherboard_map_name = "Blackhawk (Powerstack)";
- Motherboard_map = Blackhawk_pci_IRQ_map;
- Motherboard_routes = Blackhawk_pci_IRQ_routes;
- break;
- }
- } else
- {
- if ( _machine == _MACH_IBM )
- {
- unsigned char pl_id;
- unsigned long flags;
- unsigned index;
- unsigned char fn, bus;
- unsigned int addr;
- unsigned char dma_mode, ide_mode;
- int i;
-
- Motherboard_map_name = "IBM 8xx (Carolina)";
- Motherboard_map = ibm8xx_pci_IRQ_map;
- Motherboard_routes = ibm8xx_pci_IRQ_routes;
-ll_printk("before loop\n");
-
- for (index = 0;
- !pcibios_find_device (PCI_VENDOR_ID_IBM,
- PCI_DEVICE_ID_IBM_CORAL,
- index, &bus, &fn); ++index)
- {
- pcibios_read_config_dword(bus, fn, 0x10, &addr);
- addr &= ~0x3;
- outb(0x26, addr);
- dma_mode = inb(addr+4);
- outb(0x25, addr);
- ide_mode = inb(addr+4);
- /*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x",
- addr, dma_mode, ide_mode);*/
- /* Make CDROM non-DMA */
- ide_mode = (ide_mode & 0x0F) | 0x20;
- outb(0x25, addr);
- outb(ide_mode, addr+4);
- dma_mode = dma_mode & ~0x80;
- outb(0x26, addr);
- outb(dma_mode, addr+4);
- outb(0x26, addr);
- dma_mode = inb(addr+4);
- outb(0x25, addr);
- ide_mode = inb(addr+4);
- /*printk("=> DMA mode: %x, IDE mode: %x\n",
- dma_mode, ide_mode);*/
- }
-
- /* Setup the PCI INT mappings for the Carolina */
- /* These are PCI Interrupt Route Control [1|2] Register */
- outb(Carolina_PIRQ_routes[0], 0x0890);
- outb(Carolina_PIRQ_routes[1], 0x0891);
-
- pl_id=inb(0x0852);
- /*printk("CPU Planar ID is %#0x\n", pl_id);*/
-
- if (pl_id == 0x0C) {
- /* INDI */
- Motherboard_map[12] = 1;
- }
-ll_printk("before edge/level\n");
-#if 0
- /*printk("Changing IRQ mode\n");*/
- pl_id=inb(0x04d0);
- /*printk("Low mask is %#0x\n", pl_id);*/
- outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
-
- pl_id=inb(0x04d1);
- /*printk("Hi mask is %#0x\n", pl_id);*/
- outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
- pl_id=inb(0x04d1);
- /*printk("Hi mask now %#0x\n", pl_id);*/
-#endif
- }
- }
-
- /* Set up mapping from slots */
- for (i = 1; i <= 4; i++)
- {
- ibc_pirq[i-1] = Motherboard_routes[i];
- }
- /* Enable PCI interrupts */
- *ibc_pcicon |= 0x20;
+ return mem_start;
}
diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c
new file mode 100644
index 000000000..a48385b3f
--- /dev/null
+++ b/arch/ppc/kernel/pmac_pci.c
@@ -0,0 +1,423 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+struct bridge_data {
+ volatile unsigned int *cfg_addr;
+ volatile unsigned char *cfg_data;
+ void *io_base;
+ int bus_number;
+ int max_bus;
+ struct bridge_data *next;
+ struct device_node *node;
+};
+
+static struct bridge_data **bridges, *bridge_list;
+static int max_bus;
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define APPLE_VENDID 0x106b
+#define BANDIT_DEVID 1
+#define BANDIT_REVID 3
+
+#define BANDIT_DEVNUM 11
+#define BANDIT_MAGIC 0x50
+#define BANDIT_COHERENT 0x40
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we can't use pcibios_*_config_* here because bridges[]
+ * is not initialized yet.
+ */
+static void init_bandit(struct bridge_data *bp)
+{
+ unsigned int vendev, magic;
+ int rev;
+
+ /* read the word at offset 0 in config space for device 11 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+ udelay(2);
+ vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+ if (vendev != (BANDIT_DEVID << 16) + APPLE_VENDID) {
+ printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+ return;
+ }
+
+ /* read the revision id */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+ udelay(2);
+ rev = in_8(bp->cfg_data);
+ if (rev != BANDIT_REVID)
+ printk(KERN_WARNING "Unknown revision %d for bandit at %p\n",
+ rev, bp->io_base);
+
+ /* read the word at offset 0x50 */
+ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+ udelay(2);
+ magic = in_le32((volatile unsigned int *)bp->cfg_data);
+ if ((magic & BANDIT_COHERENT) != 0)
+ return;
+ magic |= BANDIT_COHERENT;
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, magic);
+ printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %p\n",
+ bp->io_base);
+}
+
+unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
+{
+ int bus;
+ struct bridge_data *bridge;
+
+ bridge_list = 0;
+ max_bus = 0;
+ add_bridges(find_devices("bandit"), &mem_start);
+ add_bridges(find_devices("chaos"), &mem_start);
+ bridges = (struct bridge_data **) mem_start;
+ mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
+ memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
+ for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
+ for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
+ bridges[bus] = bridge;
+
+ return mem_start;
+}
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
+{
+ int *bus_range;
+ int len;
+ struct bridge_data *bp;
+
+ for (; dev != NULL; dev = dev->next) {
+ if (dev->n_addrs < 1) {
+ printk(KERN_WARNING "Can't use %s: no address\n",
+ dev->full_name);
+ continue;
+ }
+ bus_range = (int *) get_property(dev, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ dev->full_name);
+ continue;
+ }
+ if (bus_range[1] == bus_range[0])
+ printk(KERN_INFO "PCI bus %d", bus_range[0]);
+ else
+ printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
+ bus_range[1]);
+ printk(" controlled by %s at %x\n",
+ dev->name, dev->addrs[0].address);
+ bp = (struct bridge_data *) *mem_ptr;
+ *mem_ptr += sizeof(struct bridge_data);
+ bp->cfg_addr = (volatile unsigned int *)
+ (dev->addrs[0].address + 0x800000);
+ bp->cfg_data = (volatile unsigned char *)
+ (dev->addrs[0].address + 0xc00000);
+ bp->io_base = (void *) dev->addrs[0].address;
+ ioremap(dev->addrs[0].address, 0x800000);
+ bp->bus_number = bus_range[0];
+ bp->max_bus = bus_range[1];
+ bp->next = bridge_list;
+ bp->node = dev;
+ bridge_list = bp;
+ if (bp->max_bus > max_bus)
+ max_bus = bp->max_bus;
+
+ if (strcmp(dev->name, "bandit") == 0)
+ init_bandit(bp);
+ }
+}
+
+void *pci_io_base(unsigned int bus)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return 0;
+ return bp->io_base;
+}
+
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+ unsigned char *devfn_ptr)
+{
+ unsigned int *reg;
+ int len;
+
+ reg = (unsigned int *) get_property(dev, "reg", &len);
+ if (reg == 0 || len < 5 * sizeof(unsigned int)) {
+ /* doesn't look like a PCI device */
+ *bus_ptr = 0xff;
+ *devfn_ptr = 0xff;
+ return -1;
+ }
+ *bus_ptr = reg[0] >> 16;
+ *devfn_ptr = reg[0] >> 8;
+ return 0;
+}
+
+int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_8(bp->cfg_data + (offset & 3));
+
+ if (offset == PCI_INTERRUPT_LINE) {
+ /*
+ * Open Firmware often doesn't initialize this
+ * register properly, so we find the node and see
+ * if it has an AAPL,interrupts property.
+ */
+ struct device_node *node;
+ unsigned int *reg;
+
+ for (node = bp->node->child; node != 0; node = node->sibling) {
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
+ continue;
+ /* this is the node, see if it has interrupts */
+ if (node->n_intrs > 0)
+ *val = node->intrs[0];
+ break;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ *val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int *val)
+{
+ struct bridge_data *bp;
+
+ *val = 0xffffffff;
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ *val = in_le32((volatile unsigned int *)bp->cfg_data);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned char val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_8(bp->cfg_data + (offset & 3), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned short val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + (offset & ~3));
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+ }
+ udelay(2);
+ out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+ unsigned char offset, unsigned int val)
+{
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == bp->bus_number) {
+ if (dev_fn < (11 << 3))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ out_le32(bp->cfg_addr,
+ (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+ + offset);
+ } else {
+ out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+ }
+ udelay(2);
+ out_le32((volatile unsigned int *)bp->cfg_data, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+ unsigned short index, unsigned char *bus_ptr,
+ unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x, vendev;
+ unsigned char h;
+
+ if (vendor == 0xffff)
+ return PCIBIOS_BAD_VENDOR_ID;
+ vendev = (dev_id << 16) + vendor;
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_VENDOR_ID, &x)
+ == PCIBIOS_SUCCESSFUL && x == vendev) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+ unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+ int bus, unit, fn, num, devfn;
+ unsigned int x;
+ unsigned char h;
+
+ num = 0;
+ for (bus = 0; bus <= max_bus; ++bus) {
+ if (bridges[bus] == 0)
+ continue;
+ unit = fn = 0;
+ if (bus == bridges[bus]->bus_number)
+ unit = 11;
+ while (unit < 32) {
+ devfn = PCI_DEVFN(unit, fn);
+ if (pcibios_read_config_dword(bus, devfn,
+ PCI_CLASS_REVISION, &x)
+ == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
+ if (index == num) {
+ *bus_ptr = bus;
+ *dev_fn_ptr = devfn;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++num;
+ }
+ if (fn != 0) {
+ if (++fn >= 8) {
+ ++unit;
+ fn = 0;
+ }
+ continue;
+ }
+ if (pcibios_read_config_byte(bus, devfn,
+ PCI_HEADER_TYPE, &h)
+ == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+ ++fn;
+ else
+ ++unit;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
new file mode 100644
index 000000000..74a8ff92d
--- /dev/null
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -0,0 +1,271 @@
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * Derived from "arch/alpha/kernel/setup.c"
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * 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.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/ide.h>
+#include <asm/pci-bridge.h>
+#include "time.h"
+
+/*
+ * A magic address and value to put into it on machines with the
+ * "ohare" I/O controller. This makes the IDE CD work on Starmaxes.
+ * Contributed by Harry Eaton.
+ */
+#define OMAGICPLACE ((volatile unsigned *) 0xf3000038)
+#define OMAGICCONT 0xbeff7a
+
+extern int root_mountflags;
+
+extern char command_line[];
+extern char saved_command_line[256];
+
+unsigned char drive_info;
+
+#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
+
+extern unsigned long find_available_memory(void);
+
+void pmac_setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+ extern unsigned long *end_of_DRAM;
+ struct device_node *cpu;
+ int *fp;
+
+ strcpy(saved_command_line, command_line);
+ *cmdline_p = command_line;
+
+ *memory_start_p = find_available_memory();
+ *memory_end_p = (unsigned long) end_of_DRAM;
+
+ set_prom_callback();
+
+ *memory_start_p = copy_device_tree(*memory_start_p, *memory_end_p);
+
+ /* Set loops_per_sec to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0) {
+ switch (_get_PVR() >> 16) {
+ case 4: /* 604 */
+ case 9: /* 604e */
+ case 20: /* 620 */
+ loops_per_sec = *fp;
+ break;
+ default: /* 601, 603, etc. */
+ loops_per_sec = *fp / 2;
+ }
+ } else
+ loops_per_sec = 50000000;
+ }
+}
+
+char *bootpath;
+char bootdevice[256];
+void *boot_host;
+int boot_target;
+int boot_part;
+kdev_t boot_dev;
+
+unsigned long
+powermac_init(unsigned long mem_start, unsigned long mem_end)
+{
+ struct device_node *chosen_np, *ohare_np;
+
+ mem_start = pmac_find_bridges(mem_start, mem_end);
+ ohare_np = find_devices("ohare");
+ if (ohare_np != NULL) {
+ printk(KERN_INFO "Twiddling the magic ohare bits\n");
+ out_le32(OMAGICPLACE, OMAGICCONT);
+ }
+ pmac_nvram_init();
+ via_cuda_init();
+ pmac_read_rtc_time();
+ pmac_find_display();
+ bootpath = NULL;
+ chosen_np = find_devices("chosen");
+ if (chosen_np != NULL)
+ bootpath = (char *) get_property(chosen_np, "bootpath", NULL);
+ if (bootpath != NULL) {
+ /*
+ * There's a bug in the prom. (Why am I not surprised.)
+ * If you pass a path like scsi/sd@1:0 to canon, it returns
+ * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+ * That is, the scsi target number doesn't get preserved.
+ */
+ call_prom("canon", 3, 1, bootpath, bootdevice, sizeof(bootdevice));
+ }
+ return mem_start;
+}
+
+void
+note_scsi_host(struct device_node *node, void *host)
+{
+ int l;
+ char *p;
+
+ l = strlen(node->full_name);
+ if (strncmp(node->full_name, bootdevice, l) == 0
+ && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+ boot_host = host;
+ p = strstr(bootpath, "/sd@");
+ if (p != NULL) {
+ p += 4;
+ boot_target = simple_strtoul(p, NULL, 10);
+ p = strchr(p, ':');
+ if (p != NULL)
+ boot_part = simple_strtoul(p + 1, NULL, 10);
+ }
+ }
+}
+
+void find_boot_device(void)
+{
+ int dev;
+
+ if (kdev_t_to_nr(ROOT_DEV) != 0)
+ return;
+ ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+ if (boot_host == NULL)
+ return;
+#ifdef CONFIG_SCSI
+ dev = sd_find_target(boot_host, boot_target);
+ if (dev == 0)
+ return;
+ boot_dev = to_kdev_t(dev + boot_part);
+#endif
+ /* XXX should cope with booting from IDE also */
+}
+
+void note_bootable_part(kdev_t dev, int part)
+{
+ static int found_boot = 0;
+
+ if (!found_boot) {
+ find_boot_device();
+ found_boot = 1;
+ }
+ if (dev == boot_dev) {
+ ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
+ boot_dev = NODEV;
+ printk(" (root)");
+ }
+}
+
+void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ struct device_node *np;
+ int i;
+ static struct device_node *atas;
+ static int atas_valid;
+
+ *p = 0;
+ *irq = 0;
+ if (!atas_valid) {
+ atas = find_devices("ATA");
+ atas_valid = 1;
+ }
+ for (i = (int)base, np = atas; i > 0 && np != NULL; --i, np = np->next)
+ ;
+ if (np == NULL)
+ return;
+ if (np->n_addrs == 0) {
+ printk("ide: no addresses for device %s\n", np->full_name);
+ return;
+ }
+ if (np->n_intrs == 0) {
+ printk("ide: no intrs for device %s, using 13\n",
+ np->full_name);
+ *irq = 13;
+ } else {
+ *irq = np->intrs[0];
+ }
+ base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
+ for (i = 0; i < 8; ++i)
+ *p++ = base + i * 0x10;
+ *p = base + 0x160;
+}
+
+int
+pmac_get_cpuinfo(char *buffer)
+{
+ int pvr = _get_PVR();
+ char *model;
+ struct device_node *cpu;
+ int l, *fp;
+
+ l = 0;
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ l += sprintf(buffer, "%dMHz ", *fp / 1000000);
+ }
+
+ switch (pvr>>16) {
+ case 1:
+ model = "601";
+ break;
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ case 9:
+ model = "604e";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+ return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
+ (pvr & 0xff00) >> 8, pvr & 0xff);
+}
diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c
new file mode 100644
index 000000000..3c1895088
--- /dev/null
+++ b/arch/ppc/kernel/pmac_support.c
@@ -0,0 +1,69 @@
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ */
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+
+void pmac_nvram_init(void)
+{
+ struct device_node *dp;
+
+ dp = find_devices("nvram");
+ if (dp == NULL) {
+ printk(KERN_ERR "Can't find NVRAM device\n");
+ nvram_naddrs = 0;
+ return;
+ }
+ nvram_naddrs = dp->n_addrs;
+ if (nvram_naddrs == 1) {
+ nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ } else if (nvram_naddrs == 2) {
+ nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+ } else {
+ printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+ nvram_naddrs);
+ }
+}
+
+unsigned char nvram_read_byte(int addr)
+{
+ switch (nvram_naddrs) {
+ case 1:
+ return nvram_data[(addr & 0x1fff) << 4];
+ case 2:
+ *nvram_addr = addr >> 5;
+ eieio();
+ return nvram_data[(addr & 0x1f) << 4];
+ }
+ return 0;
+}
+
+void nvram_write_byte(unsigned char val, int addr)
+{
+ switch (nvram_naddrs) {
+ case 1:
+ nvram_data[(addr & 0x1fff) << 4] = val;
+ break;
+ case 2:
+ *nvram_addr = addr >> 5;
+ eieio();
+ nvram_data[(addr & 0x1f) << 4] = val;
+ break;
+ }
+ eieio();
+}
diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c
new file mode 100644
index 000000000..69a17321d
--- /dev/null
+++ b/arch/ppc/kernel/pmac_time.c
@@ -0,0 +1,87 @@
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * At present, we use the decrementer register in the 601 CPU
+ * for our periodic interrupts. This will probably have to be
+ * changed for other processors.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+#include "time.h"
+
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET 2082844800
+
+/*
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
+ */
+void pmac_calibrate_decr(void)
+{
+ struct device_node *cpu;
+ int freq, *fp, divisor;
+
+ /*
+ * The cpu node should have a timebase-frequency property
+ * to tell us the rate at which the decrementer counts.
+ */
+ cpu = find_type_devices("cpu");
+ if (cpu == 0)
+ panic("can't find cpu node in time_init");
+ fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+ if (fp == 0)
+ panic("can't get cpu timebase frequency");
+ freq = *fp * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n",
+ freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+unsigned long
+pmac_get_rtc_time(void)
+{
+ struct cuda_request req;
+
+ /* Get the time from the RTC */
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
+ while (!req.got_reply)
+ cuda_poll();
+ if (req.reply_len != 7)
+ printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+ req.reply_len);
+ return (req.reply[3] << 24) + (req.reply[4] << 16)
+ + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+}
+
+int pmac_set_rtc_time(unsigned long nowtime)
+{
+ return 0;
+}
+
+/*
+ * We can't do this in time_init, because via_cuda_init hasn't
+ * been called at that stage.
+ */
+void
+pmac_read_rtc_time(void)
+{
+ xtime.tv_sec = pmac_get_rtc_time();
+ xtime.tv_usec = 0;
+}
diff --git a/arch/ppc/kernel/ppc_asm.tmpl b/arch/ppc/kernel/ppc_asm.tmpl
index e31dea266..7036f4a62 100644
--- a/arch/ppc/kernel/ppc_asm.tmpl
+++ b/arch/ppc/kernel/ppc_asm.tmpl
@@ -187,7 +187,3 @@ n:
#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-
-/* Missing instructions */
-#define bdne bc 0,2,
-
diff --git a/arch/ppc/kernel/ppc_defs.head b/arch/ppc/kernel/ppc_defs.head
new file mode 100644
index 000000000..fbe926459
--- /dev/null
+++ b/arch/ppc/kernel/ppc_defs.head
@@ -0,0 +1,3 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
new file mode 100644
index 000000000..ea2a073eb
--- /dev/null
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -0,0 +1,221 @@
+/*
+ * $Id: ppc_htab.c,v 1.7 1997/08/24 19:33:32 cort Exp $
+ *
+ * PowerPC hash table management proc entry. Will show information
+ * about the current hash table and will allow changes to it.
+ *
+ * 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/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+static long ppc_htab_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long nbytes);
+static long ppc_htab_write(struct inode * inode, struct file * file,
+ const char * buffer, unsigned long count);
+static long long ppc_htab_lseek(struct inode * inode, struct file * file,
+ long long offset, int orig);
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern unsigned long _SDR1;
+
+static struct file_operations ppc_htab_operations = {
+ ppc_htab_lseek, /* lseek */
+ ppc_htab_read, /* read */
+ ppc_htab_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+/*
+ * proc files can do almost nothing..
+ */
+struct inode_operations proc_ppc_htab_inode_operations = {
+ &ppc_htab_operations, /* default proc file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+
+/*
+ * print some useful info about the hash table. This function
+ * is _REALLY_ slow (see the nested for loops below) but nothing
+ * in here should be really timing critical. -- Cort
+ */
+static long ppc_htab_read(struct inode * inode, struct file * file,
+ char * buf, unsigned long nbytes)
+{
+ int n = 0, valid;
+ unsigned int kptes = 0, overflow = 0, uptes = 0;
+ PTE *ptr;
+ struct task_struct *p;
+ char buffer[128];
+
+ if (nbytes < 0)
+ return -EINVAL;
+
+ /*
+ * compute user/kernel pte's table this info can be
+ * misleading since there can be valid (v bit set) entries
+ * in the table but their vsid is used by no process (mm->context)
+ * due to the way tlb invalidation is handled on the ppc
+ * -- Cort
+ */
+ for ( ptr = Hash ; ptr < Hash_end ; ptr += sizeof(PTE))
+ {
+ if (ptr->v)
+ {
+ /* make sure someone is using this context/vsid */
+ for_each_task(p)
+ {
+ if ( (ptr->vsid >> 4) == p->mm->context )
+ {
+ valid = 1;
+ break;
+ }
+ }
+ if ( !valid )
+ continue;
+ /* user not allowed read or write */
+ if (ptr->pp == PP_RWXX)
+ kptes++;
+ else
+ uptes++;
+ if (ptr->h == 1)
+ overflow++;
+ }
+ }
+
+ n += sprintf( buffer,
+ "Size\t\t: %luKb\n"
+ "Buckets\t\t: %lu\n"
+ "Address\t\t: %08lx\n"
+ "Entries\t\t: %lu\n"
+ "User ptes\t: %u\n"
+ "Kernel ptes\t: %u\n"
+ "Overflows\t: %u\n"
+ "Percent full\t: %%%lu\n",
+ (unsigned long)(Hash_size>>10),
+ (Hash_size/(sizeof(PTE)*8)),
+ (unsigned long)Hash,
+ Hash_size/sizeof(PTE),
+ uptes,
+ kptes,
+ overflow,
+ ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
+ );
+
+ if (file->f_pos >= strlen(buffer))
+ return 0;
+ if (n > strlen(buffer) - file->f_pos)
+ n = strlen(buffer) - file->f_pos;
+ copy_to_user(buf, buffer + file->f_pos, n);
+ file->f_pos += n;
+ return n;
+}
+
+/*
+ * Can't _yet_ adjust the hash table size while running. -- Cort
+ */
+static long
+ppc_htab_write(struct inode * inode, struct file * file,
+ const char * buffer, unsigned long count)
+{
+ unsigned long size;
+ extern void reset_SDR1(void);
+
+ if ( current->uid != 0 )
+ return -EACCES;
+
+ /* only know how to set size right now */
+ if ( strncmp( buffer, "size ", 5) )
+ return -EINVAL;
+
+ size = simple_strtoul( &buffer[5], NULL, 10 );
+
+ /* only allow to shrink */
+ if ( size >= Hash_size>>10 )
+ return -EINVAL;
+
+ /* minimum size of htab */
+ if ( size < 64 )
+ return -EINVAL;
+
+ /* make sure it's a multiple of 64k */
+ if ( size % 64 )
+ return -EINVAL;
+
+ printk("Hash table resize to %luk\n", size);
+ /*
+ * We need to rehash all kernel entries for the new htab size.
+ * Kernel only since we do a flush_tlb_all(). Since it's kernel
+ * we only need to bother with vsids 0-15. To avoid problems of
+ * clobbering un-rehashed values we put the htab at a new spot
+ * and put everything there.
+ * -- Cort
+ */
+ Hash_size = size<<10;
+ Hash_mask = (Hash_size >> 6) - 1;
+ _SDR1 = __pa(Hash) | (Hash_mask >> 10);
+ flush_tlb_all();
+
+ reset_SDR1();
+ printk("done\n");
+ return count;
+}
+
+
+static long long
+ppc_htab_lseek(struct inode * inode, struct file * file,
+ long long offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return(file->f_pos);
+ case 1:
+ file->f_pos += offset;
+ return(file->f_pos);
+ case 2:
+ return(-EINVAL);
+ default:
+ return(-EINVAL);
+ }
+}
+
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
new file mode 100644
index 000000000..fd2ad89ff
--- /dev/null
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -0,0 +1,140 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bios32.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/checksum.h>
+#include <asm/pgtable.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void do_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+extern unsigned lost_interrupts;
+extern void do_lost_interrupts(unsigned long);
+
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(do_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(lost_interrupts);
+EXPORT_SYMBOL(do_lost_interrupts);
+
+EXPORT_SYMBOL(atomic_add);
+EXPORT_SYMBOL(atomic_sub);
+EXPORT_SYMBOL(atomic_inc);
+EXPORT_SYMBOL(atomic_inc_return);
+EXPORT_SYMBOL(atomic_dec);
+EXPORT_SYMBOL(atomic_dec_return);
+EXPORT_SYMBOL(atomic_dec_and_test);
+
+EXPORT_SYMBOL(set_bit);
+EXPORT_SYMBOL(clear_bit);
+EXPORT_SYMBOL(change_bit);
+EXPORT_SYMBOL(test_and_set_bit);
+EXPORT_SYMBOL(test_and_clear_bit);
+EXPORT_SYMBOL(test_and_change_bit);
+#if 0
+EXPORT_SYMBOL(ffz);
+EXPORT_SYMBOL(find_first_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
+#endif
+
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strspn);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(memcmp);
+
+/* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(csum_tcpudp_magic);
+
+EXPORT_SYMBOL(__copy_tofrom_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(strlen_user);
+
+/*
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+EXPORT_SYMBOL(outsl);*/
+
+EXPORT_SYMBOL(_insw);
+EXPORT_SYMBOL(_outsw);
+EXPORT_SYMBOL(_insl);
+EXPORT_SYMBOL(_outsl);
+EXPORT_SYMBOL(ioremap);
+
+EXPORT_SYMBOL(start_thread);
+
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__cli);
+EXPORT_SYMBOL(__sti);
+/*EXPORT_SYMBOL(__restore_flags);*/
+EXPORT_SYMBOL(_disable_interrupts);
+EXPORT_SYMBOL(_enable_interrupts);
+EXPORT_SYMBOL(flush_instruction_cache);
+EXPORT_SYMBOL(_get_PVR);
+EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(flush_icache_range);
+EXPORT_SYMBOL(xchg_u32);
+
+EXPORT_SYMBOL(cuda_request);
+EXPORT_SYMBOL(cuda_send_request);
+EXPORT_SYMBOL(adb_register);
+EXPORT_SYMBOL(abort);
+EXPORT_SYMBOL(call_prom);
+EXPORT_SYMBOL(find_devices);
+EXPORT_SYMBOL(find_type_devices);
+EXPORT_SYMBOL(find_path_device);
+EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(pci_io_base);
+EXPORT_SYMBOL(pci_device_loc);
+EXPORT_SYMBOL(note_scsi_host);
diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c
new file mode 100644
index 000000000..ffacd94c9
--- /dev/null
+++ b/arch/ppc/kernel/prep_pci.c
@@ -0,0 +1,436 @@
+/*
+ * $Id: prep_pci.c,v 1.7 1997/08/23 22:46:02 cort Exp $
+ * PReP pci functions.
+ * Originally by Gary Thomas
+ * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * The motherboard routes/maps will disappear shortly. -- Cort
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+
+#define MAX_DEVNR 22
+
+/* Which PCI interrupt line does a given device [slot] use? */
+/* Note: This really should be two dimensional based in slot/pin used */
+unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
+
+/* How is the 82378 PIRQ mapping setup? */
+unsigned char *Motherboard_routes;
+
+/* Tables for known hardware */
+
+/* Motorola PowerStack */
+static char Blackhawk_pci_IRQ_map[16] =
+{
+ 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 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+};
+
+static char Blackhawk_pci_IRQ_routes[] =
+{
+ 0, /* Line 0 - Unused */
+ 9, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/* Motorola MVME16xx */
+static char Genesis_pci_IRQ_map[16] =
+{
+ 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 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+};
+
+static char Genesis_pci_IRQ_routes[] =
+{
+ 0, /* Line 0 - Unused */
+ 10, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/* Motorola Series-E */
+static char Comet_pci_IRQ_map[16] =
+{
+ 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 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 1, /* Slot 14 - Ethernet */
+ 0, /* Slot 15 - unused */
+};
+
+static char Comet_pci_IRQ_routes[] =
+{
+ 0, /* Line 0 - Unused */
+ 10, /* Line 1 */
+ 11, /* Line 2 */
+ 14, /* Line 3 */
+ 15 /* Line 4 */
+};
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] = {
+ 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 - FireCoral */
+ 4, /* Slot 12 - Ethernet PCIINTD# */
+ 2, /* Slot 13 - PCI Slot #2 */
+ 2, /* Slot 14 - S3 Video PCIINTD# */
+ 0, /* Slot 15 - onboard SCSI (INDI) [1] */
+ 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+ 0, /* Slot 17 - unused */
+ 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+static char ibm8xx_pci_IRQ_routes[] = {
+ 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] ={
+ 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 - unused */
+ 3, /* Slot 12 - SCSI */
+ 0, /* Slot 13 - unused */
+ 0, /* Slot 14 - unused */
+ 0, /* Slot 15 - unused */
+};
+
+static char Nobis_pci_IRQ_routes[] = {
+ 0, /* Line 0 - Unused */
+ 13, /* Line 1 */
+ 13, /* Line 2 */
+ 13, /* Line 3 */
+ 13 /* Line 4 */
+};
+
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
+#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
+
+int
+prep_pcibios_read_config_dword (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned int *val)
+{
+ unsigned long _val;
+ unsigned long *ptr;
+ dev >>= 3;
+
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ *val = 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+ _val = le32_to_cpu(*ptr);
+ }
+ *val = _val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_read_config_word (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned short *val)
+{
+ unsigned short _val;
+ unsigned short *ptr;
+ dev >>= 3;
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ *val = (unsigned short)0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+ _val = le16_to_cpu(*ptr);
+ }
+ *val = _val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_read_config_byte (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned char *val)
+{
+ unsigned char _val;
+ volatile unsigned char *ptr;
+ dev >>= 3;
+ /* Note: the configuration registers don't always have this right! */
+ if (offset == PCI_INTERRUPT_LINE)
+ {
+ *val = Motherboard_routes[Motherboard_map[dev]];
+/*printk("dev %d map %d route %d on board %d\n",
+ dev,Motherboard_map[dev],
+ Motherboard_routes[Motherboard_map[dev]],
+ *(unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1)));*/
+ return PCIBIOS_SUCCESSFUL;
+ }
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ *(unsigned long *)val = (unsigned long) 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1));
+ _val = *ptr;
+ }
+ *val = _val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_write_config_dword (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned int val)
+{
+ unsigned long _val;
+ unsigned long *ptr;
+ dev >>= 3;
+ _val = le32_to_cpu(val);
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+ *ptr = _val;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_write_config_word (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned short val)
+{
+ unsigned short _val;
+ unsigned short *ptr;
+ dev >>= 3;
+ _val = le16_to_cpu(val);
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+ *ptr = _val;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+prep_pcibios_write_config_byte (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned char val)
+{
+ unsigned char _val;
+ unsigned char *ptr;
+ dev >>= 3;
+ _val = val;
+ if ((bus != 0) || (dev > MAX_DEVNR))
+ {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset^1));
+ *ptr = _val;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int prep_pcibios_find_device (unsigned short vendor, unsigned short device_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+/*printk("pcibios_find_device(): vendor %04x devid %04x index %d\n",
+ vendor,device_id,index);*/
+ for (dev = pci_devices; dev; dev = dev->next) {
+/*printk(" dev->vendor %04x dev->device %04x\n",
+ dev->vendor,dev->device);*/
+ if (dev->vendor == vendor && dev->device == device_id) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+/*
+ * Given the class, find the n'th instance of that device
+ * in the system.
+ */
+int prep_pcibios_find_class (unsigned int class_code, unsigned short index,
+ unsigned char *bus, unsigned char *devfn)
+{
+ unsigned int curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->class == class_code) {
+ if (curr == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(unsigned long route_pci_interrupts(void))
+{
+ unsigned char *ibc_pirq = (unsigned char *)0x80800860;
+ unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
+ int i;
+
+ if ( _machine == _MACH_Motorola)
+ {
+ switch (inb(0x800) & 0xF0)
+ {
+ case 0x10: /* MVME16xx */
+ Motherboard_map_name = "Genesis";
+ Motherboard_map = Genesis_pci_IRQ_map;
+ Motherboard_routes = Genesis_pci_IRQ_routes;
+ break;
+ case 0x20: /* Series E */
+ Motherboard_map_name = "Series E";
+ Motherboard_map = Comet_pci_IRQ_map;
+ Motherboard_routes = Comet_pci_IRQ_routes;
+ break;
+ case 0x40: /* PowerStack */
+ default: /* Can't hurt, can it? */
+ Motherboard_map_name = "Blackhawk (Powerstack)";
+ Motherboard_map = Blackhawk_pci_IRQ_map;
+ Motherboard_routes = Blackhawk_pci_IRQ_routes;
+ break;
+ }
+ } else if ( _machine == _MACH_IBM )
+ {
+ unsigned char pl_id;
+
+ if (inb(0x0852) == 0xFF) {
+ Motherboard_map_name = "IBM 850/860 Portable\n";
+ Motherboard_map = Nobis_pci_IRQ_map;
+ Motherboard_routes = Nobis_pci_IRQ_routes;
+ } else {
+ Motherboard_map_name = "IBM 8xx (Carolina)";
+ Motherboard_map = ibm8xx_pci_IRQ_map;
+ Motherboard_routes = ibm8xx_pci_IRQ_routes;
+ }
+ /*printk("Changing IRQ mode\n");*/
+ pl_id=inb(0x04d0);
+ /*printk("Low mask is %#0x\n", pl_id);*/
+ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
+
+ pl_id=inb(0x04d1);
+ /*printk("Hi mask is %#0x\n", pl_id);*/
+ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
+ pl_id=inb(0x04d1);
+ /*printk("Hi mask now %#0x\n", pl_id);*/
+ } else
+ {
+ printk("No known machine pci routing!\n");
+ return -1;
+ }
+
+ /* Set up mapping from slots */
+ for (i = 1; i <= 4; i++)
+ {
+ ibc_pirq[i-1] = Motherboard_routes[i];
+ }
+ /* Enable PCI interrupts */
+ *ibc_pcicon |= 0x20;
+ return 0;
+}
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
new file mode 100644
index 000000000..18e013964
--- /dev/null
+++ b/arch/ppc/kernel/prep_setup.c
@@ -0,0 +1,294 @@
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+
+/* for the mac fs */
+kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+extern unsigned char aux_device_present;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+#endif
+
+
+extern char saved_command_line[256];
+
+void prep_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++ = base + 0x206;
+ if (irq != NULL)
+ *irq = 0;
+}
+
+
+int
+prep_get_cpuinfo(char *buffer)
+{
+ extern char *Motherboard_map_name;
+ extern RESIDUAL res;
+ int i;
+ int pvr = _get_PVR();
+ int len;
+ char *model;
+
+ switch (pvr>>16)
+ {
+ case 1:
+ model = "601";
+ break;
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+
+#ifdef __SMP__
+#define CD(X) (cpu_data[n].X)
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+
+ len = sprintf(buffer,"processor\t: %d\n"
+ "cpu\t\t: %s\n"
+ "revision\t: %d.%d\n"
+ "upgrade\t\t: %s\n"
+ "clock\t\t: %dMHz\n"
+ "bus clock\t: %dMHz\n"
+ "machine\t\t: %s (sn %s)\n"
+ "pci map\t\t: %s\n",
+ CPUN,
+ model,
+ MAJOR(pvr), MINOR(pvr),
+ (inb(IBM_EQUIP_PRESENT) & 2) ? "not upgrade" : "upgrade",
+ (res.VitalProductData.ProcessorHz > 1024) ?
+ res.VitalProductData.ProcessorHz>>20 :
+ res.VitalProductData.ProcessorHz,
+ (res.VitalProductData.ProcessorBusHz > 1024) ?
+ res.VitalProductData.ProcessorBusHz>>20 :
+ res.VitalProductData.ProcessorBusHz,
+ res.VitalProductData.PrintableModel,
+ res.VitalProductData.Serial,
+ Motherboard_map_name
+ );
+
+ /* print info about SIMMs */
+ len += sprintf(buffer+len,"simms\t\t: ");
+ for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
+ {
+ if ( res.Memories[i].SIMMSize != 0 )
+ len += sprintf(buffer+len,"%d:%dM ",i,
+ (res.Memories[i].SIMMSize > 1024) ?
+ res.Memories[i].SIMMSize>>20 :
+ res.Memories[i].SIMMSize);
+ }
+ len += sprintf(buffer+len,"\n");
+
+ /* TLB */
+ len += sprintf(buffer+len,"tlb\t\t:");
+ switch(res.VitalProductData.TLBAttrib)
+ {
+ case CombinedTLB:
+ len += sprintf(buffer+len," %d entries\n",
+ res.VitalProductData.TLBSize);
+ break;
+ case SplitTLB:
+ len += sprintf(buffer+len," (split I/D) %d/%d entries\n",
+ res.VitalProductData.I_TLBSize,
+ res.VitalProductData.D_TLBSize);
+ break;
+ case NoneTLB:
+ len += sprintf(buffer+len," not present\n");
+ break;
+ }
+
+ /* L1 */
+ len += sprintf(buffer+len,"l1\t\t: ");
+ switch(res.VitalProductData.CacheAttrib)
+ {
+ case CombinedCAC:
+ len += sprintf(buffer+len,"%dkB LineSize\n",
+ res.VitalProductData.CacheSize,
+ res.VitalProductData.CacheLineSize);
+ break;
+ case SplitCAC:
+ len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
+ res.VitalProductData.I_CacheSize,
+ res.VitalProductData.D_CacheSize,
+ res.VitalProductData.D_CacheLineSize,
+ res.VitalProductData.D_CacheLineSize);
+ break;
+ case NoneCAC:
+ len += sprintf(buffer+len,"not present\n");
+ break;
+ }
+
+ /* 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");
+ }
+
+
+ len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
+ CD(loops_per_sec+2500)/500000,
+ (CD(loops_per_sec+2500)/5000) % 100);
+
+ /*
+ * Ooh's and aah's info about zero'd pages in idle task
+ */
+ {
+ extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
+ len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
+ "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
+ zerototal, (zerototal*PAGE_SIZE)>>10,
+ zerocount, (zerocount*PAGE_SIZE)>>10,
+ zeropage_hits,zeropage_calls,
+ /* : 1 below is so we don't div by zero */
+ (zeropage_hits*100) /
+ ((zeropage_calls)?zeropage_calls:1));
+ }
+ return len;
+}
+
+__initfunc(void
+prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+ unsigned long * memory_end_p))
+{
+ extern char cmd_line[];
+ extern char _etext[], _edata[], _end[];
+ extern int panic_timeout;
+ unsigned char reg;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ strcpy( saved_command_line, cmd_line );
+ *cmdline_p = cmd_line;
+
+ *memory_start_p = (unsigned long) Hash+Hash_size;
+ (unsigned long *)*memory_end_p = (unsigned long *)(res.TotalMemory+KERNELBASE);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_sec = 50000000;
+
+ /* reboot on panic */
+ panic_timeout = 180;
+
+ init_task.mm->start_code = PAGE_OFFSET;
+ init_task.mm->end_code = (unsigned long) _etext;
+ init_task.mm->end_data = (unsigned long) _edata;
+ init_task.mm->brk = (unsigned long) _end;
+
+ aux_device_present = 0xaa;
+ /* Set up floppy in PS/2 mode */
+ outb(0x09, SIO_CONFIG_RA);
+ reg = inb(SIO_CONFIG_RD);
+ reg = (reg & 0x3F) | 0x40;
+ outb(reg, SIO_CONFIG_RD);
+ outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
+
+ switch ( _machine )
+ {
+ case _MACH_IBM:
+ ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+ break;
+ case _MACH_Motorola:
+ ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+ break;
+ }
+
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+ ROOT_DEV = to_kdev_t(0x0200); /* floppy */
+ rd_prompt = 1;
+ rd_doload = 1;
+ rd_image_start = 0;
+#endif
+ /* 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
+
+ printk("Boot arguments: %s\n", cmd_line);
+
+ print_residual_device_info();
+
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+}
diff --git a/arch/ppc/kernel/prep_time.c b/arch/ppc/kernel/prep_time.c
new file mode 100644
index 000000000..da0151ede
--- /dev/null
+++ b/arch/ppc/kernel/prep_time.c
@@ -0,0 +1,239 @@
+/*
+ * linux/arch/i386/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * Adapted for PowerPC (PreP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * copied and modified from intel version
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+/*
+ * The motorola uses the m48t18 rtc (includes DS1643) whose registers
+ * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
+ * rtc (ds1386) which has regs at addr 0-d). The intel gets
+ * past this because the bios emulates the mc146818.
+ *
+ * Why in the world did they have to use different clocks?
+ *
+ * Right now things are hacked to check which machine we're on then
+ * use the appropriate macro. This is very very ugly and I should
+ * probably have a function that checks which machine we're on then
+ * does things correctly transparently or a function pointer which
+ * is setup at boot time to use the correct addresses.
+ * -- Cort
+ */
+/*
+ * translate from mc146818 to m48t18 addresses
+ */
+unsigned int clock_transl[] = { MOTO_RTC_SECONDS,0 /* alarm */,
+ MOTO_RTC_MINUTES,0 /* alarm */,
+ MOTO_RTC_HOURS,0 /* alarm */, /* 4,5 */
+ MOTO_RTC_DAY_OF_WEEK,
+ MOTO_RTC_DAY_OF_MONTH,
+ MOTO_RTC_MONTH,
+ MOTO_RTC_YEAR, /* 9 */
+ MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
+};
+
+int prep_cmos_clock_read(int addr)
+{
+ if ( _machine == _MACH_IBM )
+ return CMOS_READ(addr);
+ else if ( _machine == _MACH_Motorola )
+ {
+ outb(clock_transl[addr]>>8, NVRAM_AS1);
+ outb(clock_transl[addr], NVRAM_AS0);
+ return (inb(NVRAM_DATA));
+ }
+
+ printk("Unknown machine in prep_cmos_clock_read()!\n");
+ return -1;
+}
+
+void prep_cmos_clock_write(unsigned long val, int addr)
+{
+ if ( _machine == _MACH_IBM )
+ {
+ CMOS_WRITE(val,addr);
+ return;
+ }
+ else if ( _machine == _MACH_Motorola )
+ {
+ outb(clock_transl[addr]>>8, NVRAM_AS1);
+ outb(clock_transl[addr], NVRAM_AS0);
+ outb(val,NVRAM_DATA);
+ return;
+ }
+ printk("Unknown machine in prep_cmos_clock_write()!\n");
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+int prep_set_rtc_time(unsigned long nowtime)
+{
+ unsigned char save_control, save_freq_select;
+ struct rtc_time tm;
+
+ to_tm(nowtime, &tm);
+
+ save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
+
+ prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+
+ prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ tm.tm_year -= 1900;
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_year);
+ }
+ prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+ prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+ prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+ prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+ prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+ prep_cmos_clock_write(tm.tm_year,RTC_YEAR);
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ prep_cmos_clock_write(save_control, RTC_CONTROL);
+ prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+
+ if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+ time_state = TIME_OK;
+ return 0;
+}
+
+unsigned long prep_get_rtc_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = prep_cmos_clock_read(RTC_SECONDS);
+ min = prep_cmos_clock_read(RTC_MINUTES);
+ hour = prep_cmos_clock_read(RTC_HOURS);
+ day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
+ mon = prep_cmos_clock_read(RTC_MONTH);
+ year = prep_cmos_clock_read(RTC_YEAR);
+ } while (sec != prep_cmos_clock_read(RTC_SECONDS));
+ if (!(prep_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+#if 0
+void time_init(void)
+{
+ void (*irq_handler)(int, void *,struct pt_regs *);
+
+ xtime.tv_sec = prep_get_rtc_time();
+ xtime.tv_usec = 0;
+
+ prep_calibrate_decr();
+
+ /* If we have the CPU hardware time counters, use them */
+ irq_handler = timer_interrupt;
+ if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
+{
+ prep_calibrate_decr_handler(irq,dev,regs);
+ do_timer(regs);
+
+ /* update the hw clock if:
+ * the time is marked out of sync (TIME_ERROR)
+ * or ~11 minutes have expired since the last update -- Cort
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. prep_set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+ if ( time_state == TIME_BAD ||
+ xtime.tv_sec > last_rtc_update + 660 )
+ /*if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))*/
+ if (prep_set_rtc_time(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+
+
+#ifdef CONFIG_HEARTBEAT
+ /* use hard disk LED as a heartbeat instead -- much more useful
+ for debugging -- Cort */
+ switch(kstat.interrupts[0] % 101)
+ {
+ /* act like an actual heart beat -- ie thump-thump-pause... */
+ case 0:
+ case 20:
+ outb(1,IBM_HDD_LED);
+ break;
+ case 7:
+ case 27:
+ outb(0,IBM_HDD_LED);
+ break;
+ case 100:
+ break;
+ }
+#endif
+}
+#endif
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index f24872063..5e194fedb 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -7,7 +7,7 @@
* Derived from "arch/i386/kernel/process.c"
* Copyright (C) 1995 Linus Torvalds
*
- * Modified by Cort Dougan (cort@cs.nmt.edu) and
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
* Paul Mackerras (paulus@cs.anu.edu.au)
*
* This program is free software; you can redistribute it and/or
@@ -28,22 +28,22 @@
#include <linux/ptrace.h>
#include <linux/malloc.h>
#include <linux/user.h>
-#include <linux/a.out.h>
+#include <linux/elf.h>
#include <linux/config.h>
+#include <linux/elf.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/smp_lock.h>
+#include <asm/processor.h>
-int dump_fpu(void);
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
void switch_to(struct task_struct *, struct task_struct *);
-void print_backtrace(unsigned long *);
-void show_regs(struct pt_regs * regs);
-void inline zero_paged(void);
extern unsigned long _get_SP(void);
+
#undef SHOW_TASK_SWITCHES 1
#undef CHECK_STACK 1
#undef IDLE_ZERO 1
@@ -59,7 +59,7 @@ task_top(struct task_struct *tsk)
{
return ((unsigned long)tsk) + sizeof(struct task_struct);
}
-
+
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
@@ -69,9 +69,12 @@ struct mm_struct init_mm = INIT_MM;
union task_union init_task_union = { INIT_TASK };
int
-dump_fpu(void)
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
{
- return (1);
+ if (last_task_used_math == current)
+ giveup_fpu();
+ memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
+ return 1;
}
/* check to make sure the kernel stack is healthy */
@@ -80,7 +83,6 @@ int check_stack(struct task_struct *tsk)
unsigned long stack_top = kernel_stack_top(tsk);
unsigned long tsk_top = task_top(tsk);
int ret = 0;
- unsigned long *i;
#if 0
/* check tss magic */
@@ -98,7 +100,7 @@ int check_stack(struct task_struct *tsk)
if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
{
printk("stack out of bounds: %s/%d\n"
- " tsk_top %08x ksp %08x stack_top %08x\n",
+ " tsk_top %08lx ksp %08lx stack_top %08lx\n",
tsk->comm,tsk->pid,
tsk_top, tsk->tss.ksp, stack_top);
ret |= 2;
@@ -108,7 +110,7 @@ int check_stack(struct task_struct *tsk)
if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
{
printk("current stack ptr out of bounds: %s/%d\n"
- " tsk_top %08x sp %08x stack_top %08x\n",
+ " tsk_top %08lx sp %08lx stack_top %08lx\n",
current->comm,current->pid,
tsk_top, _get_SP(), stack_top);
ret |= 4;
@@ -143,15 +145,12 @@ switch_to(struct task_struct *prev, struct task_struct *new)
{
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
- struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
#if CHECK_STACK
check_stack(prev);
check_stack(new);
#endif
- /* turn off fpu for task last to run */
- /*prev->tss.regs->msr &= ~MSR_FP;*/
-
+
#ifdef SHOW_TASK_SWITCHES
printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
prev->comm,prev->pid,prev->tss.regs->nip,
@@ -160,289 +159,29 @@ switch_to(struct task_struct *prev, struct task_struct *new)
new_tss = &new->tss;
old_tss = &current->tss;
_switch(old_tss, new_tss, new->mm->context);
- /* turn off fpu for task last to run */
_enable_interrupts(s);
}
-
-#include <linux/mc146818rtc.h>
-asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
-{
-#if 1
- struct task_struct *p;
- printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
- printk("last %x\n", last_task_used_math);
- printk("cur %x regs %x/%x tss %x/%x\n",
- current, current->tss.regs,regs,&current->tss,current->tss);
- for_each_task(p)
- {
- if ((long)p < KERNELBASE)
- {
- printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
- print_mm_info();
- __cli();
- while(1);
- }
- }
- return regs->gpr[3];
-#endif
-#if 0
- /* set the time in the cmos clock */
- unsigned long hwtime, nowtime;
- struct rtc_time tm;
-
- hwtime = get_cmos_time();
- to_tm(hwtime, &tm);
- printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
- tm.tm_mday, tm.tm_year);
- return;
-#endif
-}
-/*
- * vars for idle task zero'ing out pages
- */
-unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
-unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
-unsigned long zerocount = 0; /* # currently pre-zero'd pages */
-unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
-unsigned long pageptr = 0; /* current page being zero'd */
-unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
-
-/*
- * Returns a pre-zero'd page from the list otherwise returns
- * NULL.
- */
-unsigned long get_prezerod_page(void)
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
{
- unsigned long page;
- unsigned long s;
-
- if ( zero_list )
- {
- /* atomically remove this page from the list */
- asm ( "101:lwarx %1,0,%2\n" /* reserve zero_list */
- " lwz %0,0(%1)\n" /* get next -- new zero_list */
- " stwcx. %0,0,%2\n" /* update zero_list */
- " bne- 101b\n" /* if lost reservation try again */
- : "=&r" (zero_list), "=&r" (page)
- : "r" (&zero_list)
- : "cc" );
- /* we can update zerocount after the fact since it is not
- * used for anything but control of a loop which doesn't
- * matter since it won't effect anything if it zero's one
- * less page -- Cort
- */
- atomic_inc((atomic_t *)&zeropage_hits);
- atomic_dec((atomic_t *)&zerocount);
- /* zero out the pointer to next in the page */
- *(unsigned long *)page = 0;
- return page;
- }
return 0;
}
-/*
- * Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages() -- Cort
- * Zero's out pages until we need to resched or
- * we've reached the limit of zero'd pages.
- */
-void inline zero_paged(void)
-{
- extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
- unsigned long tmp;
- pte_t ptep;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- sprintf(current->comm, "zero_paged");
- printk("Started zero_paged\n");
- /* want priority over idle task and powerd */
- current->priority = -98;
- current->counter = -98;
- __sti();
-
- while ( zerocount < 128 )
- {
- /*
- * Mark a page as reserved so we can mess with it
- * If we're interrupted we keep this page and our place in it
- * since we validly hold it and it's reserved for us.
- */
- pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
- if ( !pageptr )
- {
- printk("!pageptr in zero_paged\n");
- goto retry;
- }
-
- if ( need_resched )
- schedule();
-
- /*
- * Make the page no cache so we don't blow our cache with 0's
- */
- dir = pgd_offset( init_task.mm, pageptr );
- if (dir)
- {
- pmd = pmd_offset(dir, pageptr & PAGE_MASK);
- if (pmd && pmd_present(*pmd))
- {
- pte = pte_offset(pmd, pageptr & PAGE_MASK);
- if (pte && pte_present(*pte))
- {
- pte_uncache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
- }
- }
- }
-
- /*
- * Important here to not take time away from real processes.
- */
- for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
- {
- if ( need_resched )
- schedule();
- *(unsigned long *)(bytecount + pageptr) = 0;
- }
-
- /*
- * If we finished zero-ing out a page add this page to
- * the zero_list atomically -- we can't use
- * down/up since we can't sleep in idle.
- * Disabling interrupts is also a bad idea since we would
- * steal time away from real processes.
- * We can also have several zero_paged's running
- * on different processors so we can't interfere with them.
- * So we update the list atomically without locking it.
- * -- Cort
- */
- /* turn cache on for this page */
- pte_cache(*pte);
- flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-
- /* atomically add this page to the list */
- asm ( "101:lwarx %0,0,%1\n" /* reserve zero_list */
- " stw %0,0(%2)\n" /* update *pageptr */
-#ifdef __SMP__
- " sync\n" /* let store settle */
-#endif
- " mr %0,%2\n" /* update zero_list in reg */
- " stwcx. %2,0,%1\n" /* update zero_list in mem */
- " bne- 101b\n" /* if lost reservation try again */
- : "=&r" (zero_list)
- : "r" (&zero_list), "r" (pageptr)
- : "cc" );
- /*
- * This variable is used in the above loop and nowhere
- * else so the worst that could happen is we would
- * zero out one more or one less page than we want
- * per processor on the machine. This is because
- * we could add our page to the list but not have
- * zerocount updated yet when another processor
- * reads it. -- Cort
- */
- atomic_inc((atomic_t *)&zerocount);
- atomic_inc((atomic_t *)&zerototal);
-retry:
- schedule();
- }
-}
-
-void powerd(void)
-{
- unsigned long msr, hid0;
-
- sprintf(current->comm, "powerd");
- __sti();
- while (1)
- {
- /* want priority over idle task 'swapper' -- Cort */
- current->priority = -99;
- current->counter = -99;
- asm volatile(
- /* clear powersaving modes and set nap mode */
- "mfspr %3,1008 \n\t"
- "andc %3,%3,%4 \n\t"
- "or %3,%3,%5 \n\t"
- "mtspr 1008,%3 \n\t"
- /* enter the mode */
- "mfmsr %0 \n\t"
- "oris %0,%0,%2 \n\t"
- "sync \n\t"
- "mtmsr %0 \n\t"
- "isync \n\t"
- : "=&r" (msr)
- : "0" (msr), "i" (MSR_POW>>16),
- "r" (hid0),
- "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
- "r" (HID0_NAP));
- if ( need_resched )
- schedule();
- /*
- * The ibm carolina spec says that the eagle memory
- * controller will detect the need for a snoop
- * and wake up the processor so we don't need to
- * check for cache operations that need to be
- * snooped. The ppc book says the run signal
- * must be asserted while napping for this though.
- * -- Cort
- */
- }
-}
-
-asmlinkage int sys_idle(void)
-{
- int ret = -EPERM;
- if (current->pid != 0)
- goto out;
-
-#ifdef IDLE_ZERO
- /*
- * want one per cpu since it would be nice to have all
- * processors who aren't doing anything
- * zero-ing pages since this daemon is lock-free
- * -- Cort
- */
- kernel_thread(zero_paged, NULL, 0);
-#endif /* IDLE_ZERO */
-
-#ifdef CONFIG_POWERSAVING
- /* no powersaving modes on 601 - one per processor */
- if( (_get_PVR()>>16) != 1 )
- kernel_thread(powerd, NULL, 0);
-#endif /* CONFIG_POWERSAVING */
-
- /* endless loop with no priority at all */
- current->priority = -100;
- current->counter = -100;
- for (;;)
- {
- schedule();
- }
- ret = 0;
-out:
- return ret;
-}
-
void show_regs(struct pt_regs * regs)
{
int i;
- printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+ printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
regs->nip, regs->xer, regs->link, regs,regs->trap);
- printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
regs->msr&MSR_IR ? 1 : 0,
regs->msr&MSR_DR ? 1 : 0);
- printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+ printk("TASK = %p[%d] '%s' mm->pgd %p ",
current, current->pid, current->comm, current->mm->pgd);
- printk("Last syscall: %d ", current->tss.last_syscall);
- printk("\nlast math %08X\n", last_task_used_math);
+ printk("Last syscall: %ld ", current->tss.last_syscall);
+ printk("\nlast math %p\n", last_task_used_math);
for (i = 0; i < 32; i++)
{
long r;
@@ -451,9 +190,9 @@ void show_regs(struct pt_regs * regs)
printk("GPR%02d: ", i);
}
- if ( get_user(r, &(regs->gpr[i])) )
+ if ( __get_user(r, &(regs->gpr[i])) )
goto out;
- printk("%08X ", r);
+ printk("%08lX ", r);
if ((i % 8) == 7)
{
printk("\n");
@@ -480,14 +219,14 @@ release_thread(struct task_struct *t)
}
/*
- * Copy a thread..
- */
+ * Copy a thread..
+ */
int
copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
- int i;
struct pt_regs * childregs;
+
/* Copy registers */
childregs = ((struct pt_regs *)
((unsigned long)p + sizeof(union task_union)
@@ -497,13 +236,13 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
if ((childregs->msr & MSR_PR) == 0)
childregs->gpr[2] = (unsigned long) p; /* `current' in new task */
childregs->gpr[3] = 0; /* Result from fork() */
- p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
- p->tss.regs = (struct pt_regs *)(childregs);
- if (usp >= (unsigned long)regs)
- { /* Stack is in kernel space - must adjust */
- childregs->gpr[1] = (long)(childregs+1);
- } else
- { /* Provided stack is in user space */
+ p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
+ p->tss.regs = childregs;
+ if (usp >= (unsigned long) regs) {
+ /* Stack is in kernel space - must adjust */
+ childregs->gpr[1] = (unsigned long)(childregs + 1);
+ } else {
+ /* Provided stack is in user space */
childregs->gpr[1] = usp;
}
@@ -511,24 +250,75 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
/*
* copy fpu info - assume lazy fpu switch now always
- * this should really be conditional on whether or
- * not the process has used the fpu
* -- Cort
*/
if ( last_task_used_math == current )
giveup_fpu();
-
+
memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
p->tss.fpscr = current->tss.fpscr;
childregs->msr &= ~MSR_FP;
-
+
return 0;
}
+/*
+ * XXX ld.so expects the auxiliary table to start on
+ * a 16-byte boundary, so we have to find it and
+ * move it up. :-(
+ */
+static inline void shove_aux_table(unsigned long sp)
+{
+ int argc;
+ char *p;
+ unsigned long e;
+ unsigned long aux_start, offset;
+
+ if (__get_user(argc, (int *)sp))
+ return;
+ sp += sizeof(int) + (argc + 1) * sizeof(char *);
+ /* skip over the environment pointers */
+ do {
+ if (__get_user(p, (char **)sp))
+ return;
+ sp += sizeof(char *);
+ } while (p != NULL);
+ aux_start = sp;
+ /* skip to the end of the auxiliary table */
+ do {
+ if (__get_user(e, (unsigned long *)sp))
+ return;
+ sp += 2 * sizeof(unsigned long);
+ } while (e != AT_NULL);
+ offset = ((aux_start + 15) & ~15) - aux_start;
+ if (offset != 0) {
+ do {
+ sp -= sizeof(unsigned long);
+ if (__get_user(e, (unsigned long *)sp)
+ || __put_user(e, (unsigned long *)(sp + offset)))
+ return;
+ } while (sp > aux_start);
+ }
+}
+
+/*
+ * Set up a thread for executing a new program
+ */
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
+{
+ set_fs(USER_DS);
+ regs->nip = nip;
+ regs->gpr[1] = sp;
+ regs->msr = MSR_USER;
+ shove_aux_table(sp);
+}
+
+
asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
struct pt_regs *regs)
{
int ret;
+
lock_kernel();
ret = do_fork(SIGCHLD, regs->gpr[1], regs);
unlock_kernel();
@@ -541,26 +331,26 @@ asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
{
int error;
char * filename;
- filename = (int) getname((char *) a0);
+
+ filename = getname((char *) a0);
error = PTR_ERR(filename);
- if(IS_ERR(filename))
+ if (IS_ERR(filename))
goto out;
if ( last_task_used_math == current )
last_task_used_math = NULL;
error = do_execve(filename, (char **) a1, (char **) a2, regs);
-
putname(filename);
-
out:
unlock_kernel();
return error;
}
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+ struct pt_regs *regs)
{
unsigned long clone_flags = p1;
int res;
-
+
lock_kernel();
res = do_fork(clone_flags, regs->gpr[1], regs);
unlock_kernel();
@@ -571,34 +361,23 @@ void
print_backtrace(unsigned long *sp)
{
int cnt = 0;
- int i;
+ unsigned long i;
+
printk("Call backtrace: ");
- while ( !get_user(i, sp) && i)
- {
- if ( get_user( i, &sp[1] ) )
- return;
- printk("%08X ", i);
- if ( get_user( (ulong)sp, sp) )
- return;
- if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
- if (++cnt == 8)
- {
+ while (sp) {
+ if (__get_user( i, &sp[1] ))
+ break;
+ if (cnt++ % 7 == 0)
printk("\n");
- }
+ printk("%08lX ", i);
if (cnt > 32) break;
+ if (__get_user(sp, (unsigned long **)sp))
+ break;
}
printk("\n");
}
-inline void start_thread(struct pt_regs * regs,
- unsigned long eip, unsigned long esp)
-{
- set_fs(USER_DS);
- regs->nip = eip;
- regs->gpr[1] = esp;
- regs->msr = MSR_USER;
-}
-
+#if 0
/*
* Low level print for debugging - Cort
*/
@@ -651,3 +430,4 @@ void ll_puts(const char *s)
orig_x = x;
orig_y = y;
}
+#endif /* CONFIG_PREP */
diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
new file mode 100644
index 000000000..c7a566a14
--- /dev/null
+++ b/arch/ppc/kernel/prom.c
@@ -0,0 +1,524 @@
+/*
+ * Procedures for interfacing to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * In particular, we are interested in the device tree
+ * and in using some of its services (exit, write to stdout).
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+
+#define getpromprop(node, name, buf, len) \
+ ((int)call_prom("getprop", 4, 1, (node), (name), (buf), (len)))
+
+ihandle prom_stdout;
+ihandle prom_chosen;
+
+char command_line[256];
+int screen_initialized = 0;
+
+char prom_display_path[128];
+
+struct prom_args {
+ const char *service;
+ int nargs;
+ int nret;
+ void *args[10];
+} prom_args;
+
+struct pci_address {
+ unsigned a_hi;
+ unsigned a_mid;
+ unsigned a_lo;
+};
+
+struct pci_reg_property {
+ struct pci_address addr;
+ unsigned size_hi;
+ unsigned size_lo;
+};
+
+struct pci_range {
+ struct pci_address addr;
+ unsigned phys;
+ unsigned size_hi;
+ unsigned size_lo;
+};
+
+void (*prom_entry)(void *);
+extern int prom_trashed;
+
+static int prom_callback(struct prom_args *);
+static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
+ unsigned long, unsigned long);
+static void check_display(void);
+static int prom_next_node(phandle *);
+
+extern int pmac_display_supported(const char *);
+extern void enter_prom(void *);
+
+void
+prom_exit()
+{
+ struct prom_args args;
+
+ args.service = "exit";
+ args.nargs = 0;
+ args.nret = 0;
+ enter_prom(&args);
+ for (;;) /* should never get here */
+ ;
+}
+
+void *
+call_prom(const char *service, int nargs, int nret, ...)
+{
+ va_list list;
+ int i;
+
+ if (prom_trashed)
+ panic("prom called after its memory was reclaimed");
+ prom_args.service = service;
+ prom_args.nargs = nargs;
+ prom_args.nret = nret;
+ va_start(list, nret);
+ for (i = 0; i < nargs; ++i)
+ prom_args.args[i] = va_arg(list, void *);
+ va_end(list);
+ for (i = 0; i < nret; ++i)
+ prom_args.args[i + nargs] = 0;
+ enter_prom(&prom_args);
+ return prom_args.args[nargs];
+}
+
+void
+prom_print(const char *msg)
+{
+ const char *p, *q;
+ const char *crlf = "\r\n";
+
+ if (screen_initialized)
+ return;
+ for (p = msg; *p != 0; p = q) {
+ for (q = p; *q != 0 && *q != '\n'; ++q)
+ ;
+ if (q > p)
+ call_prom("write", 3, 1, prom_stdout, p, q - p);
+ if (*q != 0) {
+ ++q;
+ call_prom("write", 3, 1, prom_stdout, crlf, 2);
+ }
+ }
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+void
+prom_init(char *params, int unused, void (*pp)(void *))
+{
+ /* First get a handle for the stdout device */
+ if ( ! have_of() )
+ return;
+ prom_entry = pp;
+ prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
+ if (prom_chosen == (void *)-1)
+ prom_exit();
+ call_prom("getprop", 4, 1, prom_chosen, "stdout", &prom_stdout,
+ (void *) sizeof(prom_stdout));
+
+ /*
+ * If we were booted via quik, params points to the physical address
+ * of the command-line parameters.
+ * If we were booted from an xcoff image (i.e. netbooted or
+ * booted from floppy), we get the command line from the bootargs
+ * property of the /chosen node. If an initial ramdisk is present,
+ * params and unused are used for initrd_start and initrd_size,
+ * otherwise they contain 0xdeadbeef.
+ */
+ command_line[0] = 0;
+ if ((unsigned long) params >= 0x4000
+ && (unsigned long) params < 0x800000
+ && unused == 0) {
+ strncpy(command_line, params+KERNELBASE, sizeof(command_line));
+ } else {
+#ifdef CONFIG_BLK_DEV_INITRD
+ if ((unsigned long) params - KERNELBASE < 0x800000
+ && unused != 0 && unused != 0xdeadbeef) {
+ initrd_start = (unsigned long) params;
+ initrd_end = initrd_start + unused;
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ }
+#endif
+ call_prom("getprop", 4, 1, prom_chosen, "bootargs",
+ command_line, sizeof(command_line));
+ }
+ command_line[sizeof(command_line) - 1] = 0;
+
+ check_display();
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later. However, OF may fall over if we do that after
+ * we've taken over the MMU and done set_prom_callback.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static void
+check_display()
+{
+ phandle node;
+ ihandle ih;
+ char type[16], name[64], path[128];
+
+ for (node = 0; prom_next_node(&node); ) {
+ type[0] = 0;
+ getpromprop(node, "device_type", type, sizeof(type));
+ if (strcmp(type, "display") != 0)
+ continue;
+ name[0] = 0;
+ getpromprop(node, "name", name, sizeof(name));
+ if (pmac_display_supported(name))
+ /* we have a supported display */
+ return;
+ }
+ printk(KERN_INFO "No supported display found\n");
+ for (node = 0; prom_next_node(&node); ) {
+ type[0] = 0;
+ getpromprop(node, "device_type", type, sizeof(type));
+ if (strcmp(type, "display") != 0)
+ continue;
+ /* It seems OF doesn't null-terminate the path :-( */
+ memset(path, 0, sizeof(path));
+ if ((int) call_prom("package-to-path", 3, 1,
+ node, path, sizeof(path) - 1) < 0) {
+ printk(KERN_WARNING "can't get path for display %p\n",
+ node);
+ continue;
+ }
+ ih = call_prom("open", 1, 1, path);
+ if (ih == 0 || ih == (ihandle) -1) {
+ printk(KERN_WARNING "couldn't open display %s\n",
+ path);
+ continue;
+ }
+ printk(KERN_INFO "Opened display device %s using "
+ "Open Firmware\n", path);
+ strcpy(prom_display_path, path);
+ break;
+ }
+}
+
+static int
+prom_next_node(phandle *nodep)
+{
+ phandle node;
+
+ if ((node = *nodep) != 0
+ && (*nodep = call_prom("child", 1, 1, node)) != 0)
+ return 1;
+ if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+ return 1;
+ for (;;) {
+ if ((node = call_prom("parent", 1, 1, node)) == 0)
+ return 0;
+ if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+ return 1;
+ }
+}
+
+/*
+ * Callback routine for the PROM to call us.
+ * No services are implemented yet :-)
+ */
+static int
+prom_callback(struct prom_args *argv)
+{
+ printk("uh oh, prom callback '%s' (%d/%d)\n", argv->service,
+ argv->nargs, argv->nret);
+ return -1;
+}
+
+/*
+ * Register a callback with the Open Firmware PROM so it can ask
+ * us to map/unmap memory, etc.
+ */
+void
+set_prom_callback()
+{
+ call_prom("set-callback", 1, 1, prom_callback);
+}
+
+void
+abort()
+{
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ prom_exit();
+}
+
+/*
+ * Make a copy of the device tree from the PROM.
+ */
+
+static struct device_node *allnodes;
+static struct device_node **allnextp;
+
+#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+
+unsigned long
+copy_device_tree(unsigned long mem_start, unsigned long mem_end)
+{
+ phandle root;
+
+ root = call_prom("peer", 1, 1, (phandle)0);
+ if (root == (phandle)0)
+ panic("couldn't get device tree root\n");
+ allnextp = &allnodes;
+ mem_start = inspect_node(root, 0, 0, mem_start, mem_end);
+ *allnextp = 0;
+ return mem_start;
+}
+
+static unsigned long
+inspect_node(phandle node, struct device_node *dad, unsigned long base_address,
+ unsigned long mem_start, unsigned long mem_end)
+{
+ struct reg_property *reg, *rp;
+ struct pci_reg_property *pci_addrs;
+ int l, i;
+ phandle child;
+ struct device_node *np;
+ struct property *pp, **prev_propp;
+ char *prev_name;
+
+ np = (struct device_node *) mem_start;
+ mem_start += sizeof(struct device_node);
+ memset(np, 0, sizeof(*np));
+ np->node = node;
+ *allnextp = np;
+ allnextp = &np->allnext;
+ np->parent = dad;
+ if (dad != 0) {
+ /* we temporarily use the `next' field as `last_child'. */
+ if (dad->next == 0)
+ dad->child = np;
+ else
+ dad->next->sibling = np;
+ dad->next = np;
+ }
+
+ /* get and store all properties */
+ prev_propp = &np->properties;
+ prev_name = 0;
+ for (;;) {
+ pp = (struct property *) mem_start;
+ pp->name = (char *) (pp + 1);
+ if ((int) call_prom("nextprop", 3, 1, node, prev_name,
+ pp->name) <= 0)
+ break;
+ mem_start = ALIGN((unsigned long)pp->name
+ + strlen(pp->name) + 1);
+ pp->value = (unsigned char *) mem_start;
+ pp->length = (int)
+ call_prom("getprop", 4, 1, node, pp->name, pp->value,
+ mem_end - mem_start);
+ if (pp->length < 0)
+ panic("hey, where did property %s go?", pp->name);
+ mem_start = ALIGN(mem_start + pp->length);
+ prev_name = pp->name;
+ *prev_propp = pp;
+ prev_propp = &pp->next;
+ }
+ *prev_propp = 0;
+
+ np->name = get_property(np, "name", 0);
+ np->type = get_property(np, "device_type", 0);
+
+ /* get all the device addresses and interrupts */
+ reg = (struct reg_property *) mem_start;
+ pci_addrs = (struct pci_reg_property *)
+ get_property(np, "assigned-addresses", &l);
+ i = 0;
+ if (pci_addrs != 0) {
+ while ((l -= sizeof(struct pci_reg_property)) >= 0) {
+ /* XXX assumes PCI addresses mapped 1-1 to physical */
+ reg[i].address = pci_addrs[i].addr.a_lo;
+ reg[i].size = pci_addrs[i].size_lo;
+ ++i;
+ }
+ } else {
+ rp = (struct reg_property *) get_property(np, "reg", &l);
+ if (rp != 0) {
+ while ((l -= sizeof(struct reg_property)) >= 0) {
+ reg[i].address = rp[i].address + base_address;
+ reg[i].size = rp[i].size;
+ ++i;
+ }
+ }
+ }
+ if (i > 0) {
+ np->addrs = reg;
+ np->n_addrs = i;
+ mem_start += i * sizeof(struct reg_property);
+ }
+
+ np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
+ if (np->intrs != 0)
+ np->n_intrs = l / sizeof(int);
+
+ /* get the node's full name */
+ l = (int) call_prom("package-to-path", 3, 1, node,
+ (char *) mem_start, mem_end - mem_start);
+ if (l >= 0) {
+ np->full_name = (char *) mem_start;
+ np->full_name[l] = 0;
+ mem_start = ALIGN(mem_start + l + 1);
+ }
+
+ if (np->type != 0 && strcmp(np->type, "dbdma") == 0 && np->n_addrs > 0)
+ base_address = np->addrs[0].address;
+
+ child = call_prom("child", 1, 1, node);
+ while (child != (void *)0) {
+ mem_start = inspect_node(child, np, base_address,
+ mem_start, mem_end);
+ child = call_prom("peer", 1, 1, child);
+ }
+
+ return mem_start;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given name.
+ */
+struct device_node *
+find_devices(const char *name)
+{
+ struct device_node *head, **prevp, *np;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ if (np->name != 0 && strcasecmp(np->name, name) == 0) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ }
+ *prevp = 0;
+ return head;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given type.
+ */
+struct device_node *
+find_type_devices(const char *type)
+{
+ struct device_node *head, **prevp, *np;
+
+ prevp = &head;
+ for (np = allnodes; np != 0; np = np->allnext) {
+ if (np->type != 0 && strcasecmp(np->type, type) == 0) {
+ *prevp = np;
+ prevp = &np->next;
+ }
+ }
+ *prevp = 0;
+ return head;
+}
+
+/*
+ * Find the device_node with a given full_name.
+ */
+struct device_node *
+find_path_device(const char *path)
+{
+ struct device_node *np;
+
+ for (np = allnodes; np != 0; np = np->allnext)
+ if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
+ return np;
+ return NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *
+get_property(struct device_node *np, const char *name, int *lenp)
+{
+ struct property *pp;
+
+ for (pp = np->properties; pp != 0; pp = pp->next)
+ if (strcmp(pp->name, name) == 0) {
+ if (lenp != 0)
+ *lenp = pp->length;
+ return pp->value;
+ }
+ return 0;
+}
+
+void
+print_properties(struct device_node *np)
+{
+ struct property *pp;
+ char *cp;
+ int i, n;
+
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ printk(KERN_INFO "%s", pp->name);
+ for (i = strlen(pp->name); i < 16; ++i)
+ printk(" ");
+ cp = (char *) pp->value;
+ for (i = pp->length; i > 0; --i, ++cp)
+ if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
+ || (i == 1 && *cp != 0))
+ break;
+ if (i == 0 && pp->length > 1) {
+ /* looks like a string */
+ printk(" %s\n", (char *) pp->value);
+ } else {
+ /* dump it in hex */
+ n = pp->length;
+ if (n > 64)
+ n = 64;
+ if (pp->length % 4 == 0) {
+ unsigned int *p = (unsigned int *) pp->value;
+
+ n /= 4;
+ for (i = 0; i < n; ++i) {
+ if (i != 0 && (i % 4) == 0)
+ printk("\n ");
+ printk(" %08x", *p++);
+ }
+ } else {
+ unsigned char *bp = pp->value;
+
+ for (i = 0; i < n; ++i) {
+ if (i != 0 && (i % 16) == 0)
+ printk("\n ");
+ printk(" %02x", *bp++);
+ }
+ }
+ printk("\n");
+ if (pp->length > 64)
+ printk(" ... (length = %d)\n",
+ pp->length);
+ }
+ }
+}
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index a5ec62d20..8a5839d1f 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -171,8 +171,11 @@ repeat:
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (MAP_NR(page) < max_mapnr)
- *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+ if (MAP_NR(page) < max_mapnr) {
+ unsigned long phys_addr = page + (addr & ~PAGE_MASK);
+ *(unsigned long *) phys_addr = data;
+ flush_icache_range(phys_addr, phys_addr+4);
+ }
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
/* this should also re-instate whatever read-only mode there was before */
set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -364,7 +367,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKUSR: {
unsigned long tmp;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+ if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) {
ret = -EIO;
goto out;
}
@@ -378,13 +381,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (addr < PT_FPR0) {
tmp = get_reg(child, addr);
}
-#if 1
- else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+ else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
if (last_task_used_math == child)
giveup_fpu();
tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
}
-#endif
else
ret = -EIO;
if (!ret)
@@ -400,7 +401,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
ret = -EIO;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+ if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2))
goto out;
addr = addr >> 2; /* temporary hack. */
@@ -508,7 +509,7 @@ asmlinkage void syscall_trace(void)
goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c
new file mode 100644
index 000000000..4084f9f62
--- /dev/null
+++ b/arch/ppc/kernel/residual.c
@@ -0,0 +1,144 @@
+/*
+ * $Id: residual.c,v 1.2 1997/08/25 06:54:56 cort Exp $
+ *
+ * Code to deal with the PReP residual data.
+ *
+ * Written by: Cort Dougan (cort@cs.nmt.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#include <asm/pnp.h>
+
+
+/*
+ * Spit out some info about residual data
+ */
+void print_residual_device_info(void)
+{
+ int i;
+ union _PnP_TAG_PACKET *pkt;
+ PPC_DEVICE *dev;
+#define did dev->DeviceId
+
+ /* make sure we have residual data first */
+ if ( res.ResidualLength == 0 )
+ return;
+
+ printk("Residual: %ld devices\n", res.ActualNumDevices);
+ for ( i = 0;
+ i < res.ActualNumDevices ;
+ i++)
+ {
+ dev = &res.Devices[i];
+ /*
+ * pci devices
+ */
+ if ( did.BusId & PCIDEVICE )
+ {
+ printk("PCI Device:");
+ /* unknown vendor */
+ if ( !strncmp( "Unknown", pci_strvendor(did.DevId>>16), 7) )
+ printk(" id %08lx types %d/%d", did.DevId,
+ did.BaseType, did.SubType);
+ /* known vendor */
+ else
+ printk(" %s %s",
+ pci_strvendor(did.DevId>>16),
+ pci_strdev(did.DevId>>16,
+ did.DevId&0xffff)
+ );
+
+ if ( did.BusId & PNPISADEVICE )
+ {
+ printk(" pnp:");
+ /* get pnp info on the device */
+ pkt = (union _PnP_TAG_PACKET *)
+ &res.DevicePnPHeap[dev->AllocatedOffset];
+ for (; pkt->S1_Pack.Tag != DF_END_TAG;
+ pkt++ )
+ {
+ if ( (pkt->S1_Pack.Tag == S4_Packet) ||
+ (pkt->S1_Pack.Tag == S4_Packet_flags) )
+ printk(" irq %02x%02x",
+ pkt->S4_Pack.IRQMask[0],
+ pkt->S4_Pack.IRQMask[1]);
+ }
+ }
+ printk("\n");
+ continue;
+ }
+ /*
+ * isa devices
+ */
+ if ( did.BusId & ISADEVICE )
+ {
+ printk("ISA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * eisa devices
+ */
+ if ( did.BusId & EISADEVICE )
+ {
+ printk("EISA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * proc bus devices
+ */
+ if ( did.BusId & PROCESSORDEVICE )
+ {
+ printk("ProcBus Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ /*
+ * pcmcia devices
+ */
+ if ( did.BusId & PCMCIADEVICE )
+ {
+ printk("PCMCIA Device: basetype: %d subtype: %d",
+ did.BaseType, did.SubType);
+ printk("\n");
+ continue;
+ }
+ printk("Unknown bus access device: busid %lx\n",
+ did.BusId);
+ }
+}
+
+
+
+
+
+
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index e69de29bb..f3769cad0 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -0,0 +1,268 @@
+/*
+ * $Id: setup.c,v 1.16 1997/08/27 22:06:54 cort Exp $
+ * Common prep/pmac boot and setup code.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/openpic.h>
+
+#include <asm/cuda.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/ide.h>
+
+char saved_command_line[256];
+unsigned char aux_device_present;
+
+/* copy of the residual data */
+RESIDUAL res;
+int _machine;
+
+/*
+ * Perhaps we can put the pmac screen_info[] here
+ * on pmac as well so we don't need the ifdef's.
+ * Until we get multiple-console support in here
+ * that is. -- Cort
+ */
+#if defined(CONFIG_CHRP) || defined(CONFIG_PREP )
+struct screen_info screen_info = {
+ 0, 25, /* orig-x, orig-y */
+ { 0, 0 }, /* unused */
+ 0, /* orig-video-page */
+ 0, /* orig-video-mode */
+ 80, /* orig-video-cols */
+ 0,0,0, /* ega_ax, ega_bx, ega_cx */
+ 25, /* orig-video-lines */
+ 1, /* orig-video-isVGA */
+ 16 /* orig-video-points */
+};
+
+/*
+ * I really need to add multiple-console support... -- Cort
+ */
+int pmac_display_supported(char *name)
+{
+ return 0;
+}
+int sd_find_target(void *a, int b)
+{
+ return 0;
+}
+void pmac_find_display(void)
+{
+}
+
+#endif
+
+/*
+ * Find out what kind of machine we're on and save any data we need
+ * from the early boot process (devtree is copied on pmac by prom_init() )
+ */
+unsigned long identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ extern unsigned long initrd_start, initrd_end;
+ extern char cmd_line[256];
+#ifdef CONFIG_PMAC /* cheat for now - perhaps a check for OF could tell us */
+ _machine = _MACH_Pmac;
+#endif /* CONFIG_PMAC */
+#ifdef CONFIG_PREP
+ /* make a copy of residual data */
+ if ( r3 )
+ memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(RESIDUAL) );
+ if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
+ _machine = _MACH_IBM;
+ else
+ _machine = _MACH_Motorola;
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_CHRP
+ _machine = _MACH_chrp;
+#endif /* CONFIG_CHRP */
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ io_base = 0;
+ pci_dram_offset = 0;
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
+ io_base = 0x80000000;
+ pci_dram_offset = 0x80000000;
+#ifdef CONFIG_BLK_DEV_RAM
+ /* take care of initrd if we have one */
+ if ( r4 )
+ {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+#endif /* CONFIG_BLK_DEV_RAM */
+ /* take care of cmd line */
+ if ( r6 )
+ {
+
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+ break;
+ case _MACH_chrp:
+ /* LongTrail */
+ io_base = 0xf8000000;
+ pci_dram_offset = 0;
+ /* take care of initrd if we have one */
+ if ( r4 ) {
+ initrd_start = r4 + KERNELBASE;
+ initrd_end = r5 + KERNELBASE;
+ }
+ /* take care of cmd line */
+ if ( r6 ) {
+ *(char *)(r7+KERNELBASE) = 0;
+ strcpy(cmd_line, (char *)(r6+KERNELBASE));
+ }
+ break;
+ default:
+ printk("Unknown machine type in identify_machine!\n");
+ }
+ return 0;
+}
+
+/* cmd is ignored for now... */
+void machine_restart(char *cmd)
+{
+ struct cuda_request req;
+ unsigned long flags;
+ unsigned long i = 10000;
+
+ switch(_machine)
+ {
+ case _MACH_Pmac:
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+ for (;;)
+ cuda_poll();
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
+ _disable_interrupts();
+
+ /* set exception prefix high - to the prom */
+ save_flags( flags );
+ restore_flags( flags|MSR_IP );
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb( inb(0x92) & ~1L , 0x92 );
+ /* signal a reset to system control port A - soft reset */
+ outb( inb(0x92) | 1 , 0x92 );
+
+ while ( i != 0 ) i++;
+ panic("restart failed\n");
+ break;
+
+ case _MACH_chrp:
+ openpic_init_processor(1<<0);
+ break;
+ }
+}
+
+void machine_power_off(void)
+{
+ struct cuda_request req;
+
+ if ( _machine == _MACH_Pmac )
+ {
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
+ for (;;)
+ cuda_poll();
+ }
+ else /* prep or chrp */
+ {
+ machine_restart(NULL);
+ }
+}
+
+void machine_halt(void)
+{
+ if ( _machine == _MACH_Pmac )
+ {
+#if 0
+ prom_exit(); /* doesn't work because prom is trashed */
+#else
+ machine_power_off(); /* for now */
+#endif
+ }
+ else /* prep or chrp */
+ machine_restart(NULL);
+
+}
+
+void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ if ( _machine == _MACH_Pmac )
+ pmac_ide_init_hwif_ports(p,base,irq);
+ else /* prep */
+ prep_ide_init_hwif_ports(p,base,irq);
+
+}
+
+/*
+ * Will merge more into here later -- Cort
+ */
+int get_cpuinfo(char *buffer)
+{
+ extern int pmac_get_cpuinfo(char *);
+ extern int chrp_get_cpuinfo(char *);
+ extern int prep_get_cpuinfo(char *);
+
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ return pmac_get_cpuinfo(buffer);
+ break;
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ return prep_get_cpuinfo(buffer);
+ break;
+ case _MACH_chrp:
+ return chrp_get_cpuinfo(buffer);
+ break;
+ }
+ printk("Unknown machine %d in get_cpuinfo()\n",_machine);
+ return 0;
+}
+
+
+__initfunc(unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end))
+{
+ return memory_start;
+}
+
+__initfunc(void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+ extern void pmac_setup_arch(char **, unsigned long *, unsigned long *);
+ extern void chrp_setup_arch(char **, unsigned long *, unsigned long *);
+ extern void prep_setup_arch(char **, unsigned long *, unsigned long *);
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ pmac_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ break;
+ case _MACH_Motorola:
+ case _MACH_IBM:
+ prep_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ break;
+ case _MACH_chrp:
+ return chrp_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+ break;
+ }
+ printk("Unknown machine %d in setup_arch()\n",_machine);
+}
+
+
+
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 2f602059c..3151d266a 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -24,6 +24,7 @@
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <linux/elf.h>
#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
@@ -36,6 +37,10 @@
#define PAUSE_AFTER_SIGNAL
#undef PAUSE_AFTER_SIGNAL
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
/*
@@ -71,32 +76,52 @@ printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, reg
}
}
+/*
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack. SE and BE
+ * should not be in this list since gdb may want to change these. I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE (MSR_FE0 | MSR_FE1)
+
/*
* This sets regs->esp even though we don't actually use sigstacks yet..
*/
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
- struct sigcontext_struct *sc;
- struct pt_regs *int_regs;
- int signo, ret;
+ struct sigcontext_struct *sc, sigctx;
+ int ret;
+ elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
-#if 1
- if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
- || (regs->gpr[1] >= KERNELBASE))
+ sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
goto badframe;
-#endif
- sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
- get_user(current->blocked, &sc->oldmask);
- current->blocked &= _BLOCKABLE;
- get_user(int_regs, &sc->regs);
- get_user(signo, &sc->signal);
+ current->blocked = sigctx.oldmask & _BLOCKABLE;
sc++; /* Pop signal 'context' */
#ifdef DEBUG_SIGNALS
-printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+ printk("Sig return - Regs: %p, sc: %p, sig: %d\n", sigctx.regs, sc,
+ sigctx.signal);
#endif
- if (sc == (struct sigcontext_struct *)(int_regs)) {
- /* Last stacked signal */
- memcpy(regs, int_regs, sizeof(*regs));
+ if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
+ /* Last stacked signal - restore registers */
+ if (last_task_used_math == current)
+ giveup_fpu();
+ if (copy_from_user(saved_regs, sigctx.regs, sizeof(saved_regs)))
+ goto badframe;
+ saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+ | (saved_regs[PT_MSR] & MSR_USERCHANGE);
+ memcpy(regs, saved_regs,
+ MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)));
+
+ if (copy_from_user(current->tss.fpr,
+ (unsigned long *)sigctx.regs + ELF_NGREG,
+ ELF_NFPREG * sizeof(double)))
+ goto badframe;
+
if (regs->trap == 0x0C00 /* System Call! */ &&
((int)regs->result == -ERESTARTNOHAND ||
(int)regs->result == -ERESTARTSYS ||
@@ -106,15 +131,17 @@ printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
regs->result = 0;
}
ret = regs->result;
+
} else {
/* More signals to go */
- regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
- get_user(regs->gpr[3], &sc->signal);
- get_user(int_regs, (struct pt_regs **) &sc->regs);
- regs->gpr[4] = (unsigned long) int_regs;
- regs->link = (unsigned long) (int_regs+1);
- get_user(regs->nip, &sc->handler);
- ret = regs->gpr[3];
+ regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
+ if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+ goto badframe;
+ regs->gpr[3] = ret = sigctx.signal;
+ regs->gpr[4] = (unsigned long) sigctx.regs;
+ regs->link = regs->gpr[4] + ELF_NGREG * sizeof(unsigned long)
+ + ELF_NFPREG * sizeof(double);
+ regs->nip = sigctx.handler;
}
return ret;
@@ -142,6 +169,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
unsigned long *frame = NULL;
unsigned long *trampoline;
unsigned long *regs_ptr;
+ double *fpregs_ptr;
unsigned long nip = 0;
unsigned long signr;
struct sigcontext_struct *sc;
@@ -164,7 +192,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -204,7 +232,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
@@ -257,18 +285,33 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
nip = regs->nip;
frame = (unsigned long *) regs->gpr[1];
- /* Build trampoline code on stack */
- frame -= 2;
+ /*
+ * Build trampoline code on stack, and save gp and fp regs.
+ * The 56 word hole is because programs using the rs6000/xcoff
+ * style calling sequence can save up to 19 gp regs and 18 fp regs
+ * on the stack before decrementing sp.
+ */
+ frame -= 2 + 56;
trampoline = frame;
- /* verify stack is valid for writing regs struct */
- if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
- || ((unsigned long) frame >= KERNELBASE ))
- goto badframe;
- put_user(0x38007777UL, trampoline); /* li r0,0x7777 */
- put_user(0x44000002UL, trampoline+1); /* sc */
- frame -= sizeof(*regs) / sizeof(long);
+ frame -= ELF_NFPREG * sizeof(double) / sizeof(unsigned long);
+ fpregs_ptr = (double *) frame;
+ frame -= ELF_NGREG;
regs_ptr = frame;
- copy_to_user(regs_ptr, regs, sizeof(*regs));
+ /* verify stack is valid for writing to */
+ if (verify_area(VERIFY_WRITE, frame,
+ (ELF_NGREG + 2) * sizeof(long)
+ + ELF_NFPREG * sizeof(double)))
+ goto badframe;
+ if (last_task_used_math == current)
+ giveup_fpu();
+ if (__copy_to_user(regs_ptr, regs,
+ MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)))
+ || __copy_to_user(fpregs_ptr, current->tss.fpr,
+ ELF_NFPREG * sizeof(double))
+ || __put_user(0x38007777UL, trampoline) /* li r0,0x7777 */
+ || __put_user(0x44000002UL, trampoline+1)) /* sc */
+ goto badframe;
+
signr = 1;
sa = current->sig->action;
@@ -279,24 +322,29 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
continue;
frame -= sizeof(struct sigcontext_struct) / sizeof(long);
- if (verify_area(VERIFY_WRITE,(void *)frame,
- sizeof(struct sigcontext_struct)/sizeof(long)))
+ if (verify_area(VERIFY_WRITE, frame,
+ sizeof(struct sigcontext_struct)))
goto badframe;
sc = (struct sigcontext_struct *)frame;
nip = (unsigned long) sa->sa_handler;
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- put_user(nip, &sc->handler);
- put_user(oldmask, &sc->oldmask); /* was current->blocked */
- put_user(regs_ptr, &sc->regs);
- put_user(signr, &sc->signal);
+ if (__put_user(nip, &sc->handler)
+ || __put_user(oldmask, &sc->oldmask)
+ || __put_user(regs_ptr, &sc->regs)
+ || __put_user(signr, &sc->signal))
+ goto badframe;
current->blocked |= sa->sa_mask;
regs->gpr[3] = signr;
- regs->gpr[4] = (unsigned long)regs_ptr;
+ regs->gpr[4] = (unsigned long) regs_ptr;
}
+
+ frame -= __SIGNAL_FRAMESIZE / sizeof(unsigned long);
+ if (put_user(regs->gpr[1], frame))
+ goto badframe;
regs->link = (unsigned long)trampoline;
regs->nip = nip;
- regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+ regs->gpr[1] = (unsigned long) frame;
/* The DATA cache must be flushed here to insure coherency */
/* between the DATA & INSTRUCTION caches. Since we just */
@@ -305,8 +353,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
/* cache for new data, we have to force the data to go on to */
/* memory and flush the instruction cache to force it to look */
/* there. The following function performs this magic */
- store_cache_range((unsigned long) trampoline,
- (unsigned long) (trampoline + 2));
+ flush_icache_range((unsigned long) trampoline,
+ (unsigned long) (trampoline + 2));
return 1;
badframe:
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
index bfdccdee6..b7bac7a6a 100644
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -1,15 +1,25 @@
/*
* linux/arch/ppc/kernel/sys_ppc.c
*
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/sys_i386.c"
* Adapted from the i386 version by Gary Thomas
* Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au).
*
* This file contains various random system calls that
* have a non-standard calling sequence on the Linux/PPC
* platform.
+ *
+ * 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/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -20,11 +30,11 @@
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/mman.h>
+#include <linux/sys.h>
#include <linux/ipc.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
-
void
check_bugs(void)
{
@@ -32,32 +42,32 @@ check_bugs(void)
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
{
- printk("sys_ioperm()\n");
+ printk(KERN_ERR "sys_ioperm()\n");
return -EIO;
}
int sys_iopl(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
int sys_vm86(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
int sys_modify_ldt(int a1, int a2, int a3, int a4)
{
lock_kernel();
- printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+ printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return (ENOSYS);
+ return (-ENOSYS);
}
/*
@@ -65,7 +75,8 @@ int sys_modify_ldt(int a1, int a2, int a3, int a4)
*
* This is really horribly ugly.
*/
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+asmlinkage int
+sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
{
int version, ret;
@@ -73,138 +84,113 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
version = call >> 16; /* hack for backward compatibility */
call &= 0xffff;
- if (call <= SEMCTL)
- switch (call) {
- case SEMOP:
- ret = sys_semop (first, (struct sembuf *)ptr, second);
- goto out;
- case SEMGET:
- ret = sys_semget (first, second, third);
- goto out;
- case SEMCTL: {
- union semun fourth;
- ret = -EINVAL;
- if (!ptr)
- goto out;
- ret = -EFAULT;
- if (get_user(fourth.__pad, (void **) ptr))
- goto out;
- ret = sys_semctl (first, second, third, fourth);
- goto out;
- }
- default:
- ret = -EINVAL;
- goto out;
+ ret = -EINVAL;
+ switch (call) {
+ case SEMOP:
+ ret = sys_semop (first, (struct sembuf *)ptr, second);
+ break;
+ case SEMGET:
+ ret = sys_semget (first, second, third);
+ break;
+ case SEMCTL: {
+ union semun fourth;
+
+ if (!ptr)
+ break;
+ if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+ || (ret = get_user(fourth.__pad, (void **)ptr)))
+ break;
+ ret = sys_semctl (first, second, third, fourth);
+ break;
}
- if (call <= MSGCTL)
- switch (call) {
- case MSGSND:
- ret = sys_msgsnd (first, (struct msgbuf *) ptr,
- second, third);
- goto out;
- case MSGRCV:
- switch (version) {
- case 0: {
- struct ipc_kludge tmp;
- ret = -EINVAL;
- if (!ptr)
- goto out;
- ret = -EFAULT;
- if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
- sizeof (tmp)))
- goto out;
- ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
- goto out;
- }
- case 1: default:
- ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
- goto out;
+ case MSGSND:
+ ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
+ break;
+ case MSGRCV:
+ switch (version) {
+ case 0: {
+ struct ipc_kludge tmp;
+
+ if (!ptr)
+ break;
+ if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+ || (ret = copy_from_user(&tmp,
+ (struct ipc_kludge *) ptr,
+ sizeof (tmp))))
+ break;
+ ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
+ third);
+ break;
}
- case MSGGET:
- ret = sys_msgget ((key_t) first, second);
- goto out;
- case MSGCTL:
- ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
- goto out;
default:
- ret = -EINVAL;
- goto out;
+ ret = sys_msgrcv (first, (struct msgbuf *) ptr,
+ second, fifth, third);
+ break;
}
- if (call <= SHMCTL)
- switch (call) {
- case SHMAT:
- switch (version) {
- case 0: default: {
- ulong raddr;
- ret = sys_shmat (first, (char *) ptr, second, &raddr);
- if (ret)
- goto out;
- ret = put_user (raddr, (ulong *) third);
- goto out;
+ break;
+ case MSGGET:
+ ret = sys_msgget ((key_t) first, second);
+ break;
+ case MSGCTL:
+ ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+ break;
+ case SHMAT:
+ switch (version) {
+ default: {
+ ulong raddr;
+
+ if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
+ sizeof(ulong))))
+ break;
+ ret = sys_shmat (first, (char *) ptr, second, &raddr);
+ if (ret)
+ break;
+ ret = put_user (raddr, (ulong *) third);
+ break;
}
- case 1: /* iBCS2 emulator entry point */
- ret = -EINVAL;
- if (get_fs() != get_ds())
- goto out;
- ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
- goto out;
- }
- case SHMDT:
- ret = sys_shmdt ((char *)ptr);
- goto out;
- case SHMGET:
- ret = sys_shmget (first, second, third);
- goto out;
- case SHMCTL:
- ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
- goto out;
- default:
- ret = -EINVAL;
- goto out;
+ case 1: /* iBCS2 emulator entry point */
+ if (get_fs() != get_ds())
+ break;
+ ret = sys_shmat (first, (char *) ptr, second,
+ (ulong *) third);
+ break;
}
- else
- ret = -EINVAL;
-out:
- unlock_kernel();
- return ret;
-}
-
+ break;
+ case SHMDT:
+ ret = sys_shmdt ((char *)ptr);
+ break;
+ case SHMGET:
+ ret = sys_shmget (first, second, third);
+ break;
+ case SHMCTL:
+ ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+ break;
+ }
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
- lock_kernel();
- panic("scsi_register_module");
- unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
- lock_kernel();
- panic("scsi_unregister_module");
unlock_kernel();
+ return ret;
}
-#endif
/*
* sys_pipe() is the normal C calling standard for creating
* a pipe. It's not the way unix traditionally does this, though.
*/
-asmlinkage int sys_pipe(unsigned long * fildes)
+asmlinkage int sys_pipe(int *fildes)
{
int fd[2];
int error;
- error = verify_area(VERIFY_WRITE,fildes,8);
+ error = verify_area(VERIFY_WRITE, fildes, 8);
if (error)
return error;
+ lock_kernel();
error = do_pipe(fd);
+ unlock_kernel();
if (error)
return error;
- put_user(fd[0],0+fildes);
- put_user(fd[1],1+fildes);
+ if (__put_user(fd[0],0+fildes)
+ || __put_user(fd[1],1+fildes))
+ return -EFAULT; /* should we close the fds? */
return 0;
}
@@ -213,13 +199,18 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
unsigned long fd, off_t offset)
{
struct file * file = NULL;
+ int ret = -EBADF;
+
+ lock_kernel();
if (!(flags & MAP_ANONYMOUS)) {
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- return -EBADF;
+ goto out;
}
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
- return do_mmap(file, addr, len, prot, flags, offset);
+ ret = do_mmap(file, addr, len, prot, flags, offset);
+out:
+ unlock_kernel();
+ return ret;
}
extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
@@ -233,15 +224,15 @@ extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timev
asmlinkage int
ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
- int err;
if ( (unsigned long)n >= 4096 )
{
unsigned long *buffer = (unsigned long *)n;
- if ( get_user(n, buffer) ||
- get_user(inp,buffer+1) ||
- get_user(outp,buffer+2) ||
- get_user(exp,buffer+3) ||
- get_user(tvp,buffer+4) )
+ if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long))
+ || __get_user(n, buffer)
+ || __get_user(inp, ((fd_set **)(buffer+1)))
+ || __get_user(outp, ((fd_set **)(buffer+2)))
+ || __get_user(exp, ((fd_set **)(buffer+3)))
+ || __get_user(tvp, ((struct timeval **)(buffer+4))))
return -EFAULT;
}
return sys_select(n, inp, outp, exp, tvp);
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index e69de29bb..fc172d7a7 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -0,0 +1,268 @@
+/*
+ * $Id: time.c,v 1.10 1997/08/27 22:06:56 cort Exp $
+ * Common time routines among all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/time.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+/* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */
+int (*set_rtc_time)(unsigned long);
+
+/* keep track of when we need to update the rtc */
+unsigned long last_rtc_update = 0;
+
+/* The decrementer counts down by 128 every 128ns on a 601. */
+#define DECREMENTER_COUNT_601 (1000000000 / HZ)
+#define COUNT_PERIOD_NUM_601 1
+#define COUNT_PERIOD_DEN_601 1000
+
+unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
+unsigned count_period_num; /* 1 decrementer count equals */
+unsigned count_period_den; /* count_period_num / count_period_den us */
+
+/* Accessor functions for the decrementer register. */
+inline unsigned long
+get_dec(void)
+{
+ int ret;
+
+ asm volatile("mfspr %0,22" : "=r" (ret) :);
+ return ret;
+}
+
+inline void
+set_dec(int val)
+{
+ asm volatile("mtspr 22,%0" : : "r" (val));
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * We set it up to overflow again in 1/HZ seconds.
+ */
+void timer_interrupt(struct pt_regs * regs)
+{
+ int dval, d;
+ while ((dval = get_dec()) < 0) {
+ /*
+ * Wait for the decrementer to change, then jump
+ * in and add decrementer_count to its value
+ * (quickly, before it changes again!)
+ */
+ while ((d = get_dec()) == dval)
+ ;
+ set_dec(d + decrementer_count);
+ do_timer(regs);
+ /*
+ * update the rtc when needed
+ */
+ if ( xtime.tv_sec > last_rtc_update + 660 )
+ if (set_rtc_time(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
+}
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ *tv = xtime;
+ tv->tv_usec += (decrementer_count - get_dec())
+ * count_period_num / count_period_den;
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ int frac_tick;
+
+ last_rtc_update = 0; /* so the rtc gets updated soon */
+
+ frac_tick = tv->tv_usec % (1000000 / HZ);
+ save_flags(flags);
+ cli();
+ xtime.tv_sec = tv->tv_sec;
+ xtime.tv_usec = tv->tv_usec - frac_tick;
+ set_dec(frac_tick * count_period_den / count_period_num);
+ restore_flags(flags);
+}
+
+
+void
+time_init(void)
+{
+ /* pmac hasn't yet called via_cuda_init() */
+ if ( _machine != _MACH_Pmac )
+ {
+
+ if ( _machine == _MACH_chrp )
+ xtime.tv_sec = chrp_get_rtc_time();
+ else /* assume prep */
+ xtime.tv_sec = prep_get_rtc_time();
+ xtime.tv_usec = 0;
+ /*
+ * mark the rtc/on-chip timer as in sync
+ * so we don't update right away
+ */
+ last_rtc_update = xtime.tv_sec;
+ }
+
+ if ((_get_PVR() >> 16) == 1) {
+ /* 601 processor: dec counts down by 128 every 128ns */
+ decrementer_count = DECREMENTER_COUNT_601;
+ count_period_num = COUNT_PERIOD_NUM_601;
+ count_period_den = COUNT_PERIOD_DEN_601;
+ }
+
+ switch (_machine)
+ {
+ case _MACH_Pmac:
+ pmac_calibrate_decr();
+ set_rtc_time = pmac_set_rtc_time;
+ break;
+ case _MACH_IBM:
+ case _MACH_Motorola:
+ prep_calibrate_decr();
+ set_rtc_time = prep_set_rtc_time;
+ break;
+ case _MACH_chrp:
+ chrp_calibrate_decr();
+ set_rtc_time = chrp_set_rtc_time;
+ break;
+ }
+ set_dec(decrementer_count);
+}
+
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems. On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+void prep_calibrate_decr(void)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+ /* set timer to periodic mode */
+ outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+ /* set the clock to ~100 Hz */
+ outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
+ outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
+
+ if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+ __sti();
+ while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+ restore_flags(flags);
+ free_irq( 0, NULL);
+}
+
+void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
+{
+ int freq, divisor;
+ static unsigned long t1 = 0, t2 = 0;
+
+ if ( !t1 )
+ t1 = get_dec();
+ else if (!t2)
+ {
+ t2 = get_dec();
+ t2 = t1-t2; /* decr's in 1/HZ */
+ t2 = t2*HZ; /* # decrs in 1s - thus in Hz */
+ freq = t2 * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d (%luMHz)\n",
+ freq, divisor,t2>>20);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+ *done_ptr = 1;
+ }
+}
+
+void chrp_calibrate_decr(void)
+{
+ int freq, fp, divisor;
+
+ fp = 16666000; /* hardcoded for now */
+ freq = fp*60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+}
+
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+inline unsigned long mktime(unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
+{
+
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
diff --git a/arch/ppc/kernel/time.h b/arch/ppc/kernel/time.h
new file mode 100644
index 000000000..9ce5921dc
--- /dev/null
+++ b/arch/ppc/kernel/time.h
@@ -0,0 +1,74 @@
+/*
+ * $Id: time.h,v 1.5 1997/08/27 22:06:58 cort Exp $
+ * Common time prototypes and such for all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+#include <linux/mc146818rtc.h>
+
+/* time.c */
+__inline__ unsigned long get_dec(void);
+__inline__ void set_dec(int val);
+void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
+void prep_calibrate_decr(void);
+void pmac_calibrate_decr(void);
+void chrp_calibrate_decr(void);
+extern unsigned decrementer_count;
+extern unsigned count_period_num;
+extern unsigned count_period_den;
+extern unsigned long mktime(unsigned int, unsigned int,unsigned int,
+ unsigned int, unsigned int, unsigned int);
+
+/* pmac/prep/chrp_time.c */
+unsigned long prep_get_rtc_time(void);
+unsigned long pmac_get_rtc_time(void);
+unsigned long chrp_get_rtc_time(void);
+int prep_set_rtc_time(unsigned long nowtime);
+int pmac_set_rtc_time(unsigned long nowtime);
+int chrp_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+
+#define TICK_SIZE tick
+#define FEBRUARY 2
+#define STARTOFTIME 1970
+#define SECDAY 86400L
+#define SECYR (SECDAY * 365)
+#define leapyear(year) ((year) % 4 == 0)
+#define days_in_year(a) (leapyear(a) ? 366 : 365)
+#define days_in_month(a) (month_days[(a) - 1])
+
+static int month_days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+extern void inline to_tm(int tim, struct rtc_time * tm)
+{
+ register int i;
+ register long hms, day;
+
+ day = tim / SECDAY;
+ hms = tim % SECDAY;
+
+ /* Hours, minutes, seconds are easy */
+ tm->tm_hour = hms / 3600;
+ tm->tm_min = (hms % 3600) / 60;
+ tm->tm_sec = (hms % 3600) % 60;
+
+ /* Number of years in days */
+ for (i = STARTOFTIME; day >= days_in_year(i); i++)
+ day -= days_in_year(i);
+ tm->tm_year = i;
+
+ /* Number of months in days left */
+ if (leapyear(tm->tm_year))
+ days_in_month(FEBRUARY) = 29;
+ for (i = 1; day >= days_in_month(i); i++)
+ day -= days_in_month(i);
+ days_in_month(FEBRUARY) = 28;
+ tm->tm_mon = i;
+
+ /* Days are what is left over (+1) from all that. */
+ tm->tm_mday = day + 1;
+}
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 84ce1c5ca..edfcb4d63 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -1,9 +1,15 @@
/*
* linux/arch/ppc/kernel/traps.c
*
- * Copyright (C) 1995 Gary Thomas
- * Adapted for PowerPC by Gary Thomas
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * 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.
+ *
* Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au)
*/
/*
@@ -24,9 +30,21 @@
#include <linux/config.h>
#include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/processor.h>
+
+extern int fix_alignment(struct pt_regs *);
+extern void bad_page_fault(struct pt_regs *, unsigned long);
+
+#ifdef CONFIG_XMON
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern void xmon(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
/*
* Trap & Exception support
@@ -43,40 +61,53 @@ _exception(int signr, struct pt_regs *regs)
if (!user_mode(regs))
{
show_regs(regs);
- print_backtrace(regs->gpr[1]);
- panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
}
force_sig(signr, current);
}
+void
MachineCheckException(struct pt_regs *regs)
{
if ( !user_mode(regs) )
{
+#ifdef CONFIG_XMON
+ if (xmon_fault_handler) {
+ xmon_fault_handler(regs);
+ return;
+ }
+#endif
printk("Machine check in kernel mode.\n");
printk("Caused by (from msr): ");
- printk("regs %08x ",regs);
+ printk("regs %p ",regs);
switch( regs->msr & 0x0000F000)
{
case (1<<12) :
printk("Machine check signal - probably due to mm fault\n"
"with mmu off\n");
- break;
+ break;
case (1<<13) :
printk("Transfer error ack signal\n");
- break;
+ break;
case (1<<14) :
printk("Data parity signal\n");
- break;
+ break;
case (1<<15) :
printk("Address parity signal\n");
- break;
+ break;
default:
printk("Unknown values in msr\n");
}
show_regs(regs);
- print_backtrace(regs->gpr[1]);
- panic("");
+ print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ panic("machine check");
}
_exception(SIGSEGV, regs);
}
@@ -105,33 +136,71 @@ RunModeException(struct pt_regs *regs)
_exception(SIGTRAP, regs);
}
+void
ProgramCheckException(struct pt_regs *regs)
{
- if (current->flags & PF_PTRACED)
+ if (regs->msr & 0x100000) {
+ /* IEEE FP exception */
+ _exception(SIGFPE, regs);
+ } else if (regs->msr & 0x20000) {
+ /* trap exception */
+#ifdef CONFIG_XMON
+ if (xmon_bpt(regs))
+ return;
+#endif
_exception(SIGTRAP, regs);
- else
+ } else {
_exception(SIGILL, regs);
+ }
}
+void
SingleStepException(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+#ifdef CONFIG_XMON
+ if (xmon_sstep(regs))
+ return;
+#endif
_exception(SIGTRAP, regs);
}
+void
AlignmentException(struct pt_regs *regs)
{
+ int fixed;
+
+ if (last_task_used_math == current)
+ giveup_fpu();
+ fixed = fix_alignment(regs);
+ if (fixed == 1) {
+ regs->nip += 4; /* skip over emulated instruction */
+ return;
+ }
+ if (fixed == -EFAULT) {
+ /* fixed == -EFAULT means the operand address was bad */
+ bad_page_fault(regs, regs->dar);
+ return;
+ }
_exception(SIGBUS, regs);
}
+void
+PromException(struct pt_regs *regs, int trap)
+{
+ regs->trap = trap;
+#ifdef CONFIG_XMON
+ xmon(regs);
+#endif
+ printk("Exception %lx in prom at PC: %lx, SR: %lx\n",
+ regs->trap, regs->nip, regs->msr);
+ /* probably should turn up the toes here */
+}
+
+void
trace_syscall(struct pt_regs *regs)
{
- static int count;
- printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+ printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld\n",
current, current->pid, regs->nip, regs->link, regs->gpr[0],
regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
- if (++count == 20)
- {
- count = 0;
- }
}
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index 68b33f047..8b84ce2ae 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -1,38 +1,11 @@
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.S.s:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-.S.o:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
- $(AS) $(ASFLAGS) -o $*.o $*.s
- rm $*.s
-
-HOST_CC = gcc
-
-L_TARGET = lib.o
-L_OBJS = checksum.o cksum_support.o string.o
-
-${L_TARGET}: $(L_OBJS)
- $(LD) -r -o ${L_TARGET} $(L_OBJS)
-
-
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
- $(CPP) -M *.S *.c > .depend
+#
+# Makefile for ppc-specific library files..
+#
-modules:
+.S.o:
+ $(CC) -D__ASSEMBLY__ -c $< -o $*.o
-dummy:
+O_TARGET = lib.o
+O_OBJS = checksum.o string.o strcase.o
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/lib/checksum.S b/arch/ppc/lib/checksum.S
new file mode 100644
index 000000000..6c53d50ff
--- /dev/null
+++ b/arch/ppc/lib/checksum.S
@@ -0,0 +1,192 @@
+/*
+ * This file contains assembly-language implementations
+ * of IP-style 1's complement checksum routines.
+ *
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * 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.
+ *
+ * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/sys.h>
+#include <asm/errno.h>
+#include "../kernel/ppc_asm.tmpl"
+
+_TEXT()
+
+/*
+ * ip_fast_csum(buf, len) -- Optimized for IP header
+ * len is in words and is always >= 5.
+ */
+_GLOBAL(ip_fast_csum)
+ lwz r0,0(r3)
+ lwzu r5,4(r3)
+ addi r4,r4,-2
+ addc r0,r0,r5
+ mtctr r4
+1: lwzu r4,4(r3)
+ adde r0,r0,r4
+ bdnz 1b
+ addze r0,r0 /* add in final carry */
+ rlwinm r3,r0,16,0,31 /* fold two halves together */
+ add r3,r0,r3
+ not r3,r3
+ srwi r3,r3,16
+ blr
+
+/*
+ * Compute checksum of TCP or UDP pseudo-header:
+ * csum_tcpudp_magic(saddr, daddr, len, proto, sum)
+ */
+_GLOBAL(csum_tcpudp_magic)
+ rlwimi r5,r6,16,0,15 /* put proto in upper half of len */
+ addc r0,r3,r4 /* add 4 32-bit words together */
+ adde r0,r0,r5
+ adde r0,r0,r7
+ addze r0,r0 /* add in final carry */
+ rlwinm r3,r0,16,0,31 /* fold two halves together */
+ add r3,r0,r3
+ not r3,r3
+ srwi r3,r3,16
+ blr
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * csum_partial(buff, len, sum)
+ */
+_GLOBAL(csum_partial)
+ addic r0,r5,0
+ subi r3,r3,4
+ srwi. r6,r4,2
+ beq 3f /* if we're doing < 4 bytes */
+ andi. r5,r3,2 /* Align buffer to longword boundary */
+ beq+ 1f
+ lhz r5,4(r3) /* do 2 bytes to get aligned */
+ addi r3,r3,2
+ subi r4,r4,2
+ addc r0,r0,r5
+ srwi. r6,r4,2 /* # words to do */
+ beq 3f
+1: mtctr r6
+2: lwzu r5,4(r3) /* the bdnz has zero overhead, so it should */
+ adde r0,r0,r5 /* be unnecessary to unroll this loop */
+ bdnz 2b
+ andi. r4,r4,3
+3: cmpi 0,r4,2
+ blt+ 4f
+ lhz r5,4(r3)
+ addi r3,r3,2
+ subi r4,r4,2
+ adde r0,r0,r5
+4: cmpi 0,r4,1
+ bne+ 5f
+ lbz r5,4(r3)
+ slwi r5,r5,8 /* Upper byte of word */
+ adde r0,r0,r5
+5: addze r3,r0 /* add in final carry */
+ blr
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively, and (for an error on
+ * src) zeroes the rest of dst.
+ *
+ * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
+ */
+_GLOBAL(csum_partial_copy_generic)
+ addic r0,r6,0
+ subi r3,r3,4
+ subi r4,r4,4
+ srwi. r6,r5,2
+ beq 3f /* if we're doing < 4 bytes */
+ andi. r9,r4,2 /* Align dst to longword boundary */
+ beq+ 1f
+81: lhz r6,4(r3) /* do 2 bytes to get aligned */
+ addi r3,r3,2
+ subi r5,r5,2
+91: sth r6,4(r4)
+ addi r4,r4,2
+ addc r0,r0,r6
+ srwi. r6,r5,2 /* # words to do */
+ beq 3f
+1: mtctr r6
+82: lwzu r6,4(r3) /* the bdnz has zero overhead, so it should */
+92: stwu r6,4(r4) /* be unnecessary to unroll this loop */
+ adde r0,r0,r6
+ bdnz 82b
+ andi. r5,r5,3
+3: cmpi 0,r5,2
+ blt+ 4f
+83: lhz r6,4(r3)
+ addi r3,r3,2
+ subi r5,r5,2
+93: sth r6,4(r4)
+ addi r4,r4,2
+ adde r0,r0,r6
+4: cmpi 0,r5,1
+ bne+ 5f
+84: lbz r6,4(r3)
+94: stb r6,4(r4)
+ slwi r6,r6,8 /* Upper byte of word */
+ adde r0,r0,r6
+5: addze r3,r0 /* add in final carry */
+ blr
+
+.section .fixup,"ax"
+
+src_error_1:
+ li r6,0
+ subi r5,r5,2
+95: sth r6,4(r4)
+ addi r4,r4,2
+ srwi. r6,r5,2
+ beq 3f
+ mtctr r6
+src_error_2:
+ li r6,0
+96: stwu r6,4(r4)
+ bdnz 96b
+3: andi. r5,r5,3
+ beq src_error
+src_error_3:
+ li r6,0
+ mtctr r5
+ addi r4,r4,3
+97: stbu r6,1(r4)
+ bdnz 97b
+src_error:
+ cmpi 0,r7,0
+ beq 1f
+ li r6,-EFAULT
+ stw r6,0(r7)
+1: addze r3,r0
+ blr
+
+dst_error:
+ cmpi 0,r8,0
+ beq 1f
+ li r6,-EFAULT
+ stw r6,0(r8)
+1: addze r3,r0
+ blr
+
+.section __ex_table,"a"
+ .long 81b,src_error_1
+ .long 91b,dst_error
+ .long 82b,src_error_2
+ .long 92b,dst_error
+ .long 83b,src_error_3
+ .long 93b,dst_error
+ .long 84b,src_error_3
+ .long 94b,dst_error
+ .long 95b,dst_error
+ .long 96b,dst_error
+ .long 97b,dst_error
diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c
new file mode 100644
index 000000000..a9e40bce9
--- /dev/null
+++ b/arch/ppc/lib/strcase.c
@@ -0,0 +1,12 @@
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ int c1, c2;
+
+ do {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ } while (c1 == c2 && c1 != 0);
+ return c1 - c2;
+}
diff --git a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S
new file mode 100644
index 000000000..96378dec1
--- /dev/null
+++ b/arch/ppc/lib/string.S
@@ -0,0 +1,345 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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 "../kernel/ppc_asm.tmpl"
+#include <asm/errno.h>
+
+ .globl strcpy
+strcpy:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strncpy
+strncpy:
+ cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ blr
+
+ .globl strcat
+strcat:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r5)
+ cmpwi 0,r0,0
+ bne 1b
+ addi r5,r5,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strcmp
+strcmp:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r5)
+ cmpwi 1,r3,0
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ beqlr 1
+ beq 1b
+ blr
+
+ .globl strlen
+strlen:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ blr
+
+ .globl memset
+memset:
+ rlwimi r4,r4,8,16,23
+ rlwimi r4,r4,16,0,15
+ addi r6,r3,-4
+ cmplwi 0,r5,4
+ blt 7f
+ stwu r4,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r5,r0,r5
+ subf r6,r0,r6
+ rlwinm r0,r5,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r4,4(r6)
+ bdnz 1b
+6: andi. r5,r5,3
+7: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r6,3
+8: stbu r4,1(r6)
+ bdnz 8b
+ blr
+
+ .globl bcopy
+bcopy:
+ mr r6,r3
+ mr r3,r4
+ mr r4,r6
+ b memcpy
+
+ .globl memmove
+memmove:
+ cmplw 0,r3,r4
+ bgt backwards_memcpy
+ /* fall through */
+
+ .globl memcpy
+memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ 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)
+ lwzu r8,8(r4)
+ stw r7,4(r6)
+ stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,4(r4)
+ addi r5,r5,-4
+ stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+ stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+ stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl backwards_memcpy
+backwards_memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ add r6,r3,r5
+ add r4,r4,r5
+ beq 2f
+ andi. r0,r6,3
+ mtctr r7
+ bne 5f
+1: lwz r7,-4(r4)
+ lwzu r8,-8(r4)
+ stw r7,-4(r6)
+ stwu r8,-8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,-4(r4)
+ subi r5,r5,4
+ stwu r0,-4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+4: lbzu r0,-1(r4)
+ stbu r0,-1(r6)
+ bdnz 4b
+ blr
+5: mtctr r0
+6: lbzu r7,-1(r4)
+ stbu r7,-1(r6)
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl memcmp
+memcmp:
+ cmpwi 0,r5,0
+ ble- 2f
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r6)
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ bdnzt 2,1b
+ blr
+2: li r3,0
+ blr
+
+ .global memchr
+memchr:
+ cmpwi 0,r5,0
+ ble- 2f
+ mtctr r5
+ addi r3,r3,-1
+1: lbzu r0,1(r3)
+ cmpw 0,r0,r4
+ bdnzf 2,1b
+ beqlr
+2: li r3,0
+ blr
+
+ .globl __copy_tofrom_user
+__copy_tofrom_user:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = 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 */
+ mtctr r7
+ bne 5f
+1: lwz r7,4(r4)
+11: lwzu r8,8(r4)
+12: stw r7,4(r6)
+13: stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+14: lwzu r0,4(r4)
+ addi r5,r5,-4
+15: stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+16: stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+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
+ beq 2b
+ mtctr r7
+ b 1b
+99: li r3,-EFAULT
+ 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 4b,99b
+ .long 16b,99b
+ .long 6b,99b
+ .long 17b,99b
+.text
+
+ .globl __clear_user
+__clear_user:
+ addi r6,r3,-4
+ li r3,0
+ li r5,0
+ cmplwi 0,r4,4
+ blt 7f
+11: stwu r5,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r4,r0,r4
+ subf r6,r0,r6
+ rlwinm r0,r4,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r5,4(r6)
+ bdnz 1b
+6: andi. r4,r4,3
+7: cmpwi 0,r4,0
+ beqlr
+ mtctr r4
+ addi r6,r6,3
+8: stbu r5,1(r6)
+ bdnz 8b
+ blr
+99: li r3,-EFAULT
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 11b,99b
+ .long 1b,99b
+ .long 8b,99b
+.text
+
+ .globl __strncpy_from_user
+__strncpy_from_user:
+ addi r6,r3,-1
+ addi r4,r4,-1
+ cmpwi 0,r5,0
+ beq 2f
+ mtctr r5
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ beq 3f
+2: addi r6,r6,1
+3: subf r3,r3,r6
+ blr
+99: li r3,-EFAULT
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 1b,99b
+.text
+
+ .globl strlen_user
+strlen_user:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ addi r3,r3,1
+ blr
+99: li r3,0
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 1b,99b
diff --git a/arch/ppc/mkdiff b/arch/ppc/mkdiff
new file mode 100644
index 000000000..304eb9428
--- /dev/null
+++ b/arch/ppc/mkdiff
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+N=`basename $PWD`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+echo Diff of: $N against $N.ORIG '->' $N-$date-ppc.patch
+diff -uNr -X $N/arch/ppc/ignore $N.ORIG $N > dist/$N-$date-ppc.patch
diff --git a/arch/ppc/mkdist b/arch/ppc/mkdist
new file mode 100644
index 000000000..80408b741
--- /dev/null
+++ b/arch/ppc/mkdist
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
+date=`date +'%y%m%d'`
+
+echo zImage-$V.$P.$S-$date
+echo System.map-$V.$P.$S-$date
+
+rcp zImage charon:ppc/dist/kernel-images/zImage-$V.$P.$S-$date
+rcp System.map charon:ppc/dist/kernel-images/System.map-$V.$P.$S-$date
+
diff --git a/arch/ppc/mktar b/arch/ppc/mktar
new file mode 100644
index 000000000..a50112ff6
--- /dev/null
+++ b/arch/ppc/mktar
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+tar -vzcf ppclinux-$V.$P.$S-$date.tar.gz -X linux/arch/ppc/ignore linux
diff --git a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile
index 13aeab6ca..2b07c7227 100644
--- a/arch/ppc/mm/Makefile
+++ b/arch/ppc/mm/Makefile
@@ -7,28 +7,7 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.s.o:
- $(AS) -o $*.o $<
-.c.s:
- $(CC) $(CFLAGS) -S $<
+O_TARGET := mm.o
+O_OBJS = fault.o init.o extable.o
-OBJS = fault.o init.o extable.o
-
-mm.o: $(OBJS)
- $(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-
-fastdep:
- $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff --git a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c
new file mode 100644
index 000000000..77e3171bc
--- /dev/null
+++ b/arch/ppc/mm/extable.c
@@ -0,0 +1,65 @@
+/*
+ * linux/arch/ppc/mm/extable.c
+ *
+ * from linux/arch/i386/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ const struct exception_table_entry *mid;
+ for ( mid = first; mid < last; mid++)
+ {
+ if ( mid->insn == value )
+ return mid->fixup;
+ }
+ return 0;
+#if 0
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ long diff;
+ mid = (last - first) / 2 + first;
+ diff = mid->insn - value;
+ if (diff == 0)
+ return mid->fixup;
+ else if (diff < 0)
+ first = mid+1;
+ else
+ last = mid-1;
+ }
+#endif
+ return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+ unsigned long ret;
+
+#if 1 /*ndef CONFIG_MODULES*/
+ /* There is only the kernel to search. */
+ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+ if (ret) return ret;
+#else
+ /* The kernel is the last "module" -- no need to treat it special. */
+ struct module *mp;
+ for (mp = module_list; mp != NULL; mp = mp->next) {
+ if (mp->ex_table_start == NULL)
+ continue;
+ ret = search_one_table(mp->ex_table_start,
+ mp->ex_table_end - 1, addr);
+ if (ret) return ret;
+ }
+#endif
+
+ return 0;
+}
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index fea722780..67b94d809 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -1,8 +1,12 @@
/*
* arch/ppc/mm/fault.c
*
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Ported to PPC by Gary Thomas
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/mm/fault.c"
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ *
* Modified by Cort Dougan and Paul Mackerras.
*
* This program is free software; you can redistribute it and/or
@@ -26,40 +30,42 @@
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/mmu.h>
#include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *);
extern void (*xmon_fault_handler)(void);
-#endif
-
-/* the linux norm for the function name is show_regs() so
- make it call dump_regs() on the mac -- Cort */
-#ifdef CONFIG_PMAC
-#define show_regs dump_regs
+extern int xmon_dabr_match(struct pt_regs *);
+int xmon_kernel_faults;
#endif
extern void die_if_kernel(char *, struct pt_regs *, long);
void bad_page_fault(struct pt_regs *, unsigned long);
void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void print_pte(struct _PTE);
-void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
+/*
+ * The error_code parameter is DSISR for a data fault, SRR1 for
+ * an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
{
- struct task_struct *tsk = current;
- extern unsigned _end[];
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- /*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
- current->comm,current->pid,address,regs->nip,regs,error_code);*/
-#ifdef CONFIG_PMAC
+
+#ifdef CONFIG_XMON
if (xmon_fault_handler && regs->trap == 0x300) {
xmon_fault_handler();
return;
}
+ if (error_code & 0x00400000) {
+ /* DABR match */
+ if (xmon_dabr_match(regs))
+ return;
+ }
#endif
if (in_interrupt()) {
static int complained;
@@ -68,14 +74,18 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long er
printk("page fault in interrupt handler, addr=%lx\n",
address);
show_regs(regs);
+#ifdef CONFIG_XMON
+ if (xmon_kernel_faults)
+ xmon(regs);
+#endif
}
}
- if (current == NULL)
- goto bad_area;
-
-do_page:
+ if (current == NULL) {
+ bad_page_fault(regs, address);
+ return;
+ }
down(&mm->mmap_sem);
- vma = find_vma(tsk->mm, address);
+ vma = find_vma(mm, address);
if (!vma)
goto bad_area;
if (vma->vm_start <= address)
@@ -84,7 +94,7 @@ do_page:
goto bad_area;
if (expand_stack(vma, address))
goto bad_area;
-
+
good_area:
if (error_code & 0xb5700000)
/* an error such as lwarx to I/O controller space,
@@ -98,67 +108,45 @@ good_area:
/* a read */
} else {
/* protection fault */
- if ( error_code & 0x08000000 )
+ if (error_code & 0x08000000)
goto bad_area;
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
handle_mm_fault(current, vma, address, error_code & 0x02000000);
- up(&mm->mmap_sem);
- /*printk("do_page_fault() return %s/%d addr %x msr %x\n",
- current->comm,current->pid,address,regs->msr);*/
- /* not needed since flush_page_to_ram() works */
-#if 0
- flush_page(address);
-#endif
+ up(&mm->mmap_sem);
return;
-
+
bad_area:
- up(&current->mm->mmap_sem);
+ up(&mm->mmap_sem);
bad_page_fault(regs, address);
}
-
void
bad_page_fault(struct pt_regs *regs, unsigned long address)
{
- extern unsigned int probingmem;
- struct task_struct *tsk = current;
unsigned long fixup;
-
+
+ if (user_mode(regs)) {
+ force_sig(SIGSEGV, current);
+ return;
+ }
/* Are we prepared to handle this fault? */
if ((fixup = search_exception_table(regs->nip)) != 0) {
- if ( user_mode(regs) )
- printk("Exception from user mode\n");
-#if 0
- printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
-#endif
regs->nip = fixup;
return;
}
- if ( user_mode(regs) )
- {
- force_sig(SIGSEGV, tsk);
- return;
- }
-
-bad_kernel_access:
- /* make sure it's not a bootup probe test */
- if ( probingmem )
- {
- probingmem = 0;
- return;
- }
/* kernel has accessed a bad area */
show_regs(regs);
- print_backtrace( regs->gpr[1] );
-#ifdef CONFIG_PMAC
- xmon(regs);
+ print_backtrace( (unsigned long *)regs->gpr[1] );
+#ifdef CONFIG_XMON
+ if (xmon_kernel_faults)
+ xmon(regs);
#endif
- panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
- regs->nip,address,tsk->comm,tsk->pid);
+ panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
+ regs->nip,regs->link,address,current->comm,current->pid);
}
unsigned long va_to_phys(unsigned long address)
@@ -189,6 +177,10 @@ unsigned long va_to_phys(unsigned long address)
return (0);
}
+#if 0
+/*
+ * Misc debugging functions. Please leave them here. -- Cort
+ */
void print_pte(struct _PTE p)
{
printk(
@@ -210,7 +202,8 @@ unsigned long htab_phys_to_va(unsigned long address)
for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
{
if ( ptr->rpn == (address>>12) )
- printk("phys %08X -> va ???\n",
+ printk("phys %08lX -> va ???\n",
address);
}
}
+#endif
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index d46975996..8503401b4 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -31,54 +31,58 @@
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/stddef.h>
-#ifdef CONFIG_PMAC
#include <asm/prom.h>
-#endif
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
-#ifdef CONFIG_PREP
#include <asm/residual.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h> /* for initrd_* */
#endif
+int prom_trashed;
int next_mmu_context;
+unsigned long _SDR1;
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
+unsigned long *end_of_DRAM;
+int mem_init_done;
extern pgd_t swapper_pg_dir[];
extern char _start[], _end[];
extern char etext[], _stext[];
-/* References to section boundaries */
extern char __init_begin, __init_end;
+extern RESIDUAL res;
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void show_net_buffers(void);
-extern unsigned long *find_end_of_memory(void);
+/* Hardwired MMU segments */
+#if defined(CONFIG_PREP) || defined(CONFIG_PMAC)
+#define MMU_SEGMENT_1 0x80000000
+#define MMU_SEGMENT_2 0xc0000000
+#endif /* CONFIG_PREP || CONFIG_PMAC */
+#ifdef CONFIG_CHRP
+#define MMU_SEGMENT_1 0xf0000000 /* LongTrail */
+#define MMU_SEGMENT_2 0xc0000000
+#endif /* CONFIG_CHRP */
-#undef MAP_RAM_WITH_SEGREGS 1
-#ifdef CONFIG_PMAC
void *find_mem_piece(unsigned, unsigned);
static void mapin_ram(void);
static void inherit_prom_translations(void);
-#endif
-#ifdef CONFIG_PREP
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
-int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);
-#endif
-
static void hash_init(void);
static void *MMU_get_page(void);
-void map_page(struct thread_struct *, unsigned long va,
+void map_page(struct task_struct *, unsigned long va,
unsigned long pa, int flags);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+extern unsigned long *find_end_of_memory(void);
-PTE *Hash, *Hash_end;
-unsigned long Hash_size, Hash_mask;
-unsigned long *end_of_DRAM;
-int mem_init_done;
+/*
+ * this tells the prep system to map all of ram with the segregs
+ * instead of the bats. I'd like to get this to apply to the
+ * pmac as well then have everything use the bats -- Cort
+ */
+#undef MAP_RAM_WITH_SEGREGS 1
-#ifdef CONFIG_PREP
-#ifdef HASHSTATS
-extern unsigned long evicts;
-#endif /* HASHSTATS */
/*
* these are used to setup the initial page tables
* They can waste up to an entire page since the
@@ -88,8 +92,6 @@ extern unsigned long evicts;
unsigned int probingmem = 0;
unsigned int mmu_pages_count = 0;
char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
-unsigned long _TotalMemory;
-#endif /* CONFIG_PREP */
/*
* BAD_PAGE is the page that is used for page faults when linux
@@ -120,7 +122,6 @@ pte_t __bad_page(void)
return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
}
-#ifdef CONFIG_PMAC
#define MAX_MEM_REGIONS 32
phandle memory_pkg;
@@ -128,7 +129,6 @@ struct mem_pieces {
int n_regions;
struct reg_property regions[MAX_MEM_REGIONS];
};
-
struct mem_pieces phys_mem;
struct mem_pieces phys_avail;
struct mem_pieces prom_mem;
@@ -138,7 +138,6 @@ static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
static void print_mem_pieces(struct mem_pieces *);
unsigned long avail_start;
-int prom_trashed;
/*
* Read in a property describing some pieces of memory.
@@ -272,10 +271,10 @@ find_mem_piece(unsigned size, unsigned align)
* Our text, data, bss use something over 1MB, starting at 0.
* Open Firmware may be using 1MB at the 4MB point.
*/
-unsigned long *find_end_of_memory(void)
+unsigned long *pmac_find_end_of_memory(void)
{
unsigned long a, total;
- unsigned long h, kstart, ksize;
+ unsigned long kstart, ksize;
extern char _stext[], _end[];
int i;
@@ -325,20 +324,6 @@ unsigned long *find_end_of_memory(void)
remove_mem_piece(&phys_avail, kstart, ksize, 0);
remove_mem_piece(&prom_mem, kstart, ksize, 0);
- /*
- * Allow 64k of hash table for every 16MB of memory,
- * up to a maximum of 2MB.
- */
- for (h = 64<<10; h < total / 256 && h < 2<<20; h *= 2)
- ;
- Hash_size = h;
- Hash_mask = (h >> 6) - 1;
-
- /* Find some memory for the hash table. */
- Hash = find_mem_piece(Hash_size, Hash_size);
- printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
- total >> 20, Hash_size >> 10, Hash);
-
return __va(total);
}
@@ -353,6 +338,9 @@ unsigned long find_available_memory(void)
int i;
unsigned long a, free;
unsigned long start, end;
+
+ if ( _machine != _MACH_Pmac )
+ return 0;
free = 0;
for (i = 0; i < phys_avail.n_regions - 1; ++i) {
@@ -366,7 +354,6 @@ unsigned long find_available_memory(void)
avail_start = (unsigned long) __va(a);
return avail_start;
}
-#endif /* CONFIG_PMAC */
void show_mem(void)
{
@@ -399,14 +386,21 @@ void show_mem(void)
"Ctx", "Ctx<<4", "Last Sys", "pc", "task");
for_each_task(p)
{
- printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+ printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ",
p->comm,p->pid,
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,
- p);
+ (ulong)p);
if ( p == current )
- printk(" current");
+ printk("current");
+ if ( p == last_task_used_math )
+ {
+ if ( p == current )
+ printk(",");
+ printk("last math");
+ }
+
printk("\n");
}
}
@@ -434,76 +428,68 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
void mem_init(unsigned long start_mem, unsigned long end_mem)
{
unsigned long addr;
-#ifdef CONFIG_PMAC
int i;
- unsigned long lim;
-#endif
+ unsigned long a, lim;
int codepages = 0;
int datapages = 0;
int initpages = 0;
end_mem &= PAGE_MASK;
high_memory = (void *) end_mem;
- num_physpages = max_mapnr = MAP_NR(high_memory);
-
- /* clear the zero-page */
- memset(empty_zero_page, 0, PAGE_SIZE);
-
+ max_mapnr = MAP_NR(high_memory);
+ num_physpages = max_mapnr; /* RAM is assumed contiguous */
+
/* mark usable pages in the mem_map[] */
start_mem = PAGE_ALIGN(start_mem);
-
-#ifdef CONFIG_PMAC
- remove_mem_piece(&phys_avail, __pa(avail_start),
- start_mem - avail_start, 1);
-
- for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
- set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-
- for (i = 0; i < phys_avail.n_regions; ++i) {
- a = (unsigned long) __va(phys_avail.regions[i].address);
- lim = a + phys_avail.regions[i].size;
- a = PAGE_ALIGN(a);
- for (; a < lim; a += PAGE_SIZE) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
- mem_map[MAP_NR(a)].count = 1;
- free_page(a);
+
+ if ( _machine == _MACH_Pmac )
+ {
+ remove_mem_piece(&phys_avail, __pa(avail_start),
+ start_mem - avail_start, 1);
+
+ for (addr = KERNELBASE ; addr < end_mem; addr += PAGE_SIZE)
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+
+ for (i = 0; i < phys_avail.n_regions; ++i) {
+ a = (unsigned long) __va(phys_avail.regions[i].address);
+ lim = a + phys_avail.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
}
- }
- phys_avail.n_regions = 0;
-
- /* free the prom's memory */
- for (i = 0; i < prom_mem.n_regions; ++i) {
- a = (unsigned long) __va(prom_mem.regions[i].address);
- lim = a + prom_mem.regions[i].size;
- a = PAGE_ALIGN(a);
- for (; a < lim; a += PAGE_SIZE) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
- mem_map[MAP_NR(a)].count = 1;
- free_page(a);
+ phys_avail.n_regions = 0;
+
+ /* free the prom's memory */
+ for (i = 0; i < prom_mem.n_regions; ++i) {
+ a = (unsigned long) __va(prom_mem.regions[i].address);
+ lim = a + prom_mem.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE)
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
}
+ prom_trashed = 1;
}
- prom_trashed = 1;
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_PREP
- /* mark mem used by kernel as reserved, mark other unreserved */
- for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+ else /* prep */
{
- /* skip hash table gap */
- if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
- continue;
- if ( addr < (ulong) /*Hash_end*/ start_mem )
- set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
- else
- clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ /* mark mem used by kernel as reserved, mark other unreserved */
+ for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+ {
+ /* skip hash table gap */
+ if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+ continue;
+ if ( addr < (ulong) /*Hash_end*/ start_mem )
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ else
+ clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ }
}
for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
- if(PageReserved(mem_map + MAP_NR(addr))) {
+ if (PageReserved(mem_map + MAP_NR(addr))) {
if (addr < (ulong) etext)
codepages++;
- /*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
- initpages++;*/
+ else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+ initpages++;
else if (addr < (ulong) start_mem)
datapages++;
continue;
@@ -515,9 +501,8 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
#endif /* CONFIG_BLK_DEV_INITRD */
free_page(addr);
}
-
-#endif /* CONFIG_PREP */
- printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+
+ printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
(unsigned long) nr_free_pages << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
@@ -534,7 +519,6 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
*/
void free_initmem(void)
{
- unsigned long addr;
unsigned long a;
unsigned long num_freed_pages = 0;
@@ -548,16 +532,14 @@ void free_initmem(void)
num_freed_pages++;
}
-#if 0
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- num_freed_pages++;
- mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
- mem_map[MAP_NR(addr)].count = 1;
- free_page(addr);
+ a = (unsigned long)(&__init_begin);
+ for (; a < (unsigned long)(&__init_end); a += PAGE_SIZE) {
+ mem_map[MAP_NR(a)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(a)].count, 1);
+ free_page(a);
}
-#endif
- printk ("Freeing unused kernel memory: %dk freed\n",
+
+ printk ("Freeing unused kernel memory: %ldk freed\n",
(num_freed_pages * PAGE_SIZE) >> 10);
}
@@ -576,29 +558,23 @@ void si_meminfo(struct sysinfo *val)
val->totalram++;
if (!atomic_read(&mem_map[i].count))
continue;
- val->sharedram += atomic_read(&mem_map[i].count)-1;
+ val->sharedram += atomic_read(&mem_map[i].count) - 1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
return;
}
-/* Kernel MMU setup & lowest level hardware support */
-
-unsigned long _SDR1; /* Hardware SDR1 image */
-
-#ifdef CONFIG_PREP
-
BAT BAT0 =
{
{
- 0x80000000>>17, /* bepi */
+ MMU_SEGMENT_1>>17, /* bepi */
BL_256M, /* bl */
1, /* vs -- supervisor mode valid */
1, /* vp -- user mode valid */
},
{
- 0x80000000>>17, /* brpn */
+ MMU_SEGMENT_1>>17, /* brpn */
1, /* write-through */
1, /* cache-inhibited */
0, /* memory coherence */
@@ -609,13 +585,13 @@ BAT BAT0 =
BAT BAT1 =
{
{
- 0xC0000000>>17, /* bepi */
+ MMU_SEGMENT_2>>17, /* bepi */
BL_256M, /* bl */
1, /* vs */
1, /* vp */
},
{
- 0xC0000000>>17, /* brpn */
+ MMU_SEGMENT_2>>17, /* brpn */
1, /* w */
1, /* i (cache disabled) */
0, /* m */
@@ -635,7 +611,11 @@ BAT BAT2 =
0x00000000>>17, /* brpn */
0, /* w */
0, /* i */
+#ifdef __SMP__
1, /* m */
+#else
+ 0, /* m */
+#endif
0, /* g */
BPP_RW /* pp */
}
@@ -676,13 +656,13 @@ P601_BAT BAT0_601 =
P601_BAT BAT1_601 =
{
{
- 0xC0000000>>17, /* bepi */
+ MMU_SEGMENT_2>>17, /* bepi */
1,1,0, /* wim */
1, 0, /* vs, vp */
BPP_RW, /* pp */
},
{
- 0xC0000000>>17, /* brpn */
+ MMU_SEGMENT_2>>17, /* brpn */
1, /* v */
BL_8M, /* bl */
}
@@ -724,69 +704,24 @@ P601_BAT BAT3_601 =
* this will likely stay seperate from the pmac.
* -- Cort
*/
-unsigned long *find_end_of_memory(void)
+unsigned long *prep_find_end_of_memory(void)
{
- extern RESIDUAL res;
- extern unsigned long resptr;
- int i, p;
- unsigned long h;
-
- /* copy residual data */
- if ( resptr )
- memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
- else
- /* clearing bss probably clears this but... */
- memset( &res, sizeof(RESIDUAL), 0 );
- _TotalMemory = res.TotalMemory;
+ int i;
- /* this really has nothing to do with the mmu_init() but is
- necessary for early setup -- Cort */
- if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
- {
- _machine = _MACH_IBM;
- }
- else
- _machine = _MACH_Motorola;
-
- /* setup the hash table */
- if (_TotalMemory == 0 )
+ if (res.TotalMemory == 0 )
{
/*
* I need a way to probe the amount of memory if the residual
* data doesn't contain it. -- Cort
*/
printk("Ramsize from residual data was 0 -- Probing for value\n");
- _TotalMemory = 0x03000000;
- printk("Ramsize default to be %dM\n", _TotalMemory>>20);
+ res.TotalMemory = 0x03000000;
+ printk("Ramsize default to be %ldM\n", res.TotalMemory>>20);
}
-
-#if 0
- /* linux has trouble with > 64M ram -- Cort */
- if ( _TotalMemory > 0x04000000 /* 64M */ )
- {
- printk("Only using first 64M of ram.\n");
- _TotalMemory = 0x04000000;
- }
-#endif
-
- /* setup the bat2 mapping to cover physical ram */
- BAT2.batu.bl = 0x1; /* 256k mapping */
- for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
- h *= 2 )
- BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
- /*
- * Allow 64k of hash table for every 16MB of memory,
- * up to a maximum of 2MB.
- */
- for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
- ;
- Hash_size = h;
- Hash_mask = (h >> 6) - 1;
-
- /* align htab on a Hash_size boundry above _end[] */
- Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
- memset(Hash, Hash_size, 0 );
+ /* NOTE: everything below here is moving to mapin_ram() */
+
+
/*
* if this is a 601, we can only map sizes of 8M with the BAT's
* so we have to map what we can't map with the bats with the segregs
@@ -799,11 +734,11 @@ unsigned long *find_end_of_memory(void)
if ( _get_PVR() == 1 )
{
/* map in rest of ram with seg regs */
- if ( _TotalMemory > 0x01000000 /* 16M */)
+ if ( res.TotalMemory > 0x01000000 /* 16M */)
{
for (i = KERNELBASE+0x01000000;
- i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
- map_page(&init_task.tss, i, __pa(i),
+ i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE)
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
}
}
@@ -815,25 +750,21 @@ unsigned long *find_end_of_memory(void)
memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
memset(&BAT3_601, sizeof(BAT2), 0);
/* map all of ram for kernel with segregs */
- for (i = KERNELBASE; i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
+ for (i = KERNELBASE; i < KERNELBASE+res.TotalMemory; i += PAGE_SIZE)
{
if ( i < (unsigned long)etext )
- map_page(&init_task.tss, i, __pa(i),
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
else
- map_page(&init_task.tss, i, __pa(i),
+ map_page(&init_task, i, __pa(i),
_PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
}
#endif /* MAP_RAM_WITH_SEGREGS */
- printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
- _TotalMemory >> 20, Hash_size >> 10, Hash);
- return ((unsigned long *)_TotalMemory);
+ return (__va(res.TotalMemory));
}
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_PMAC
/*
* Map in all of physical memory starting at KERNELBASE.
*/
@@ -847,17 +778,39 @@ static void mapin_ram()
int i;
unsigned long v, p, s, f;
- v = KERNELBASE;
- for (i = 0; i < phys_mem.n_regions; ++i) {
- p = phys_mem.regions[i].address;
- for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
- f = _PAGE_PRESENT | _PAGE_ACCESSED;
- if ((char *) v < _stext || (char *) v >= etext)
- f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
- map_page(&init_task.tss, v, p, f);
- v += PAGE_SIZE;
- p += PAGE_SIZE;
- }
+ if ( _machine == _MACH_Pmac )
+ {
+ v = KERNELBASE;
+ for (i = 0; i < phys_mem.n_regions; ++i) {
+ p = phys_mem.regions[i].address;
+ for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+ f = _PAGE_PRESENT | _PAGE_ACCESSED;
+ if ((char *) v < _stext || (char *) v >= etext)
+ f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+ else
+ /* On the powerpc, no user access forces R/W kernel access */
+ f |= _PAGE_USER;
+ map_page(&init_task, v, p, f);
+ v += PAGE_SIZE;
+ p += PAGE_SIZE;
+ }
+ }
+ }
+ else /* prep */
+ {
+ /* setup the bat2 mapping to cover physical ram */
+ BAT2.batu.bl = 0x1; /* 256k mapping */
+ for ( f = 256*1024 /* 256k */ ;
+ (f <= res.TotalMemory) && (f <= 256*1024*1024);
+ f *= 2 )
+ BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
+ /*
+ * let ibm get to the device mem from user mode since
+ * the X for them needs it right now -- Cort
+ */
+ if ( _machine == _MACH_IBM )
+ BAT0.batu.vp = BAT1.batu.vp = 1;
+
}
}
@@ -889,7 +842,7 @@ static void inherit_prom_translations()
for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
/* ignore stuff mapped down low */
- if (tp->virt < 0x10000000)
+ if (tp->virt < 0x10000000 && tp->phys < 0x10000000)
continue;
/* map PPC mmu flags to linux mm flags */
f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
@@ -900,13 +853,12 @@ static void inherit_prom_translations()
p = tp->phys;
n = tp->size;
for (; n != 0; n -= PAGE_SIZE) {
- map_page(&init_task.tss, v, p, f);
+ map_page(&init_task, v, p, f);
v += PAGE_SIZE;
p += PAGE_SIZE;
}
}
}
-#endif
/*
* Initialize the hash table and patch the instructions in head.S.
@@ -914,10 +866,29 @@ static void inherit_prom_translations()
static void hash_init(void)
{
int Hash_bits;
+ unsigned long h;
extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
hash_page_patch_C[];
+ /*
+ * Allow 64k of hash table for every 16MB of memory,
+ * up to a maximum of 2MB.
+ */
+ for (h = 64<<10; h < (ulong)__pa(end_of_DRAM) / 256 && h < 2<<20; h *= 2)
+ ;
+ Hash_size = h;
+ Hash_mask = (h >> 6) - 1;
+
+ /* Find some memory for the hash table. */
+ if ( is_prep )
+ /* align htab on a Hash_size boundry above _end[] */
+ Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
+ else /* pmac */
+ Hash = find_mem_piece(Hash_size, Hash_size);
+
+ printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+ __pa(end_of_DRAM) >> 20, Hash_size >> 10, Hash);
memset(Hash, 0, Hash_size);
Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
@@ -943,8 +914,8 @@ static void hash_init(void)
* out from the data cache and invalidated in the instruction
* cache, on those machines with split caches.
*/
- store_cache_range((unsigned long) hash_page_patch_A,
- (unsigned long) (hash_page_patch_C + 1));
+ flush_icache_range((unsigned long) hash_page_patch_A,
+ (unsigned long) (hash_page_patch_C + 1));
}
@@ -958,71 +929,93 @@ static void hash_init(void)
void
MMU_init(void)
{
- end_of_DRAM = find_end_of_memory();
+ if ( _machine == _MACH_Pmac )
+ end_of_DRAM = pmac_find_end_of_memory();
+ else /* prep and chrp */
+ end_of_DRAM = prep_find_end_of_memory();
+
hash_init();
_SDR1 = __pa(Hash) | (Hash_mask >> 10);
-#ifdef CONFIG_PMAC
- /* Force initial page tables */
- /* this done by INIT_TSS in processor.h on prep -- Cort */
- init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
/* Map in all of RAM starting at KERNELBASE */
mapin_ram();
- /* Copy mappings from the prom */
- inherit_prom_translations();
-#endif /* CONFIG_PMAC */
+ if ( _machine == _MACH_Pmac )
+ /* Copy mappings from the prom */
+ inherit_prom_translations();
}
static void *
MMU_get_page()
{
- void *p;
-
- if (mem_init_done) {
- p = (void *) __get_free_page(GFP_KERNEL);
- if (p == 0)
- panic("couldn't get a page in MMU_get_page");
- } else {
-#ifdef CONFIG_PREP
- mmu_pages_count++;
- if ( mmu_pages_count > MAX_MMU_PAGES )
- printk("out of mmu pages!\n");
- p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
- (mmu_pages_count+PAGE_SIZE));
-#endif
-#ifdef CONFIG_PMAC
- p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
-#endif
- }
- memset(p, 0, PAGE_SIZE);
- return p;
+ void *p;
+
+ if (mem_init_done) {
+ p = (void *) __get_free_page(GFP_KERNEL);
+ if (p == 0)
+ panic("couldn't get a page in MMU_get_page");
+ } else {
+ if ( is_prep || (_machine == _MACH_chrp) )
+ {
+ mmu_pages_count++;
+ if ( mmu_pages_count > MAX_MMU_PAGES )
+ printk("out of mmu pages!\n");
+ p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+ (mmu_pages_count+PAGE_SIZE));
+ }
+ else /* pmac */
+ {
+ p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+ }
+ }
+ memset(p, 0, PAGE_SIZE);
+ return p;
}
-#ifdef CONFIG_PMAC
void *
ioremap(unsigned long addr, unsigned long size)
{
unsigned long p, end = addr + size;
+ /*
+ * BAT mappings on prep cover this already so don't waste
+ * space with it. -- Cort
+ */
+ if ( is_prep )
+ if ( ((addr >= 0xc0000000) && (end < (0xc0000000+(256<<20)))) ||
+ ((addr >= 0x80000000) && (end < (0x80000000+(256<<20)))) )
+ return (void *)addr;
for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
- map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+ map_page(&init_task, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
return (void *) addr;
}
-#endif
+
+extern void iounmap(unsigned long *addr)
+{
+ /*
+ * BAT mappings on prep cover this already so don't waste
+ * space with it. -- Cort
+ */
+ if ( is_prep )
+ if ( (((unsigned long)addr >= 0xc0000000) && ((unsigned long)addr < (0xc0000000+(256<<20)))) ||
+ (((unsigned long)addr >= 0x80000000) && ((unsigned long)addr < (0x80000000+(256<<20)))) )
+ return;
+ /* else unmap it */
+}
void
-map_page(struct thread_struct *tss, unsigned long va,
+map_page(struct task_struct *tsk, unsigned long va,
unsigned long pa, int flags)
{
pmd_t *pd;
pte_t *pg;
+
- if (tss->pg_tables == NULL) {
+ if (tsk->mm->pgd == NULL) {
/* Allocate upper level page map */
- tss->pg_tables = (unsigned long *) MMU_get_page();
+ tsk->mm->pgd = (pgd_t *) MMU_get_page();
}
/* Use upper 10 bits of VA to index the first level map */
- pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+ pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
if (pmd_none(*pd)) {
/* Need to allocate second-level table */
pg = (pte_t *) MMU_get_page();
@@ -1084,26 +1077,6 @@ flush_tlb_mm(struct mm_struct *mm)
}
}
-
-void
-flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
- unsigned vsid;
-
- if ( vmaddr < TASK_SIZE) {
- /*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
- flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
- /* this is needed on prep at the moment -- don't know why
- -- Cort*/
- MMU_invalidate_page(vma->vm_mm,vmaddr);
- }
- else
- {
- /*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
- }
-}
-
-
/* for each page addr in the range, call MMU_invalidate_page()
if the range is very large and the hash table is small it might be faster to
do a search of the hash table and just invalidate pages that are in the range
@@ -1113,15 +1086,10 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
void
flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
{
- start &= PAGE_MASK;
+ start &= PAGE_MASK;
for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
{
- /*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
- start );*/
flush_hash_page(mm->context, start);
- /* this is needed on prep at the moment -- don't know why
- -- Cort*/
- MMU_invalidate_page(mm,start);
}
}
@@ -1135,78 +1103,18 @@ void
mmu_context_overflow(void)
{
struct task_struct *tsk;
- int nr;
- printk(KERN_INFO "mmu_context_overflow\n");
- for (nr = 0; nr < NR_TASKS; ++nr) {
- tsk = task[nr];
- if (tsk && tsk->mm)
+ printk(KERN_DEBUG "mmu_context_overflow\n");
+ read_lock(&tasklist_lock);
+ for_each_task(tsk) {
+ if (tsk->mm)
tsk->mm->context = NO_CONTEXT;
}
+ read_unlock(&tasklist_lock);
flush_hash_segments(0x10, 0xffffff);
- _tlbia();
next_mmu_context = 0;
+ /* make sure current always has a context */
+ current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
+ set_context(current->mm->context);
}
-#ifdef CONFIG_PREP
-/*
- * it's not a simple matter to get rid of these and switch to the
- * ones paul is using. it will take some time and thought -- Cort
- */
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
-{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *slot;
- int flags = 0;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = VSID_FROM_CONTEXT(segment,mm->context);
- for (_h = 0; _h < 2; _h++)
- {
- hash = page_index ^ vsid;
- if (_h)
- {
- hash = ~hash; /* Secondary hash uses ones-complement */
- }
- hash &= 0x3FF | (Hash_mask /*<< 10*/);
- hash *= 8; /* Eight entries / hash bucket */
- _pte = &Hash[hash];
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
- { /* Found it! */
- _tlbie(va); /* Clear TLB */
- if (_pte->r) flags |= _PAGE_ACCESSED;
- if (_pte->c) flags |= _PAGE_DIRTY;
- _pte->v = 0;
- return /*(flags)*/;
- }
- }
- }
- _tlbie(va);
- return /*(flags)*/;
-}
-#endif
-
-#include <asm/mmu.h>
-void print_mm_info(void)
-{
- struct _SEGREG s;
- long a;
- struct _BATU bu;
- struct _BATL bl;
- unsigned long i;
-
- for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
- {
- a = get_SR(i);
- memcpy(&s,&a,4);
- printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x %x\n",
- i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
- }
-
- asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
- printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
- bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
-}
diff --git a/arch/ppc/pmac_defconfig b/arch/ppc/pmac_defconfig
new file mode 100644
index 000000000..5f34efcd2
--- /dev/null
+++ b/arch/ppc/pmac_defconfig
@@ -0,0 +1,274 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_NATIVE=y
+CONFIG_PMAC=y
+# CONFIG_PREP is not set
+CONFIG_MCOMMON=y
+# CONFIG_M601 is not set
+# CONFIG_M603 is not set
+# CONFIG_M604 is not set
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BINFMT_JAVA=m
+CONFIG_PMAC_CONSOLE=y
+CONFIG_MAC_KEYBOARD=y
+CONFIG_MAC_FLOPPY=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_XMON=y
+CONFIG_ATY_VIDEO=y
+CONFIG_IMSTT_VIDEO=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+# 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_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# 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=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# 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_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN 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_PPA is not set
+# CONFIG_SCSI_PAS16 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_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=10
+CONFIG_SCSI_MAC53C94=y
+CONFIG_SCSI_QLOGIC_PMAC=m
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+CONFIG_NET_ALIAS=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+CONFIG_NET_IPIP=m
+# 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_PCTCP is not set
+CONFIG_INET_RARP=y
+CONFIG_PATH_MTU_DISCOVERY=y
+CONFIG_IP_NOSR=y
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MACE=y
+CONFIG_DEC_ELCP=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+CONFIG_MINIX_FS=m
+CONFIG_EXT2_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+CONFIG_NVRAM=y
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+# CONFIG_CS4232 is not set
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CONFIG_LOWLEVEL_SOUND=y
+# CONFIG_ACI_MIXER is not set
+# CONFIG_AWE32_SYNTH is not set
+# CONFIG_AEDSP16 is not set
+CONFIG_AWACS=y
diff --git a/arch/ppc/prep_defconfig b/arch/ppc/prep_defconfig
new file mode 100644
index 000000000..ea39e83ea
--- /dev/null
+++ b/arch/ppc/prep_defconfig
@@ -0,0 +1,250 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+CONFIG_MCOMMON=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_VGA_CONSOLE=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=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_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+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
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# 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_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN 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=y
+# CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT is not set
+CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y
+CONFIG_SCSI_NCR53C8XX_IOMAPPED=y
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
+CONFIG_SCSI_NCR53C8XX_SYNC=5
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 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_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SOFTCURSOR is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER 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_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
diff --git a/arch/ppc/vmlinux.lds b/arch/ppc/vmlinux.lds
new file mode 100644
index 000000000..1a51a4a7e
--- /dev/null
+++ b/arch/ppc/vmlinux.lds
@@ -0,0 +1,85 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+/* .init : { *(.init) } =0*/
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text)
+ *(.fixup)
+ *(.got1)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata1)
+ }
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ /* Read-write section, merged into data segment: */
+ . = (. + 0x0FFF) & 0xFFFFF000;
+ .data :
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
+ CONSTRUCTORS
+ }
+ _edata = .;
+ PROVIDE (edata = .);
+
+ .fixup : { *(.fixup) }
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss) *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+}
+