summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /arch/ppc/kernel
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r--arch/ppc/kernel/Makefile76
-rw-r--r--arch/ppc/kernel/head.S1754
-rw-r--r--arch/ppc/kernel/include/elf/ChangeLog155
-rw-r--r--arch/ppc/kernel/include/elf/common.h232
-rw-r--r--arch/ppc/kernel/include/elf/dwarf.h314
-rw-r--r--arch/ppc/kernel/include/elf/external.h190
-rw-r--r--arch/ppc/kernel/include/elf/hppa.h90
-rw-r--r--arch/ppc/kernel/include/elf/internal.h173
-rw-r--r--arch/ppc/kernel/include/elf/mips.h267
-rw-r--r--arch/ppc/kernel/include/elf/ppc.h32
-rw-r--r--arch/ppc/kernel/irq.c554
-rw-r--r--arch/ppc/kernel/ksyms.c14
-rw-r--r--arch/ppc/kernel/ld.script-user75
-rw-r--r--arch/ppc/kernel/misc.S659
-rw-r--r--arch/ppc/kernel/mk_defs.c161
-rw-r--r--arch/ppc/kernel/pci.c488
-rw-r--r--arch/ppc/kernel/port_io.c143
-rw-r--r--arch/ppc/kernel/ppc_asm.tmpl168
-rw-r--r--arch/ppc/kernel/ppc_defs.h119
-rw-r--r--arch/ppc/kernel/process.c270
-rw-r--r--arch/ppc/kernel/ptrace.c579
-rw-r--r--arch/ppc/kernel/setup.c246
-rw-r--r--arch/ppc/kernel/signal.c239
-rw-r--r--arch/ppc/kernel/stubs.c59
-rw-r--r--arch/ppc/kernel/support.c84
-rw-r--r--arch/ppc/kernel/syscalls.c188
-rw-r--r--arch/ppc/kernel/time.c336
-rw-r--r--arch/ppc/kernel/traps.c134
28 files changed, 7799 insertions, 0 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
new file mode 100644
index 000000000..8a3a845f1
--- /dev/null
+++ b/arch/ppc/kernel/Makefile
@@ -0,0 +1,76 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# 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__ -traditional $< -o $*.s
+ $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+.S.o:
+# $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+ $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+ $(AS) $(ASFLAGS) -o $*.o $*.s
+ rm $*.s
+
+HOST_CC = gcc
+
+OBJS = misc.o setup.o port_io.o irq.o pci.o traps.o stubs.o process.o \
+ signal.o ksyms.o time.o syscalls.o \
+ support.o ptrace.o # ramdisk_drvr.o
+
+all: head.o kernel.o #no_ramdisk.o ramdisk.o
+
+head.o: head.s
+head.s: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
+
+ppc_defs.h: mk_defs
+# simppc mk_defs -- $@
+ mk_defs $@
+
+#no_ramdisk.o: no_ramdisk.S
+
+#ramdisk.o: ramdisk.image mk_ramdisk
+# mk_ramdisk ramdisk.image $*.s
+# $(AS) -o $@ $*.s
+# rm $*.s
+
+#mk_ramdisk: mk_ramdisk.c
+# ${HOST_CC} -o mk_ramdisk mk_ramdisk.c
+
+mk_defs: mk_defs.c $(TOPDIR)/include/asm/mmu.h $(TOPDIR)/include/asm/processor.h $(TOPDIR)/include/asm/pgtable.h $(TOPDIR)/include/asm/ptrace.h
+# cc.ppc ${CFLAGS} -o mk_defs -T ld.script-user -Ttext 0x1000 mk_defs.c
+ gcc.ppc ${CFLAGS} -o mk_defs mk_defs.c
+
+
+kernel.o: $(OBJS)
+ $(LD) -r -o kernel.o $(OBJS)
+ sync
+
+#mkboot: mkboot.c
+# ${HOST_CC} -o $@ -Iinclude mkboot.c
+
+dep:
+ $(CPP) -M *.c > .depend
+
+fastdep:
+
+modules:
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
new file mode 100644
index 000000000..bd6819c34
--- /dev/null
+++ b/arch/ppc/kernel/head.S
@@ -0,0 +1,1754 @@
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
+#include <linux/errno.h>
+#define NEWMM
+#define SYNC() \
+ isync; \
+ sync
+
+/* #define TLB_STATS */
+
+/* Keep track of low-level exceptions - rather crude, but informative */
+#define STATS
+
+/*
+ * Increment a [64 bit] statistic counter
+ * Uses R2, R3
+ */
+#define BUMP(ctr) \
+ lis r2,ctr@h; \
+ ori r2,r2,ctr@l; \
+ lwz r3,4(r2); \
+ addic r3,r3,1; \
+ stw r3,4(r2); \
+ lwz r3,0(r2); \
+ addze r3,r3; \
+ stw r3,0(r2)
+
+/* The same as 'BUMP' but running unmapped (TLB code) */
+#define BUMP_UNMAPPED(ctr) \
+ mfspr r0,XER; \
+ lis r2,ctr@h; \
+ ori r2,r2,ctr@l; \
+ lis r3,0xF000; \
+ andc r2,r2,r3; \
+ lwz r3,4(r2); \
+ addic r3,r3,1; \
+ stw r3,4(r2); \
+ lwz r3,0(r2); \
+ addze r3,r3; \
+ mtspr XER,r0; \
+ stw r3,0(r2)
+
+/* These macros can be used to generate very raw traces of low-level */
+/* operations (where printf, etc. can't help). All they provide is */
+/* some after-the-fact documentation of what took place. Since [in */
+/* most instances] they have no registers to work with, they use the */
+/* hardware "special" registers SPRx for storage. Because of this, */
+/* defining more than one of them simultaneously will yield incorrect */
+/* results and a non-functional system. Note: the trick here is to */
+/* gather some data without disturbing anything - Heisenberg are you watching? */
+
+/* CAUTION! Don't turn on more than one of these at once! */
+/* #define DO_TRAP_TRACE */
+/* #define DO_TLB_TRACE */
+/* #define DO_RFI_TRACE */
+
+#ifdef DO_RFI_TRACE
+#define DO_RFI_TRACE_UNMAPPED(mark) \
+ mtspr SPR0,r1; \
+ mtspr SPR1,r2; \
+ mtspr SPR2,r3; \
+ mfcr r3; \
+ mtspr SPR3,r3; \
+ lis r1,_RFI_ptr@h; \
+ ori r1,r1,_RFI_ptr@l; \
+ lis r3,0xF000; \
+ andc r1,r1,r3; \
+ lwz r1,0(r1); \
+ andc r1,r1,r3; \
+ subi r1,r1,4; \
+ lis r2,(mark>>16); \
+ ori r2,r2,(mark&0xFFFF); \
+ stwu r2,4(r1); \
+ mfspr r2,SRR0; \
+ stwu r2,4(r1); \
+ mfspr r2,SRR1; \
+ stwu r2,4(r1); \
+ addi r1,r1,4+4; \
+ lis r2,_RFI_ptr@h; \
+ ori r2,r2,_RFI_ptr@l; \
+ andc r2,r2,r3; \
+ stw r1,0(r2); \
+ mfspr r3,SPR3; \
+ mtcrf 0xFF,r3; \
+ mfspr r1,SPR0; \
+ mfspr r2,SPR1; \
+ mfspr r3,SPR2
+#define DO_RFI_TRACE_MAPPED(mark) \
+ mtspr SPR0,r1; \
+ mtspr SPR1,r2; \
+ mtspr SPR2,r3; \
+ mfcr r3; \
+ mtspr SPR3,r3; \
+ lis r1,_RFI_ptr@h; \
+ ori r1,r1,_RFI_ptr@l; \
+ lwz r1,0(r1); \
+ lis r3,0x9000; \
+ or r1,r1,r3; \
+ subi r1,r1,4; \
+ lis r2,(mark>>16); \
+ ori r2,r2,(mark&0xFFFF); \
+ stwu r2,4(r1); \
+ mfspr r2,SRR0; \
+ stwu r2,4(r1); \
+ mfspr r2,SRR1; \
+ stwu r2,4(r1); \
+ addi r1,r1,4+4; \
+ lis r2,_RFI_ptr@h; \
+ ori r2,r2,_RFI_ptr@l; \
+ stw r1,0(r2); \
+ mfspr r3,SPR3; \
+ mtcrf 0xFF,r3; \
+ mfspr r1,SPR0; \
+ mfspr r2,SPR1; \
+ mfspr r3,SPR2
+#else
+#define DO_RFI_TRACE_UNMAPPED(mark)
+#define DO_RFI_TRACE_MAPPED(mark)
+#endif
+
+#ifdef DO_TRAP_TRACE
+#define DEFAULT_TRAP(offset) \
+ mtspr SPR0,r1; \
+ mtspr SPR1,r2; \
+ mtspr SPR2,r3; \
+ lis r1,_TRAP_ptr@h; \
+ ori r1,r1,_TRAP_ptr@l; \
+ lis r3,0xF000; \
+ andc r1,r1,r3; \
+ lwz r1,0(r1); \
+ andc r1,r1,r3; \
+ subi r1,r1,4; \
+ lis r2,0xCACA; \
+ ori r2,r2,offset; \
+ stwu r2,4(r1); \
+ mfspr r2,SRR0; \
+ stwu r2,4(r1); \
+ mfspr r2,SRR1; \
+ stwu r2,4(r1); \
+ mfspr r2,SPR0; \
+ stwu r2,4(r1); \
+ addi r1,r1,4; \
+ lis r2,_TRAP_ptr@h; \
+ ori r2,r2,_TRAP_ptr@l; \
+ andc r2,r2,r3; \
+ stw r1,0(r2); \
+ mfspr r1,SPR0; \
+ mfspr r2,SPR1; \
+ mfspr r3,SPR2; \
+ li r13,0; \
+ ori r13,r13,HID0_ICE; \
+ mtspr HID0,r13; \
+ lis r13,0xFFF00000>>16; \
+ ori r13,r13,offset; \
+ mtlr r13; \
+ b hang
+#define TRACE_TRAP(offset) \
+ mtspr SPR0,r1; \
+ mtspr SPR1,r2; \
+ mtspr SPR2,r3; \
+ mfcr r3; \
+ mtspr SPR3,r3; \
+ lis r1,_TRAP_ptr@h; \
+ ori r1,r1,_TRAP_ptr@l; \
+ lis r3,0xF000; \
+ andc r1,r1,r3; \
+ lwz r1,0(r1); \
+ andc r1,r1,r3; \
+ subi r1,r1,4; \
+ lis r2,0xCABB; \
+ ori r2,r2,offset; \
+ stwu r2,4(r1); \
+ dcbst 0,r1; \
+ mfspr r2,SRR0; \
+ stwu r2,4(r1); \
+ dcbst 0,r1; \
+ mfspr r2,SRR1; \
+ stwu r2,4(r1); \
+ dcbst 0,r1; \
+ li r2,offset; \
+ cmpi 0,r2,0x0C00; \
+ beq 01f; \
+ cmpi 0,r2,0x0300; \
+ beq 00f; \
+ cmpi 0,r2,0x0400; \
+ beq 00f; \
+ mfspr r2,SPR0; \
+ b 02f; \
+00: mfspr r2,DAR; \
+ b 02f; \
+01: mr r2,r0; \
+02: stwu r2,4(r1); \
+ dcbst 0,r1; \
+ addi r1,r1,4; \
+ mflr r2; \
+ stw r2,0(r1); \
+ bl check_trace; \
+ lwz r2,0(r1); \
+ mtlr r2; \
+02: lis r2,_TRAP_ptr@h; \
+ ori r2,r2,_TRAP_ptr@l; \
+ oris r1,r1,0x9000; \
+ cmp 0,r1,r2; \
+ bne 00f; \
+ lis r1,_TRAP_TRACE@h; \
+ ori r1,r1,_TRAP_TRACE@l; \
+00: lis r3,0xF000; \
+ andc r2,r2,r3; \
+ stw r1,0(r2); \
+ mfspr r1,SPR0; \
+ mfspr r2,SPR1; \
+ mfspr r3,SPR3; \
+ mtcrf 0xFF,r3; \
+ mfspr r3,SPR2
+#else
+#define DEFAULT_TRAP(offset) \
+ li r13,0; \
+ ori r13,r13,HID0_ICE; \
+ mtspr HID0,r13; \
+ lis r13,0xFFF00000>>16; \
+ ori r13,r13,offset; \
+ mtlr r13; \
+ blr
+#define TRACE_TRAP(offset)
+#endif
+
+#define DATA_CACHE_OFF() \
+ mfspr r2,HID0; \
+ li r3,0; \
+ ori r3,r3,HID0_DCE; \
+ andc r2,r2,r3; \
+ mtspr HID0,r2;
+
+#define DATA_CACHE_ON() \
+ mfspr r2,HID0; \
+ ori r2,r2,HID0_DCE; \
+ mtspr HID0,r2;
+
+/* This instruction is not implemented on the PPC 603 */
+#define tlbia \
+ li r4,64; \
+ mtspr CTR,r4; \
+ lis r4,0x9000; \
+0: tlbie r4; \
+ addi r4,r4,0x1000; \
+ bdnz 0b
+
+/* Validate kernel stack - check for overflow */
+#define CHECK_STACK()
+#define _CHECK_STACK() \
+ mtspr SPR0,r3; \
+ lis r2,current_set@ha; \
+ lwz r2,current_set@l(r2); \
+ lwz r2,KERNEL_STACK_PAGE(r2); \
+ lis r3,sys_stack@h; \
+ ori r3,r3,sys_stack@l; \
+ cmpl 0,r1,r3; \
+ ble 02f; \
+ li r3,0x0FFF; \
+ andc r2,r2,r3; \
+ andc r3,r1,r3; \
+ cmp 0,r3,r2; \
+ beq 02f; \
+ mr r3,r1; \
+ bl _EXTERN(bad_stack); \
+02: mfspr r3,SPR0
+
+/* Save all registers on kernel stack during an exception */
+#define SAVE_REGS(mark) \
+ subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
+ stmw r3,GPR3(r1); /* Save R3..R31 */ \
+ stw r3,ORIG_GPR3(r1); \
+ stw r0,GPR0(r1); \
+ mfspr r2,SPR0; \
+ stw r2,GPR1(r1); \
+ mfspr r2,SPR1; \
+ stw r2,GPR2(r1); \
+ mfspr r2,SPR2; \
+ stw r2,_NIP(r1); \
+ mfspr r2,SPR3; \
+ stw r2,_MSR(r1); \
+ mfctr r2; \
+ stw r2,_CTR(r1); \
+ mflr r2; \
+ stw r2,_LINK(r1); \
+ mfcr r2; \
+ stw r2,_CCR(r1); \
+ mfspr r2,XER; \
+ stw r2,_XER(r1); \
+ stfd fr0,FPR0(r1); \
+ stfd fr1,FPR1(r1); \
+ stfd fr2,FPR2(r1); \
+ stfd fr3,FPR3(r1); \
+ mffs fr0; \
+ stfd fr0,FPCSR(r1); \
+ lis r2,_break_lwarx@h; \
+ ori r2,r2,_break_lwarx@l; \
+ stwcx. r2,0,r2; \
+ li r2,mark; \
+ stw r2,TRAP(r1); \
+ lis r2,0xDEAD; \
+ ori r2,r2,0xDEAD; \
+ stw r2,MARKER(r1); \
+ li r2,0; \
+ stw r2,RESULT(r1)
+
+#define SAVE_PAGE_FAULT_REGS(offset) \
+ mfspr r2,DAR; \
+ stw r2,_DAR(r1); \
+ mfspr r2,DSISR; \
+ stw r2,_DSISR(r1); \
+ mfspr r2,PVR; /* Check for 603/603e */ \
+ srwi r2,r2,16; \
+ cmpi 0,r2,3; /* 603 */ \
+ beq 22f; \
+ cmpi 0,r2,6; /* 603e */ \
+ bne 24f; \
+22: mfspr r2,HASH1; /* Note: these registers exist only on 603 */ \
+ stw r2,_HASH1(r1); \
+ mfspr r2,HASH2; \
+ stw r2,_HASH2(r1); \
+ mfspr r2,IMISS; \
+ stw r2,_IMISS(r1); \
+ mfspr r2,DMISS; \
+ stw r2,_DMISS(r1); \
+ mfspr r2,ICMP; \
+ stw r2,_ICMP(r1); \
+ mfspr r2,DCMP; \
+ stw r2,_DCMP(r1); \
+24:
+
+#define SAVE_INT_REGS(mark) \
+ mtspr SPR0,r1; /* Save current stack pointer */ \
+ mtspr SPR1,r2; /* Scratch */ \
+ mfcr r2; \
+ mtspr SPR2,r2; \
+ mfspr r2,SRR1; /* Interrupt from user/system mode */ \
+ andi. r2,r2,MSR_PR; \
+ beq+ 10f; /* Jump if system - already have stack */ \
+ mfspr r2,SPR2; /* Restore CCR */ \
+ mtcrf 0xFF,r2; \
+ mfspr r2,SRR0; /* Preserve interrupt registers */ \
+ mtspr SPR2,r2; \
+ mfspr r2,SRR1; \
+ mtspr SPR3,r2; \
+ lis r2,05f@h; \
+ ori r2,r2,05f@l; \
+ mtspr SRR0,r2; \
+ mfmsr r2; \
+ ori r2,r2,MSR_|MSR_DR|MSR_IR; \
+ mtspr SRR1,r2; \
+ rfi; \
+05: lis r2,current_set@ha; \
+ lwz r2,current_set@l(r2); \
+ mfspr r1,SPR2; \
+ stw r1,TSS+LAST_PC(r2); \
+ mfspr r1,SPR0; \
+ stw r1,TSS+USER_STACK(r2); \
+ lwz r1,TSS+KSP(r2); \
+ subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
+ stw r1,TSS+PT_REGS(r2); /* Save regs pointer for 'ptrace' */ \
+ lwz r1,TSS+KSP(r2); \
+ b 20f; \
+10: mfspr r2,SPR2; /* Restore CCR */ \
+ mtcrf 0xFF,r2; \
+ mfspr r2,SRR0; /* Preserve interrupt registers */ \
+ mtspr SPR2,r2; \
+ mfspr r2,SRR1; \
+ mtspr SPR3,r2; \
+ lis r2,20f@h; \
+ ori r2,r2,20f@l; \
+ mtspr SRR0,r2; \
+ mfmsr r2; \
+ ori r2,r2,MSR_|MSR_DR|MSR_IR; \
+ mtspr SRR1,r2; \
+ SYNC(); \
+ rfi; \
+20: SAVE_REGS(mark); \
+ CHECK_STACK()
+
+#define RETURN_FROM_INT(mark) \
+90: mfmsr r0; /* Disable interrupts */ \
+ li r4,0; \
+ ori r4,r4,MSR_EE; \
+ andc r0,r0,r4; \
+ sync; /* Some chip revs need this... */ \
+ mtmsr r0; \
+ lis r2,intr_count@ha; /* Need to run 'bottom half' */ \
+ lwz r3,intr_count@l(r2); \
+ cmpi 0,r3,0; \
+ bne 00f; \
+ lis r4,bh_mask@ha; \
+ lwz r4,bh_mask@l(r4); \
+ lis r5,bh_active@ha; \
+ lwz r5,bh_active@l(r5); \
+ and. r4,r4,r5; \
+ beq 00f; \
+ addi r3,r3,1; \
+ stw r3,intr_count@l(r2); \
+ bl _EXTERN(_do_bottom_half); \
+ lis r2,intr_count@ha; \
+ lwz r3,intr_count@l(r2); \
+ subi r3,r3,1; \
+ stw r3,intr_count@l(r2); \
+00: lwz r2,_MSR(r1); /* Returning to user mode? */ \
+ andi. r2,r2,MSR_PR; \
+ beq+ 10f; /* no - no need to mess with stack */ \
+/* lis r2,kernel_pages_are_copyback@ha; \
+ lwz r2,kernel_pages_are_copyback@l(r2); \
+ cmpi 0,r2,0; \
+ beq 05f; \
+ bl _EXTERN(flush_instruction_cache); */ \
+05: lis r3,current_set@ha; /* need to save kernel stack pointer */ \
+ lwz r3,current_set@l(r3); \
+ addi r4,r1,INT_FRAME_SIZE; /* size of frame */ \
+ stw r4,TSS+KSP(r3); \
+ lwz r4,STATE(r3); /* If state != 0, can't run */ \
+ cmpi 0,r4,0; \
+ beq 06f; \
+ bl _EXTERN(schedule); \
+ b 90b; \
+06: lwz r4,COUNTER(r3); /* Time quantum expired? */ \
+ cmpi 0,r4,0; \
+ bne 07f; \
+ bl _EXTERN(schedule); \
+ b 90b; \
+07: lwz r4,BLOCKED(r3); /* Check for pending unblocked signals */ \
+ lwz r5,SIGNAL(r3); \
+ andc. r0,r5,r4; /* Lets thru any unblocked */ \
+ beq 10f; \
+ mr r3,r4; \
+ mr r4,r1; \
+ bl _EXTERN(do_signal); \
+10: lwz r2,_NIP(r1); /* Restore environment */ \
+ mtspr SRR0,r2; \
+ lwz r2,_MSR(r1); \
+ mtspr SRR1,r2; \
+ lmw r3,GPR3(r1); \
+ lwz r2,_CTR(r1); \
+ mtctr r2; \
+ lwz r2,_LINK(r1); \
+ mtlr r2; \
+ lwz r2,_XER(r1); \
+ mtspr XER,r2; \
+ lwz r2,_CCR(r1); \
+ mtcrf 0xFF,r2; \
+ lfd fr0,FPCSR(r1); \
+ mtfsf 0xFF,fr0; \
+ lfd fr0,FPR0(r1); \
+ lfd fr1,FPR1(r1); \
+ lfd fr2,FPR2(r1); \
+ lfd fr3,FPR3(r1); \
+ lwz r0,GPR0(r1); \
+ lwz r2,GPR2(r1); \
+ lwz r1,GPR1(r1); \
+ SYNC(); \
+ rfi
+
+_TEXT()
+/*
+ * This code may be executed by a bootstrap process. If so, the
+ * purpose is to relocate the loaded image to it's final location
+ * in memory.
+ * R3: End of image
+ * R4: Start of image - 0x400
+ * R11: Start of command line string
+ * R12: End of command line string
+ * R30: 'BeBx' if this is a BeBox
+ *
+ */
+ .globl _start
+ .globl _stext
+_stext:
+_start:
+ addi r4,r4,0x400 /* Point at start of image */
+ li r5,0 /* Load address */
+ subi r4,r4,4 /* Adjust for auto-increment */
+ subi r5,r5,4
+ subi r3,r3,4
+00: lwzu r0,4(r4) /* Fast move */
+ stwu r0,4(r5)
+ cmp 0,r3,r4
+ bne 00b
+ li r5,0x100 /* Actual code starts here */
+ mtlr r5
+ blr
+
+hang:
+ ori r0,r0,0
+ b hang
+
+/*
+ * BeBox CPU #1 vector & code
+ */
+_ORG(0x0080)
+ .globl BeBox_CPU1_vector
+BeBox_CPU1_vector:
+ .long 0
+BeBox_CPU1_reset:
+ li r1,BeBox_CPU1_vector@l
+ li r2,0
+ stw r2,0(r1)
+00: lwz r2,0(r1)
+ cmpi 0,r2,0
+ bne 10f
+ li r2,10000
+ mtctr r2
+02: nop
+ bdnz 02b
+ b 00b
+10: mtlr r1
+ blr
+
+_ORG(0x0100)
+
+/* Hard Reset */
+ .globl HardReset
+HardReset:
+ b Reset
+
+_ORG(0x0200)
+ b MachineCheck
+
+_ORG(0x0300)
+ b DataAccess
+
+_ORG(0x0400)
+ b InstructionAccess
+
+_ORG(0x0500)
+ b HardwareInterrupt
+
+_ORG(0x0600)
+ b Alignment
+
+_ORG(0x0700)
+ b ProgramCheck
+
+_ORG(0x0800)
+ b FloatingPointCheck
+
+/* Decrementer register - ignored for now... */
+_ORG(0x0900)
+/* TRACE_TRAP(0x900) */
+ mtspr SPR0,r1
+ lis r1,0x7FFF
+ ori r1,r1,0xFFFF
+ mtspr DEC,r1
+ mfspr r1,SPR0
+#if 0
+ SYNC
+#endif
+ rfi
+
+_ORG(0x0A00)
+DEFAULT_TRAP(0x0A00)
+_ORG(0x0B00)
+DEFAULT_TRAP(0x0B00)
+
+/*
+ * System call
+ */
+_ORG(0x0C00)
+ b SystemCall
+
+_ORG(0x0D00)
+ b SingleStep
+
+_ORG(0x0E00)
+DEFAULT_TRAP(0x0E00)
+_ORG(0x0F00)
+DEFAULT_TRAP(0x0F00)
+
+/*
+ * Handle TLB Miss on an instruction load
+ */
+_ORG(0x1000)
+/* Note: It is *unsafe* to use the TRACE TRAP macro here since there */
+/* could be a 'trace' in progress when the TLB miss occurs. */
+/* TRACE_TRAP(0x1000) */
+#ifdef TLB_STATS
+ lis r2,DataLoadTLB_trace_ptr@h
+ ori r2,r2,DataLoadTLB_trace_ptr@l
+ lis r3,0xF000
+ andc r2,r2,r3
+ lwz r1,0(r2)
+ andc r1,r1,r3
+ li r0,0x1000
+ stw r0,0(r1)
+ mftbu r0
+ stw r0,4(r1)
+ mftb r0
+ stw r0,8(r1)
+ mfspr r0,IMISS
+ mfspr r3,SRR1
+ extrwi r3,r3,1,14
+ or r0,r0,r3
+ stw r0,12(r1)
+ addi r1,r1,16
+ mfcr r0
+ cmpl 0,r1,r2
+ blt 00f
+ lis r1,DataLoadTLB_trace_buf@h
+ ori r1,r1,DataLoadTLB_trace_buf@l
+ lis r3,0xF000
+ andc r1,r1,r3
+00: mtcrf 0xFF,r0
+ stw r1,0(r2)
+#endif
+ b InstructionTLBMiss
+
+/*
+ * Handle TLB Miss on a data item load
+ */
+_ORG(0x1100)
+/* TRACE_TRAP(0x1100) */
+#ifdef TLB_STATS
+ lis r2,DataLoadTLB_trace_ptr@h
+ ori r2,r2,DataLoadTLB_trace_ptr@l
+ lis r3,0xF000
+ andc r2,r2,r3
+ lwz r1,0(r2)
+ andc r1,r1,r3
+ li r0,0x1100
+ stw r0,0(r1)
+ mftbu r0
+ stw r0,4(r1)
+ mftb r0
+ stw r0,8(r1)
+ mfspr r0,DMISS
+ mfspr r3,SRR1
+ extrwi r3,r3,1,14
+ or r0,r0,r3
+ stw r0,12(r1)
+ addi r1,r1,16
+ mfcr r0
+ cmpl 0,r1,r2
+ blt 00f
+ lis r1,DataLoadTLB_trace_buf@h
+ ori r1,r1,DataLoadTLB_trace_buf@l
+ lis r3,0xF000
+ andc r1,r1,r3
+00: mtcrf 0xFF,r0
+ stw r1,0(r2)
+ .data
+DataLoadTLB_trace_buf:
+ .space 64*1024*4
+DataLoadTLB_trace_ptr:
+ .long DataLoadTLB_trace_buf
+ .text
+#endif
+ b DataLoadTLBMiss
+
+/*
+ * Handle TLB Miss on a store operation
+ */
+_ORG(0x1200)
+/* TRACE_TRAP(0x1200) */
+#ifdef TLB_STATS
+ lis r2,DataLoadTLB_trace_ptr@h
+ ori r2,r2,DataLoadTLB_trace_ptr@l
+ lis r3,0xF000
+ andc r2,r2,r3
+ lwz r1,0(r2)
+ andc r1,r1,r3
+ li r0,0x1200
+ stw r0,0(r1)
+ mftbu r0
+ stw r0,4(r1)
+ mftb r0
+ stw r0,8(r1)
+ mfspr r0,DMISS
+ mfspr r3,SRR1
+ extrwi r3,r3,1,14
+ or r0,r0,r3
+ stw r0,12(r1)
+ addi r1,r1,16
+ mfcr r0
+ cmpl 0,r1,r2
+ blt 00f
+ lis r1,DataLoadTLB_trace_buf@h
+ ori r1,r1,DataLoadTLB_trace_buf@l
+ lis r3,0xF000
+ andc r1,r1,r3
+00: mtcrf 0xFF,r0
+ stw r1,0(r2)
+#endif
+ b DataStoreTLBMiss
+
+_ORG(0x1300)
+InstructionAddressBreakpoint:
+ DEFAULT_TRAP(0x1300)
+
+_ORG(0x1400)
+SystemManagementInterrupt:
+ DEFAULT_TRAP(0x1400)
+
+_ORG(0x1500)
+
+/*
+ * 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.
+ * Since the instruction cache NEVER snoops the data cache, memory must
+ * be made coherent with the data cache to insure that the instruction
+ * cache gets a valid instruction stream. Note that this flushing is
+ * only performed when switching from system to user mode since this is
+ * the only juncture [as far as the OS goes] where the data cache may
+ * contain instructions, e.g. after a disk read.
+ */
+#define NUM_CACHE_LINES 128*4
+#define CACHE_LINE_SIZE 32
+cache_flush_buffer:
+ .space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
+
+#if NUM_CACHE_LINES < 512
+_ORG(0x4000)
+#endif
+
+
+/*
+ * Hardware reset [actually from bootstrap]
+ * Initialize memory management & call secondary init
+ * Registers initialized by bootstrap:
+ * R11: Start of command line string
+ * R12: End of command line string
+ * R30: 'BeBx' if this is a BeBox
+ */
+Reset:
+ lis r7,0xF000 /* To mask upper 4 bits */
+#define IS_BE_BOX 0x42654278 /* 'BeBx' */
+ lis r1,isBeBox@h
+ ori r1,r1,isBeBox@l
+ andc r1,r1,r7
+/* See if this is a CPU other than CPU#1 */
+/* This [currently] happens on the BeBox */
+ lwz r2,0(r1)
+ cmpi 0,r2,0
+ bne Reset_BeBox_CPU1
+/* Save machine type indicator */
+ li r2,0
+ lis r3,IS_BE_BOX>>16
+ ori r3,r3,IS_BE_BOX&0xFFFF
+ cmp 0,r30,r3
+ bne 00f
+ li r2,1
+ mr r11,r28
+ mr r12,r29
+ lis r5,BeBox_CPU1_vector@h
+ ori r5,r5,BeBox_CPU1_vector@l
+ andc r5,r5,r7 /* Tell CPU #1 where to go */
+00: stw r2,0(r1)
+ stw r30,4(r1)
+/* Copy argument string */
+ li r0,0 /* Null terminate string */
+ stb r0,0(r12)
+ lis r1,cmd_line@h
+ ori r1,r1,cmd_line@l
+ andc r1,r1,r7 /* No MMU yet - need unmapped address */
+ subi r1,r1,1
+ subi r11,r11,1
+00: lbzu r0,1(r11)
+ cmpi 0,r0,0
+ stbu r0,1(r1)
+ bne 00b
+ lis r1,sys_stack@h
+ ori r1,r1,sys_stack@l
+ li r2,0x0FFF /* Mask stack address down to page boundary */
+ andc r1,r1,r2
+ subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
+ li r2,0 /* TOC pointer for nanokernel */
+ li r0,MSR_ /* Make sure FPU enabled */
+ mtmsr r0
+ lis r3,_edata@h /* Clear BSS */
+ ori r3,r3,_edata@l
+ andc r3,r3,r7 /* make unmapped address */
+ lis r4,_end@h
+ ori r4,r4,_end@l
+ andc r4,r4,r7 /* make unmapped address */
+ subi r3,r3,4
+ li r0,0
+00: stwu r0,4(r3)
+ cmp 0,r3,r4
+ blt 00b
+/* Initialize BAT registers */
+ lis r3,BAT0@h
+ ori r3,r3,BAT0@l
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r0,0(r3)
+ mtspr IBAT0U,r0
+ mtspr DBAT0U,r0
+ lwz r0,4(r3)
+ mtspr IBAT0L,r0
+ mtspr DBAT0L,r0
+ lis r3,BAT1@h
+ ori r3,r3,BAT1@l
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r0,0(r3)
+ mtspr IBAT1U,r0
+ mtspr DBAT1U,r0
+ lwz r0,4(r3)
+ mtspr IBAT1L,r0
+ mtspr DBAT1L,r0
+/* this BAT mapping will cover all of kernel space */
+#ifdef NEWMM
+ lis r3,BAT2@h
+ ori r3,r3,BAT2@l
+#else
+ lis r3,TMP_BAT2@h
+ ori r3,r3,TMP_BAT2@l
+#endif
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r0,0(r3)
+ mtspr IBAT2U,r0
+ mtspr DBAT2U,r0
+ lwz r0,4(r3)
+ mtspr IBAT2L,r0
+ mtspr DBAT2L,r0
+#if 0
+ lis r3,BAT3@h
+ ori r3,r3,BAT3@l
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r0,0(r3)
+ mtspr IBAT3U,r0
+ mtspr DBAT3U,r0
+ lwz r0,4(r3)
+ mtspr IBAT3L,r0
+ mtspr DBAT3L,r0
+#endif
+/* Now we can turn on the MMU */
+ mfmsr r3
+ ori r3,r3,MSR_DR|MSR_IR
+ mtspr SRR1,r3
+ lis r3,10f@h
+ ori r3,r3,10f@l
+ mtspr SRR0,r3
+DO_RFI_TRACE_UNMAPPED(0xDEAD0000)
+ SYNC
+ rfi /* enables MMU */
+10: bl _EXTERN(MMU_init) /* initialize MMU environment */
+DO_RFI_TRACE_MAPPED(0xDEAD0100)
+/* Withdraw BAT2->RAM mapping */
+ lis r7,0xF000 /* To mask upper 4 bits */
+ lis r3,20f@h
+ ori r3,r3,20f@l
+ andc r3,r3,r7 /* make unmapped address */
+ mtspr SRR0,r3
+ mfmsr r3
+ li r4,MSR_DR|MSR_IR
+ andc r3,r3,r4
+ mtspr SRR1,r3
+ SYNC
+DO_RFI_TRACE_MAPPED(0xDEAD0200)
+ SYNC
+ rfi
+20:
+
+DO_RFI_TRACE_UNMAPPED(0xDEAD0400)
+20: lis r3,BAT2@h
+ ori r3,r3,BAT2@l
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r0,0(r3)
+ mtspr IBAT2U,r0
+ mtspr DBAT2U,r0
+ lwz r0,4(r3)
+ mtspr IBAT2L,r0
+ mtspr DBAT2L,r0
+/* Load up the kernel context */
+ lis r2,init_task@h
+ ori r2,r2,init_task@l
+ addi r2,r2,TSS
+ andc r2,r2,r7 /* make unmapped address */
+ SYNC /* Force all PTE updates to finish */
+ tlbia /* Clear all TLB entries */
+ lis r3,_SDR1@h
+ ori r3,r3,_SDR1@l
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r3,0(r3)
+ mtspr SDR1,r3
+ lwz r0,MMU_SEG0(r2)
+ mtsr SR0,r0
+ lwz r0,MMU_SEG1(r2)
+ mtsr SR1,r0
+ lwz r0,MMU_SEG2(r2)
+ mtsr SR2,r0
+ lwz r0,MMU_SEG3(r2)
+ mtsr SR3,r0
+ lwz r0,MMU_SEG4(r2)
+ mtsr SR4,r0
+ lwz r0,MMU_SEG5(r2)
+ mtsr SR5,r0
+ lwz r0,MMU_SEG6(r2)
+ mtsr SR6,r0
+ lwz r0,MMU_SEG7(r2)
+ mtsr SR7,r0
+ lwz r0,MMU_SEG8(r2)
+ mtsr SR8,r0
+ lwz r0,MMU_SEG9(r2)
+ mtsr SR9,r0
+ lwz r0,MMU_SEG10(r2)
+ mtsr SR10,r0
+ lwz r0,MMU_SEG11(r2)
+ mtsr SR11,r0
+ lwz r0,MMU_SEG12(r2)
+ mtsr SR12,r0
+ lwz r0,MMU_SEG13(r2)
+ mtsr SR13,r0
+ lwz r0,MMU_SEG14(r2)
+ mtsr SR14,r0
+ lwz r0,MMU_SEG15(r2)
+ mtsr SR15,r0
+/* Now turn on the MMU for real! */
+ mfmsr r3
+ ori r3,r3,MSR_DR|MSR_IR
+ mtspr SRR1,r3
+ lis r3,30f@h
+ ori r3,r3,30f@l
+ mtspr SRR0,r3
+DO_RFI_TRACE_UNMAPPED(0xDEAD0500)
+ SYNC
+ rfi /* enables MMU */
+30:
+/* Turn on L1 Data Cache */
+ mfspr r3,HID0 /* Caches are controlled by this register */
+ ori r4,r3,(HID0_ICE|HID0_ICFI)
+ ori r3,r3,(HID0_ICE)
+ ori r4,r4,(HID0_DCE|HID0_DCI)
+ ori r3,r3,(HID0_DCE)
+ sync
+ mtspr HID0,r4
+ mtspr HID0,r3
+/* L1 cache enable */
+ mfspr r2,PVR /* Check for 603/603e */
+ srwi r2,r2,16
+ cmpi 0,r2,4 /* 604 */
+ bne 40f
+ mfspr r3,HID0 /* Turn on 604 specific features */
+ ori r3,r3,(HID0_SIED|HID0_BHTE)
+ mtspr HID0,r3
+40: b _EXTERN(start_kernel) /* call main code */
+ .long 0 # Illegal!
+
+/*
+ * BeBox CPU #2 runs here
+ */
+Reset_BeBox_CPU1:
+ lis r1,CPU1_stack@h
+ ori r1,r1,CPU1_stack@l
+ li r2,0x0FFF /* Mask stack address down to page boundary */
+ andc r1,r1,r2
+ subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
+ lis r30,CPU1_trace@h
+ ori r30,r30,CPU1_trace@l
+ andc r30,r30,r7
+ li r5,1
+ stw r5,0(r30)
+ li r2,0 /* TOC pointer for nanokernel */
+ li r0,MSR_ /* Make sure FPU enabled */
+ mtmsr r0
+/* Initialize BAT registers */
+ lis r3,BAT0@h
+ ori r3,r3,BAT0@l
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r0,0(r3)
+ mtspr IBAT0U,r0
+ mtspr DBAT0U,r0
+ lwz r0,4(r3)
+ mtspr IBAT0L,r0
+ mtspr DBAT0L,r0
+ lis r3,BAT1@h
+ ori r3,r3,BAT1@l
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r0,0(r3)
+ mtspr IBAT1U,r0
+ mtspr DBAT1U,r0
+ lwz r0,4(r3)
+ mtspr IBAT1L,r0
+ mtspr DBAT1L,r0
+ lis r3,TMP_BAT2@h
+ ori r3,r3,TMP_BAT2@l
+ andc r3,r3,r7 /* make unmapped address */
+ lwz r0,0(r3)
+ mtspr IBAT2U,r0
+ mtspr DBAT2U,r0
+ lwz r0,4(r3)
+ mtspr IBAT2L,r0
+ mtspr DBAT2L,r0
+/* Now we can turn on the MMU */
+ mfmsr r3
+ ori r3,r3,MSR_DR|MSR_IR
+ mtspr SRR1,r3
+ lis r3,10f@h
+ ori r3,r3,10f@l
+ mtspr SRR0,r3
+ li r5,2
+ stw r5,0(r30)
+ SYNC
+ rfi /* enables MMU */
+10:
+ lis r30,CPU1_trace@h
+ ori r30,r30,CPU1_trace@l
+ li r5,3
+ stw r5,0(r30)
+ bl _EXTERN(BeBox_CPU1)
+
+/*
+ * Machine Check (Bus Errors, etc)
+ */
+MachineCheck:
+ TRACE_TRAP(0x0200)
+ SAVE_INT_REGS(0x0200)
+ mr r3,r1 /* Set pointer to saved regs */
+ bl _EXTERN(MachineCheckException)
+ RETURN_FROM_INT(0x0200)
+
+/*
+ * Data Access exception
+ */
+DataAccess:
+/* TRACE_TRAP(0x0300) */
+ SAVE_INT_REGS(0x0300)
+ SAVE_PAGE_FAULT_REGS(0x0300)
+ BUMP(__Data_Page_Faults)
+ mr r3,r1 /* Set pointer to saved regs */
+ bl _EXTERN(DataAccessException)
+#if 0
+ bl _EXTERN(flush_instruction_cache)
+#endif
+ RETURN_FROM_INT(0x0300)
+
+/*
+ * Instruction Access Exception
+ */
+InstructionAccess:
+/* TRACE_TRAP(0x0400) */
+ SAVE_INT_REGS(0x0400)
+ SAVE_PAGE_FAULT_REGS(0x0400)
+ BUMP(__Instruction_Page_Faults)
+ mr r3,r1 /* Set pointer to saved regs */
+ bl _EXTERN(InstructionAccessException)
+#if 0
+ bl _EXTERN(flush_instruction_cache)
+#endif
+ RETURN_FROM_INT(0x0400)
+
+/*
+ * Hardware Interrupt
+ */
+HardwareInterrupt:
+ SAVE_INT_REGS(0x0500)
+ BUMP(__Hardware_Interrupts)
+ mr r3,r1 /* Set pointer to saved regs */
+ bl _EXTERN(handle_IRQ)
+ RETURN_FROM_INT(0x0500)
+
+/*
+ * Alignment
+ */
+Alignment:
+ TRACE_TRAP(0x0600)
+ SAVE_INT_REGS(0x0600)
+ mr r3,r1 /* Set pointer to saved regs */
+ bl _EXTERN(AlignmentException)
+ RETURN_FROM_INT(0x0600)
+
+/*
+ * Illegal instruction
+ */
+ProgramCheck:
+ TRACE_TRAP(0x0700)
+ SAVE_INT_REGS(0x0700)
+ mr r3,r1 /* Set pointer to saved regs */
+ bl _EXTERN(ProgramCheckException)
+ RETURN_FROM_INT(0x0700)
+
+/*
+ * Single Step Exception
+ */
+SingleStep:
+ SAVE_INT_REGS(0x0D00)
+ SAVE_PAGE_FAULT_REGS(0x0D00)
+ mr r3,r1 /* Set pointer to saved regs */
+ bl _EXTERN(SingleStepException)
+#if 0
+ bl _EXTERN(flush_instruction_cache)
+#endif
+ RETURN_FROM_INT(0x0D00)
+
+/*
+ * Floating point [not available, etc]
+ */
+FloatingPointCheck:
+ TRACE_TRAP(0x0800)
+ SAVE_INT_REGS(0x0800)
+ mr r3,r1 /* Set pointer to saved regs */
+ bl _EXTERN(FloatingPointCheckException)
+ RETURN_FROM_INT(0x0200)
+
+/*
+ * System Call exception
+ */
+SystemCall:
+/* TRACE_TRAP(0x0C00) */
+ SAVE_INT_REGS(0x0C00)
+ lwz r2,_CCR(r1) /* Clear SO bit in CR */
+ lis r9,0x1000
+ andc r2,r2,r9
+ stw r2,_CCR(r1)
+ cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
+ bne+ 10f
+ mr r3,r1
+ bl _EXTERN(sys_sigreturn)
+ cmpi 0,r3,0 /* Check for restarted system call */
+ bge 99f
+ b 20f
+10: lis r2,current_set@ha
+ lwz r2,current_set@l(r2)
+ lwz r2,TASK_FLAGS(r2)
+ andi. r2,r2,PF_TRACESYS
+ bne 50f
+ lis r2,sys_call_table@h
+ ori r2,r2,sys_call_table@l
+ slwi r0,r0,2
+ lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
+ mtlr r2
+ mr r9,r1
+ blrl /* Call handler */
+20: stw r3,RESULT(r1) /* Save result */
+ cmpi 0,r3,0
+ bge 30f
+ neg r3,r3
+ cmpi 0,r3,ERESTARTNOHAND
+ bne 22f
+ li r3,EINTR
+22: lwz r2,_CCR(r1) /* Set SO bit in CR */
+ oris r2,r2,0x1000
+ stw r2,_CCR(r1)
+30: stw r3,GPR3(r1) /* Update return value */
+#if 0
+ mr r3,r1
+ bl _EXTERN(trace_syscall)
+#endif
+ b 99f
+/* Traced system call support */
+50: bl _EXTERN(syscall_trace)
+ lwz r0,GPR0(r1) /* Restore original registers */
+ lwz r3,GPR3(r1)
+ lwz r4,GPR4(r1)
+ lwz r5,GPR5(r1)
+ lwz r6,GPR6(r1)
+ lwz r7,GPR7(r1)
+ lwz r8,GPR8(r1)
+ lwz r9,GPR9(r1)
+ lis r2,sys_call_table@h
+ ori r2,r2,sys_call_table@l
+ slwi r0,r0,2
+ lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
+ mtlr r2
+ mr r9,r1
+ blrl /* Call handler */
+ stw r3,RESULT(r1) /* Save result */
+ cmpi 0,r3,0
+ bge 60f
+ neg r3,r3
+ cmpi 0,r3,ERESTARTNOHAND
+ bne 52f
+ li r3,EINTR
+52: lwz r2,_CCR(r1) /* Set SO bit in CR */
+ oris r2,r2,0x1000
+ stw r2,_CCR(r1)
+60: stw r3,GPR3(r1) /* Update return value */
+ bl _EXTERN(syscall_trace)
+99:
+#if 0 /* This isn't needed here - already in RETURN_FROM_INT */
+ lis r2,kernel_pages_are_copyback@ha
+ lwz r2,kernel_pages_are_copyback@l(r2)
+ cmpi 0,r2,0
+ beq 00f
+ bl _EXTERN(flush_instruction_cache) /* Ensure cache coherency */
+00:
+#endif
+ RETURN_FROM_INT(0x0C00)
+
+/*
+ * Handle TLB miss for instruction
+ */
+InstructionTLBMiss:
+ BUMP_UNMAPPED(__Instruction_TLB_Misses)
+#ifdef DO_TLB_TRACE
+ lis r1,_TLB_ptr@h
+ ori r1,r1,_TLB_ptr@l
+ lis r2,0xF000
+ andc r1,r1,r2
+ lwz r1,0(r1)
+ andc r1,r1,r2
+ subi r1,r1,4
+ lis r2,0xBEBE
+ ori r2,r2,0x0100
+ stwu r2,4(r1)
+ mfspr r2,SRR0
+ stwu r2,4(r1)
+ mfspr r2,SRR1
+ stwu r2,4(r1)
+ mfspr r2,HASH1
+ stwu r2,4(r1)
+ mfspr r2,HASH2
+ stwu r2,4(r1)
+ mfspr r2,ICMP
+ stwu r2,4(r1)
+ mfspr r2,IMISS
+ stwu r2,4(r1)
+ addi r1,r1,4+(1*4)
+ lis r3,_TLB_ptr@h
+ ori r3,r3,_TLB_ptr@l
+ lis r2,0xF000
+ andc r3,r3,r2
+ stw r1,0(r3)
+#endif
+ mfctr r0 /* Need to save this - CTR can't be touched! */
+ mfspr r2,HASH1 /* Get PTE pointer */
+ mfspr r3,ICMP /* Partial item compare value */
+00: li r1,8 /* 8 items / bucket */
+ mtctr r1
+ subi r2,r2,8 /* Preset pointer */
+10: lwzu r1,8(r2) /* Get next PTE */
+ cmp 0,r1,r3 /* Found entry yet? */
+ bdne 10b /* Jump back if not, until CTR==0 */
+ bne 30f /* Try secondary hash if CTR==0 */
+ lwz r1,4(r2) /* Get second word of entry */
+#if 0
+ andi. r3,r1,0x08 /* Check guard bit - invalid access if set */
+ bne InstructionFetchError
+#endif
+ andi. r3,r1,0x100 /* Check R bit (referenced) */
+ bne 20f /* If set, all done */
+ ori r1,r1,0x100 /* Set bit */
+ stw r1,4(r2) /* Update memory image */
+20: mtctr r0 /* Restore CTR */
+ mfspr r3,SRR1 /* Need to restore CR0 */
+ mtcrf 0x80,r3
+ mfspr r0,IMISS /* Set to update TLB */
+ mtspr RPA,r1
+ tlbli r0
+#if 0
+ SYNC
+#endif
+ rfi /* All done */
+/* Secondary hash */
+30: andi. r1,r3,0x40 /* Already doing secondary hash? */
+ bne InstructionAddressInvalid /* Yes - item not in hash table */
+ mfspr r2,HASH2 /* Get hash table pointer */
+ ori r3,r3,0x40 /* Set secondary hash */
+ b 00b /* Try lookup again */
+
+/*
+ * Handle TLB miss for DATA Load operation
+ */
+DataLoadTLBMiss:
+ BUMP_UNMAPPED(__DataLoad_TLB_Misses)
+#ifdef DO_TLB_TRACE
+ lis r1,_TLB_ptr@h
+ ori r1,r1,_TLB_ptr@l
+ lis r2,0xF000
+ andc r1,r1,r2
+ lwz r1,0(r1)
+ andc r1,r1,r2
+ subi r1,r1,4
+ lis r2,0xBEBE
+ ori r2,r2,0x0200
+ stwu r2,4(r1)
+ mfspr r2,SRR0
+ stwu r2,4(r1)
+ mfspr r2,SRR1
+ stwu r2,4(r1)
+ mfspr r2,HASH1
+ stwu r2,4(r1)
+ mfspr r2,HASH2
+ stwu r2,4(r1)
+ mfspr r2,DCMP
+ stwu r2,4(r1)
+ mfspr r2,DMISS
+ stwu r2,4(r1)
+ addi r1,r1,4+(1*4)
+ lis r3,_TLB_ptr@h
+ ori r3,r3,_TLB_ptr@l
+ lis r2,0xF000
+ andc r3,r3,r2
+ stw r1,0(r3)
+#endif
+ mfctr r0 /* Need to save this - CTR can't be touched! */
+ mfspr r2,HASH1 /* Get PTE pointer */
+ mfspr r3,DCMP /* Partial item compare value */
+00: li r1,8 /* 8 items / bucket */
+ mtctr r1
+ subi r2,r2,8 /* Preset pointer */
+10: lwzu r1,8(r2) /* Get next PTE */
+ cmp 0,r1,r3 /* Found entry yet? */
+ bdne 10b /* Jump back if not, until CTR==0 */
+ bne 30f /* Try secondary hash if CTR==0 */
+ lwz r1,4(r2) /* Get second word of entry */
+ andi. r3,r1,0x100 /* Check R bit (referenced) */
+ ori r1,r1,0x100 /* Set bit */
+ bne 20f /* If set, all done */
+ stw r1,4(r2) /* Update memory image */
+20: mtctr r0 /* Restore CTR */
+ mfspr r3,SRR1 /* Need to restore CR0 */
+ mtcrf 0x80,r3
+ mfspr r0,DMISS /* Set to update TLB */
+ mtspr RPA,r1
+/* SYNC() */
+ tlbld r0
+#if 0
+ SYNC
+#endif
+ rfi /* All done */
+/* Secondary hash */
+30: andi. r1,r3,0x40 /* Already doing secondary hash? */
+ bne DataAddressInvalid /* Yes - item not in hash table */
+ mfspr r2,HASH2 /* Get hash table pointer */
+ ori r3,r3,0x40 /* Set secondary hash */
+ b 00b /* Try lookup again */
+
+/*
+ * Handle TLB miss for DATA STORE
+ */
+DataStoreTLBMiss:
+ BUMP_UNMAPPED(__DataStore_TLB_Misses)
+#ifdef DO_TLB_TRACE
+ lis r1,_TLB_ptr@h
+ ori r1,r1,_TLB_ptr@l
+ lis r2,0xF000
+ andc r1,r1,r2
+ lwz r1,0(r1)
+ andc r1,r1,r2
+ subi r1,r1,4
+ lis r2,0xBEBE
+ ori r2,r2,0x0300
+ stwu r2,4(r1)
+ mfspr r2,SRR0
+ stwu r2,4(r1)
+ mfspr r2,SRR1
+ stwu r2,4(r1)
+ mfspr r2,HASH1
+ stwu r2,4(r1)
+ mfspr r2,HASH2
+ stwu r2,4(r1)
+ mfspr r2,DCMP
+ stwu r2,4(r1)
+ mfspr r2,DMISS
+ stwu r2,4(r1)
+ addi r1,r1,4+(1*4)
+ lis r3,_TLB_ptr@h
+ ori r3,r3,_TLB_ptr@l
+ lis r2,0xF000
+ andc r3,r3,r2
+ stw r1,0(r3)
+#endif
+ mfctr r0 /* Need to save this - CTR can't be touched! */
+ mfspr r2,HASH1 /* Get PTE pointer */
+ mfspr r3,DCMP /* Partial item compare value */
+00: li r1,8 /* 8 items / bucket */
+ mtctr r1
+ subi r2,r2,8 /* Preset pointer */
+10: lwzu r1,8(r2) /* Get next PTE */
+ cmp 0,r1,r3 /* Found entry yet? */
+ bdne 10b /* Jump back if not, until CTR==0 */
+ bne 30f /* Try secondary hash if CTR==0 */
+ lwz r1,4(r2) /* Get second word of entry */
+ andi. r3,r1,0x80 /* Check C bit (changed) */
+#if 0 /* Note: no validation */
+ beq 40f /* If not set (first time) validate access */
+#else
+ ori r1,r1,0x180 /* Set changed, accessed */
+ bne 20f
+ stw r1,4(r2)
+#endif
+20: mtctr r0 /* Restore CTR */
+ mfspr r3,SRR1 /* Need to restore CR0 */
+ mtcrf 0x80,r3
+ mfspr r0,DMISS /* Set to update TLB */
+ mtspr RPA,r1
+ tlbld r0
+#if 0
+ SYNC
+#endif
+ rfi /* All done */
+/* Secondary hash */
+30: andi. r1,r3,0x40 /* Already doing secondary hash? */
+ bne DataAddressInvalid /* Yes - item not in hash table */
+ mfspr r2,HASH2 /* Get hash table pointer */
+ ori r3,r3,0x40 /* Set secondary hash */
+ b 00b /* Try lookup again */
+/* PTE found - validate access */
+40: rlwinm. r3,r1,30,0,1 /* Extract PP bits */
+ bge- 50f /* Jump if PP=0,1 */
+ andi. r3,r1,1
+ beq+ 70f /* Access OK */
+ b WriteProtectError /* Not OK - fail! */
+50: mfspr r3,SRR1 /* Check privilege */
+ andi. r3,r3,MSR_PR
+ beq+ 60f /* Jump if supervisor mode */
+ mfspr r3,DMISS /* Get address */
+ mfsrin r3,r3 /* Get segment register */
+ andis. r3,r3,0x2000 /* If Kp==0, OK */
+ beq+ 70f
+ b WriteProtectError /* Bad access */
+60: mfspr r3,DMISS /* Get address */
+ mfsrin r3,r3 /* Get segment register */
+ andis. r3,r3,0x4000 /* If Ks==0, OK */
+ beq+ 70f
+ b WriteProtectError /* Bad access */
+70: ori r1,r1,0x180 /* Set changed, accessed */
+ stw r1,4(r2) /* Update PTE in memory */
+ b 20b
+
+/*
+ * These routines are error paths/continuations of the exception
+ * handlers above. They are placed here to avoid the problems
+ * of only 0x100 bytes per exception handler.
+ */
+
+/* Invalid address */
+InstructionAddressInvalid:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
+ b 10f
+
+/* Fetch from guarded or no-access page */
+InstructionFetchError:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x0800 /* Set bit 4 -> protection error */
+10: mtspr DSISR,r1
+ mtctr r0 /* Restore CTR */
+ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
+ mtspr SRR1,r2
+ mfspr r1,IMISS /* Get failing address */
+ rlwinm. r2,r2,0,31,31 /* Check for little endian access */
+ beq 20f /* Jump if big endian */
+ xori r1,r1,3
+20: mtspr DAR,r1 /* Set fault address */
+ mfmsr r0 /* Restore "normal" registers */
+ xoris r0,r0,MSR_TGPR>>16
+ mtcrf 0x80,r3 /* Restore CR0 */
+ ori r0,r0,MSR_FP /* Need to keep FP enabled */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0
+ b InstructionAccess
+
+/* Invalid address */
+DataAddressInvalid:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
+ b 10f
+
+/* Write to read-only space */
+WriteProtectError:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x0800 /* Set bit 4 -> protection error */
+10: mtspr DSISR,r1
+ mtctr r0 /* Restore CTR */
+ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
+ mtspr SRR1,r2
+ mfspr r1,DMISS /* Get failing address */
+ rlwinm. r2,r2,0,31,31 /* Check for little endian access */
+ beq 20f /* Jump if big endian */
+ xori r1,r1,3
+20: mtspr DAR,r1 /* Set fault address */
+ mfmsr r0 /* Restore "normal" registers */
+ xoris r0,r0,MSR_TGPR>>16
+ mtcrf 0x80,r3 /* Restore CR0 */
+ ori r0,r0,MSR_FP /* Need to keep FP enabled */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0
+ b DataAccess
+
+/*
+ * Flush instruction cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_instruction_cache)
+ mflr r5
+ bl _EXTERN(flush_data_cache)
+ mfspr r3,HID0 /* Caches are controlled by this register */
+ li r4,0
+ ori r4,r4,(HID0_ICE|HID0_ICFI)
+ or r3,r3,r4 /* Need to enable+invalidate to clear */
+ mtspr HID0,r3
+ andc r3,r3,r4
+ ori r3,r3,HID0_ICE /* Enable cache */
+ mtspr HID0,r3
+ mtlr r5
+ blr
+
+/*
+ * Flush data cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_data_cache)
+ BUMP(__Cache_Flushes)
+ lis r3,cache_is_copyback@ha
+ lwz r3,cache_is_copyback@l(r3)
+ cmpi 0,r3,0
+ beq 10f
+/* When DATA CACHE is copy-back */
+ lis r3,cache_flush_buffer@h
+ ori r3,r3,cache_flush_buffer@l
+ li r4,NUM_CACHE_LINES
+ mtctr r4
+00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */
+ addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
+ bdnz 00b
+10: blr
+
+/*
+ * Flush a particular page from the DATA cache
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ * void flush_page(void *page)
+ */
+_GLOBAL(flush_page)
+ li r4,0x0FFF
+ andc r3,r3,r4 /* Get page base address */
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+00: dcbf 0,r3 /* Clear line */
+ icbi 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 00b
+ blr
+
+/*
+ * This routine switches between two different tasks. The process
+ * state of one is saved on its kernel stack. Then the state
+ * of the other is restored from its kernel stack. The memory
+ * management hardware is updated to the second process's state.
+ * Finally, we can return to the second process, via the 'return'.
+ *
+ * Note: there are two ways to get to the "going out" portion
+ * of this code; either by coming in via the entry (_switch)
+ * or via "fork" which must set up an environment equivalent
+ * to the "_switch" path. If you change this (or in particular, the
+ * SAVE_REGS macro), you'll have to change the fork code also.
+ *
+ * The code which creates the new task context is in 'copy_thread'
+ * in arch/ppc/kernel/process.c
+ */
+_GLOBAL(_switch)
+ mtspr SPR0,r1 /* SAVE_REGS prologue */
+ mtspr SPR1,r2
+ mflr r2 /* Return to switch caller */
+ mtspr SPR2,r2
+ mfmsr r2
+ mtspr SPR3,r2
+ SAVE_REGS(0x0FF0)
+ SYNC()
+ stw r1,KSP(r3) /* Set old stack pointer */
+ BUMP(__Context_Switches)
+ lwz r1,KSP(r4) /* Load new stack pointer */
+ CHECK_STACK()
+ lwz r0,MMU_SEG0(r4)
+ mtsr SR0,r0
+ lwz r0,MMU_SEG1(r4)
+ mtsr SR1,r0
+ lwz r0,MMU_SEG2(r4)
+ mtsr SR2,r0
+ lwz r0,MMU_SEG3(r4)
+ mtsr SR3,r0
+ lwz r0,MMU_SEG4(r4)
+ mtsr SR4,r0
+ lwz r0,MMU_SEG5(r4)
+ mtsr SR5,r0
+ lwz r0,MMU_SEG6(r4)
+ mtsr SR6,r0
+ lwz r0,MMU_SEG7(r4)
+ mtsr SR7,r0
+ lwz r0,MMU_SEG8(r4)
+ mtsr SR8,r0
+ lwz r0,MMU_SEG9(r4)
+ mtsr SR9,r0
+ lwz r0,MMU_SEG10(r4)
+ mtsr SR10,r0
+ lwz r0,MMU_SEG11(r4)
+ mtsr SR11,r0
+ lwz r0,MMU_SEG12(r4)
+ mtsr SR12,r0
+ lwz r0,MMU_SEG13(r4)
+ mtsr SR13,r0
+ lwz r0,MMU_SEG14(r4)
+ mtsr SR14,r0
+ lwz r0,MMU_SEG15(r4)
+ mtsr SR15,r0
+ tlbia /* Invalidate entire TLB */
+ BUMP(__TLBIAs)
+ bl _EXTERN(flush_instruction_cache)
+#ifdef TLB_STATS
+/* TEMP */
+ lis r2,DataLoadTLB_trace_ptr@h
+ ori r2,r2,DataLoadTLB_trace_ptr@l
+ lis r3,0x9000
+ lwz r4,0(r2)
+ or r4,r4,r3
+ li r0,0
+ stw r0,0(r4)
+ stw r0,4(r4)
+ stw r0,8(r4)
+ stw r0,12(r4)
+ addi r4,r4,4
+ cmpl 0,r4,r2
+ blt 00f
+ lis r4,DataLoadTLB_trace_buf@h
+ ori r4,r4,DataLoadTLB_trace_buf@l
+00: stw r4,0(r2)
+/* TEMP */
+#endif
+#if 0
+ lwz r2,_NIP(r1) /* Force TLB/MMU hit */
+ lwz r2,0(r2)
+#endif
+ RETURN_FROM_INT(0xF000)
+
+
+/*
+ * This routine is just here to keep GCC happy - sigh...
+ */
+_GLOBAL(__main)
+ blr
+
+#ifdef DO_TRAP_TRACE
+check_trace:
+ sync /* Force all writes out */
+ lwz r2,-8(r1)
+ andi. r2,r2,MSR_PR
+ bne 99f
+ lwz r2,-32(r1)
+ lwz r3,-16(r1)
+ cmp 0,r2,r3
+ bne 99f
+ andi. r2,r2,0x7FFF
+ cmpi 0,r2,0x0C00
+ bge 99f
+ lwz r2,-32+4(r1)
+ lwz r3,-16+4(r1)
+ cmp 0,r2,r3
+ bne 99f
+ lwz r2,-32+8(r1)
+ lwz r3,-16+8(r1)
+ cmp 0,r2,r3
+ bne 99f
+ lwz r2,-32(r1)
+ lwz r3,-16(r1)
+ cmp 0,r2,r3
+ bne 99f
+ andi. r2,r2,0x7FFF
+ cmpi 0,r2,0x0600
+ beq 00f
+ lwz r2,-32+12(r1)
+ lwz r3,-16+12(r1)
+ cmp 0,r2,r3
+ bne 99f
+00: li r2,0x7653
+ stw r2,0(r1)
+ b 00b
+99: blr
+#endif
+
+ .data
+ .globl sdata
+sdata:
+ .space 2*4096
+sys_stack:
+ .space 2*4096
+CPU1_stack:
+
+ .globl empty_zero_page
+empty_zero_page:
+ .space 4096
+
+ .globl swapper_pg_dir
+swapper_pg_dir:
+ .space 4096
+
+/*
+ * 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.
+ */
+ .globl cmd_line
+cmd_line:
+ .space 512
+
+#ifdef STATS
+/*
+ * Miscellaneous statistics - gathered just for performance info
+ */
+
+ .globl _INTR_stats
+_INTR_stats:
+__Instruction_TLB_Misses:
+ .long 0,0 /* Instruction TLB misses */
+__DataLoad_TLB_Misses:
+ .long 0,0 /* Data [load] TLB misses */
+__DataStore_TLB_Misses:
+ .long 0,0 /* Data [store] TLB misses */
+__Instruction_Page_Faults:
+ .long 0,0 /* Instruction page faults */
+__Data_Page_Faults:
+ .long 0,0 /* Data page faults */
+__Cache_Flushes:
+ .long 0,0 /* Explicit cache flushes */
+__Context_Switches:
+ .long 0,0 /* Context switches */
+__Hardware_Interrupts:
+ .long 0,0 /* I/O interrupts (disk, timer, etc) */
+ .globl __TLBIAs
+__TLBIAs:
+ .long 0,0 /* TLB cache forceably flushed */
+ .globl __TLBIEs
+__TLBIEs:
+ .long 0,0 /* Specific TLB entry flushed */
+#endif
+
+/*
+ * This location is used to break any outstanding "lock"s when
+ * changing contexts.
+ */
+_break_lwarx: .long 0
+
+/*
+ * Various trace buffers
+ */
+#ifdef DO_TRAP_TRACE
+ .data
+_TRAP_TRACE: .space 32*1024
+_TRAP_ptr: .long _TRAP_TRACE
+ .text
+#endif
+
+#ifdef DO_TLB_TRACE
+ .data
+_TLB_TRACE: .space 128*1024
+_TLB_ptr: .long _TLB_TRACE
+ .text
+#endif
+
+#ifdef DO_RFI_TRACE
+ .data
+_RFI_DATA: .space 128*1024
+_RFI_ptr: .long _RFI_DATA
+ .text
+#endif
+
diff --git a/arch/ppc/kernel/include/elf/ChangeLog b/arch/ppc/kernel/include/elf/ChangeLog
new file mode 100644
index 000000000..b4e7bd3ad
--- /dev/null
+++ b/arch/ppc/kernel/include/elf/ChangeLog
@@ -0,0 +1,155 @@
+Tue Jun 20 10:18:28 1995 Jeff Law (law@snake.cs.utah.edu)
+
+ * hppa.h (CPU_PA_RISC1_0): Protect from redefinitions.
+ (CPU_PA_RISC1_1): Likewise.
+
+Wed Mar 8 18:14:37 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+
+ * ppc.h: New file for PowerPC support.
+
+Tue Feb 14 13:59:13 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+
+ * common.h (EM_PPC): Use official value of 20, not 17.
+ (EM_PPC_OLD): Define this to be the old value of EM_PPC.
+
+
+Tue Jan 24 09:40:59 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+
+ * common.h (EM_PPC): New macro, PowerPC machine id.
+
+Tue Jan 17 10:51:38 1995 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * mips.h (SHT_MIPS_MSYM, SHT_MIPS_DWARF, SHT_MIPS_EVENTS): Define.
+
+
+Mon Oct 17 13:43:59 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
+
+ * internal.h (Elf_Internal_Shdr): Remove rawdata and size fields.
+ Add bfd_section field.
+
+Tue May 24 16:11:50 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * mips.h (Elf32_External_gptab): Define.
+
+Mon May 16 13:22:04 1994 Jeff Law (law@snake.cs.utah.edu)
+
+ * common.h (EM_HPPA): Delete.
+ (EM_PARISC): Add.
+ * hppa.h: New file.
+
+Mon May 9 13:27:03 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * common.h (SHN_LORESERVE): Rename from SHN_LORESERV.
+ (ELF32_R_TYPE, ELF32_R_INFO): Don't rely on size of unsigned char.
+ (ELF64_R_TYPE): Don't rely on size of unsigned long.
+
+Mon Apr 25 15:53:09 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * internal.h (Elf_Internal_Shdr): Use PTR, not void *.
+
+Fri Mar 11 00:34:59 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
+
+ * mips.h (SHN_MIPS_TEXT, SHN_MIPS_DATA): Define.
+
+Sat Mar 5 14:08:54 1994 Peter Schauer (pes@regent.e-technik.tu-muenchen.de)
+
+ * internal.h: Remove Elf32_*, Elf64_* typedefs. These names
+ cause conflicts with system headers, e.g. link.h in gdb/solib.c.
+ Combine 32- and 64-bit versions of *_Internal_Dyn.
+ * common.h: Replace uses of Elf64_Word, Elf64_Xword typedefs
+ by their expansion.
+ * mips.h: Replace uses of Elf32_Word, Elf32_Sword, Elf32_Addr
+ typedefs by their expansion. Add DT_MIPS_RLD_MAP definition.
+
+Fri Feb 18 10:39:54 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * common.h (EM_CYGNUS_POWERPC): Define. This may be temporary,
+ depending upon how quickly I can find a real PowerPC ABI.
+
+Mon Feb 7 08:27:13 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * internal.h: Change HOST_64_BIT to BFD_HOST_64_BIT.
+
+Wed Feb 2 14:12:18 1994 Jim Kingdon (kingdon@lioth.cygnus.com)
+
+ * common.h: Add comments regarding value of EM_HPPA and how to
+ pick an unofficial value.
+
+Wed Nov 17 17:14:26 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * mips.h (SHT_MIPS_OPTIONS): Define.
+
+Mon Nov 8 17:57:00 1993 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+
+ * mips.h: Added some more MIPS ABI macro definitions.
+
+Wed Nov 3 22:07:17 1993 Ken Raeburn (raeburn@rtl.cygnus.com)
+
+ * common.h (EM_MIPS_RS4_BE): New macro.
+
+Tue Oct 12 07:28:18 1993 Ian Lance Taylor (ian@cygnus.com)
+
+ * mips.h: New file. MIPS ABI specific information.
+
+Mon Jun 21 13:13:43 1993 Ken Raeburn (raeburn@poseidon.cygnus.com)
+
+ * internal.h: Combined 32- and 64-bit versions of all structures
+ except *_Internal_Dyn. This will simply the assembler interface,
+ and some bfd code.
+
+Tue May 25 02:00:16 1993 Ken Raeburn (raeburn@cambridge.cygnus.com)
+
+ * external.h, internal.h, common.h: Added 64-bit versions of some
+ structures and macros. Renamed old versions to put "32" in the
+ name. Some are unchanged.
+
+Thu Apr 29 12:12:20 1993 Ken Raeburn (raeburn@deneb.cygnus.com)
+
+ * common.h (EM_HPPA, NT_VERSION, STN_UNDEF, DT_*): New macros.
+ * external.h (Elf_External_Dyn): New type.
+
+ * internal.h (Elf_Internal_Shdr): New field `size'.
+ (Elf_Internal_Dyn): New type.
+
+Tue Apr 20 16:03:45 1993 Fred Fish (fnf@cygnus.com)
+
+ * dwarf.h (LANG_CHILL): Change value to one randomly picked in
+ the user defined range, to reduce probability of collisions.
+
+Sun Nov 15 09:34:02 1992 Fred Fish (fnf@cygnus.com)
+
+ * dwarf.h (AT_src_coords): Whitespace change only.
+ * dwarf.h (AT_body_begin, AT_body_end, LANG_MODULA2):
+ Add from latest gcc.
+ * dwarf.h (LANG_CHILL): Add as GNU extension.
+
+Sat Aug 1 13:46:53 1992 Fred Fish (fnf@cygnus.com)
+
+ * dwarf.h: Replace with current version from gcc distribution.
+
+Fri Jun 19 19:05:09 1992 John Gilmore (gnu at cygnus.com)
+
+ * internal.h: Add real struct tags to all the Type_Defs, so they
+ can be used in prototypes where the Type_Defs are not known.
+
+Fri Apr 3 20:58:58 1992 Mark Eichin (eichin at cygnus.com)
+
+ * common.h: added ELF_R_{SYM,TYPE,INFO} for handling relocation
+ info
+ added EM_MIPS, and corrected value of EM_860 based on System V ABI
+ manual.
+
+ * external.h: added Elf_External_{Rel,Rela}.
+
+ * internal.h: added Elf_Internal_{Rel,Rela}.
+ added rawdata to Elf_Internal_Shdr.
+
+Sat Nov 30 20:43:59 1991 Steve Chamberlain (sac at rtl.cygnus.com)
+
+ * common.h, dwarf.h, external.h, internal.h, ChangeLog; moved from
+ ../elf-<foo>
+
+
+Local Variables:
+version-control: never
+End:
diff --git a/arch/ppc/kernel/include/elf/common.h b/arch/ppc/kernel/include/elf/common.h
new file mode 100644
index 000000000..a9bce87d6
--- /dev/null
+++ b/arch/ppc/kernel/include/elf/common.h
@@ -0,0 +1,232 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that are common to both the internal and external representations.
+ For example, ELFMAG0 is the byte 0x7F in both the internal (in-memory)
+ and external (in-file) representations. */
+
+
+/* Fields in e_ident[] */
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7F /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+#define EI_CLASS 4 /* File class */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+
+#define EI_DATA 5 /* Data encoding */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+
+#define EI_VERSION 6 /* File version */
+
+#define EI_PAD 7 /* Start of padding bytes */
+
+
+/* Values for e_type, which identifies the object file type */
+
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* Relocatable file */
+#define ET_EXEC 2 /* Executable file */
+#define ET_DYN 3 /* Shared object file */
+#define ET_CORE 4 /* Core file */
+#define ET_LOPROC 0xFF00 /* Processor-specific */
+#define ET_HIPROC 0xFFFF /* Processor-specific */
+
+/* Values for e_machine, which identifies the architecture */
+
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
+
+#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
+
+#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */
+
+#define EM_PARISC 15 /* HPPA */
+#define EM_PPC 20 /* PowerPC */
+
+/* If it is necessary to assign new unofficial EM_* values, please pick large
+ random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision
+ with official or non-GNU unofficial values. */
+
+/* Cygnus PowerPC ELF backend. Written in the absence of an ABI. */
+#define EM_CYGNUS_POWERPC 0x9025
+
+/* Old version of PowerPC, this should be removed shortly. */
+#define EM_PPC_OLD 17
+
+
+/* Values for e_version */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+
+/* Values for program header, p_type field */
+
+#define PT_NULL 0 /* Program header table entry unused */
+#define PT_LOAD 1 /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define PT_INTERP 3 /* Program interpreter */
+#define PT_NOTE 4 /* Auxiliary information */
+#define PT_SHLIB 5 /* Reserved, unspecified semantics */
+#define PT_PHDR 6 /* Entry for header table itself */
+#define PT_LOPROC 0x70000000 /* Processor-specific */
+#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */
+
+/* Program segment permissions, in program header p_flags field */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */
+
+/* Values for section header, sh_type field */
+
+#define SHT_NULL 0 /* Section header table entry unused */
+#define SHT_PROGBITS 1 /* Program specific (private) data */
+#define SHT_SYMTAB 2 /* Link editing symbol table */
+#define SHT_STRTAB 3 /* A string table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_HASH 5 /* A symbol hash table */
+#define SHT_DYNAMIC 6 /* Information for dynamic linking */
+#define SHT_NOTE 7 /* Information that marks file */
+#define SHT_NOBITS 8 /* Section occupies no space in file */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_SHLIB 10 /* Reserved, unspecified semantics */
+#define SHT_DYNSYM 11 /* Dynamic linking symbol table */
+#define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */
+#define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */
+#define SHT_LOUSER 0x80000000 /* Application-specific semantics */
+#define SHT_HIUSER 0x8FFFFFFF /* Application-specific semantics */
+
+/* Values for section header, sh_flags field */
+
+#define SHF_WRITE (1 << 0) /* Writable data during execution */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable machine instructions */
+#define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */
+
+/* Values of note segment descriptor types for core files. */
+
+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
+
+/* Values of note segment descriptor types for object files. */
+/* (Only for hppa right now. Should this be moved elsewhere?) */
+
+#define NT_VERSION 1 /* Contains a version string. */
+
+/* These three macros disassemble and assemble a symbol table st_info field,
+ which contains the symbol binding and symbol type. The STB_ and STT_
+ defines identify the binding and type. */
+
+#define ELF_ST_BIND(val) (((unsigned int)(val)) >> 4)
+#define ELF_ST_TYPE(val) ((val) & 0xF)
+#define ELF_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xF))
+
+#define STN_UNDEF 0 /* undefined symbol index */
+
+#define STB_LOCAL 0 /* Symbol not visible outside obj */
+#define STB_GLOBAL 1 /* Symbol visible outside obj */
+#define STB_WEAK 2 /* Like globals, lower precedence */
+#define STB_LOPROC 13 /* Application-specific semantics */
+#define STB_HIPROC 15 /* Application-specific semantics */
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol gives a file name */
+#define STT_LOPROC 13 /* Application-specific semantics */
+#define STT_HIPROC 15 /* Application-specific semantics */
+
+/* Special section indices, which may show up in st_shndx fields, among
+ other places. */
+
+#define SHN_UNDEF 0 /* Undefined section reference */
+#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */
+#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */
+#define SHN_HIPROC 0xFF1F /* End range of appl-specific */
+#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */
+#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */
+#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */
+
+/* relocation info handling macros */
+
+#define ELF32_R_SYM(i) ((i) >> 8)
+#define ELF32_R_TYPE(i) ((i) & 0xff)
+#define ELF32_R_INFO(s,t) (((s) << 8) + ((t) & 0xff))
+
+#define ELF64_R_SYM(i) ((i) >> 32)
+#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+#define ELF64_R_INFO(s,t) (((bfd_vma) (s) << 32) + (bfd_vma) (t))
+
+/* Dynamic section tags */
+
+#define DT_NULL 0
+#define DT_NEEDED 1
+#define DT_PLTRELSZ 2
+#define DT_PLTGOT 3
+#define DT_HASH 4
+#define DT_STRTAB 5
+#define DT_SYMTAB 6
+#define DT_RELA 7
+#define DT_RELASZ 8
+#define DT_RELAENT 9
+#define DT_STRSZ 10
+#define DT_SYMENT 11
+#define DT_INIT 12
+#define DT_FINI 13
+#define DT_SONAME 14
+#define DT_RPATH 15
+#define DT_SYMBOLIC 16
+#define DT_REL 17
+#define DT_RELSZ 18
+#define DT_RELENT 19
+#define DT_PLTREL 20
+#define DT_DEBUG 21
+#define DT_TEXTREL 22
+#define DT_JMPREL 23
+#define DT_LOPROC 0x70000000
+#define DT_HIPROC 0x7fffffff
diff --git a/arch/ppc/kernel/include/elf/dwarf.h b/arch/ppc/kernel/include/elf/dwarf.h
new file mode 100644
index 000000000..bc9723ae0
--- /dev/null
+++ b/arch/ppc/kernel/include/elf/dwarf.h
@@ -0,0 +1,314 @@
+/* Declarations and definitions of codes relating to the DWARF symbolic
+ debugging information format.
+
+ Written by Ron Guilmette (rfg@ncd.com)
+
+Copyright (C) 1992 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file is derived from the DWARF specification (a public document)
+ Revision 1.0.1 (April 8, 1992) developed by the UNIX International
+ Programming Languages Special Interest Group (UI/PLSIG) and distributed
+ by UNIX International. Copies of this specification are available from
+ UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+*/
+
+/* Tag names and codes. */
+
+enum dwarf_tag {
+ TAG_padding = 0x0000,
+ TAG_array_type = 0x0001,
+ TAG_class_type = 0x0002,
+ TAG_entry_point = 0x0003,
+ TAG_enumeration_type = 0x0004,
+ TAG_formal_parameter = 0x0005,
+ TAG_global_subroutine = 0x0006,
+ TAG_global_variable = 0x0007,
+ /* 0x0008 -- reserved */
+ /* 0x0009 -- reserved */
+ TAG_label = 0x000a,
+ TAG_lexical_block = 0x000b,
+ TAG_local_variable = 0x000c,
+ TAG_member = 0x000d,
+ /* 0x000e -- reserved */
+ TAG_pointer_type = 0x000f,
+ TAG_reference_type = 0x0010,
+ TAG_compile_unit = 0x0011,
+ TAG_string_type = 0x0012,
+ TAG_structure_type = 0x0013,
+ TAG_subroutine = 0x0014,
+ TAG_subroutine_type = 0x0015,
+ TAG_typedef = 0x0016,
+ TAG_union_type = 0x0017,
+ TAG_unspecified_parameters = 0x0018,
+ TAG_variant = 0x0019,
+ TAG_common_block = 0x001a,
+ TAG_common_inclusion = 0x001b,
+ TAG_inheritance = 0x001c,
+ TAG_inlined_subroutine = 0x001d,
+ TAG_module = 0x001e,
+ TAG_ptr_to_member_type = 0x001f,
+ TAG_set_type = 0x0020,
+ TAG_subrange_type = 0x0021,
+ TAG_with_stmt = 0x0022,
+
+ /* GNU extensions */
+
+ TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */
+ TAG_namelist = 0x8001, /* For Fortran 90 */
+ TAG_function_template = 0x8002, /* for C++ */
+ TAG_class_template = 0x8003 /* for C++ */
+};
+
+#define TAG_lo_user 0x8000 /* implementation-defined range start */
+#define TAG_hi_user 0xffff /* implementation-defined range end */
+#define TAG_source_file TAG_compile_unit /* for backward compatibility */
+
+/* Form names and codes. */
+
+enum dwarf_form {
+ FORM_ADDR = 0x1,
+ FORM_REF = 0x2,
+ FORM_BLOCK2 = 0x3,
+ FORM_BLOCK4 = 0x4,
+ FORM_DATA2 = 0x5,
+ FORM_DATA4 = 0x6,
+ FORM_DATA8 = 0x7,
+ FORM_STRING = 0x8
+};
+
+/* Attribute names and codes. */
+
+enum dwarf_attribute {
+ AT_sibling = (0x0010|FORM_REF),
+ AT_location = (0x0020|FORM_BLOCK2),
+ AT_name = (0x0030|FORM_STRING),
+ AT_fund_type = (0x0050|FORM_DATA2),
+ AT_mod_fund_type = (0x0060|FORM_BLOCK2),
+ AT_user_def_type = (0x0070|FORM_REF),
+ AT_mod_u_d_type = (0x0080|FORM_BLOCK2),
+ AT_ordering = (0x0090|FORM_DATA2),
+ AT_subscr_data = (0x00a0|FORM_BLOCK2),
+ AT_byte_size = (0x00b0|FORM_DATA4),
+ AT_bit_offset = (0x00c0|FORM_DATA2),
+ AT_bit_size = (0x00d0|FORM_DATA4),
+ /* (0x00e0|FORM_xxxx) -- reserved */
+ AT_element_list = (0x00f0|FORM_BLOCK4),
+ AT_stmt_list = (0x0100|FORM_DATA4),
+ AT_low_pc = (0x0110|FORM_ADDR),
+ AT_high_pc = (0x0120|FORM_ADDR),
+ AT_language = (0x0130|FORM_DATA4),
+ AT_member = (0x0140|FORM_REF),
+ AT_discr = (0x0150|FORM_REF),
+ AT_discr_value = (0x0160|FORM_BLOCK2),
+ /* (0x0170|FORM_xxxx) -- reserved */
+ /* (0x0180|FORM_xxxx) -- reserved */
+ AT_string_length = (0x0190|FORM_BLOCK2),
+ AT_common_reference = (0x01a0|FORM_REF),
+ AT_comp_dir = (0x01b0|FORM_STRING),
+ AT_const_value_string = (0x01c0|FORM_STRING),
+ AT_const_value_data2 = (0x01c0|FORM_DATA2),
+ AT_const_value_data4 = (0x01c0|FORM_DATA4),
+ AT_const_value_data8 = (0x01c0|FORM_DATA8),
+ AT_const_value_block2 = (0x01c0|FORM_BLOCK2),
+ AT_const_value_block4 = (0x01c0|FORM_BLOCK4),
+ AT_containing_type = (0x01d0|FORM_REF),
+ AT_default_value_addr = (0x01e0|FORM_ADDR),
+ AT_default_value_data2 = (0x01e0|FORM_DATA2),
+ AT_default_value_data4 = (0x01e0|FORM_DATA4),
+ AT_default_value_data8 = (0x01e0|FORM_DATA8),
+ AT_default_value_string = (0x01e0|FORM_STRING),
+ AT_friends = (0x01f0|FORM_BLOCK2),
+ AT_inline = (0x0200|FORM_STRING),
+ AT_is_optional = (0x0210|FORM_STRING),
+ AT_lower_bound_ref = (0x0220|FORM_REF),
+ AT_lower_bound_data2 = (0x0220|FORM_DATA2),
+ AT_lower_bound_data4 = (0x0220|FORM_DATA4),
+ AT_lower_bound_data8 = (0x0220|FORM_DATA8),
+ AT_private = (0x0240|FORM_STRING),
+ AT_producer = (0x0250|FORM_STRING),
+ AT_program = (0x0230|FORM_STRING),
+ AT_protected = (0x0260|FORM_STRING),
+ AT_prototyped = (0x0270|FORM_STRING),
+ AT_public = (0x0280|FORM_STRING),
+ AT_pure_virtual = (0x0290|FORM_STRING),
+ AT_return_addr = (0x02a0|FORM_BLOCK2),
+ AT_abstract_origin = (0x02b0|FORM_REF),
+ AT_start_scope = (0x02c0|FORM_DATA4),
+ AT_stride_size = (0x02e0|FORM_DATA4),
+ AT_upper_bound_ref = (0x02f0|FORM_REF),
+ AT_upper_bound_data2 = (0x02f0|FORM_DATA2),
+ AT_upper_bound_data4 = (0x02f0|FORM_DATA4),
+ AT_upper_bound_data8 = (0x02f0|FORM_DATA8),
+ AT_virtual = (0x0300|FORM_STRING),
+
+ /* GNU extensions. */
+
+ AT_sf_names = (0x8000|FORM_DATA4),
+ AT_src_info = (0x8010|FORM_DATA4),
+ AT_mac_info = (0x8020|FORM_DATA4),
+ AT_src_coords = (0x8030|FORM_DATA4),
+ AT_body_begin = (0x8040|FORM_ADDR),
+ AT_body_end = (0x8050|FORM_ADDR)
+};
+
+#define AT_lo_user 0x8000 /* implementation-defined range start */
+#define AT_hi_user 0xffff /* implementation-defined range end */
+
+/* Location atom names and codes. */
+
+enum dwarf_location_atom {
+ OP_REG = 0x01,
+ OP_BASEREG = 0x02,
+ OP_ADDR = 0x03,
+ OP_CONST = 0x04,
+ OP_DEREF2 = 0x05,
+ OP_DEREF4 = 0x06,
+ OP_ADD = 0x07
+};
+
+#define OP_LO_USER 0x80 /* implementation-defined range start */
+#define OP_HI_USER 0xff /* implementation-defined range end */
+
+/* Fundamental type names and codes. */
+
+enum dwarf_fundamental_type {
+ FT_char = 0x0001,
+ FT_signed_char = 0x0002,
+ FT_unsigned_char = 0x0003,
+ FT_short = 0x0004,
+ FT_signed_short = 0x0005,
+ FT_unsigned_short = 0x0006,
+ FT_integer = 0x0007,
+ FT_signed_integer = 0x0008,
+ FT_unsigned_integer = 0x0009,
+ FT_long = 0x000a,
+ FT_signed_long = 0x000b,
+ FT_unsigned_long = 0x000c,
+ FT_pointer = 0x000d, /* an alias for (void *) */
+ FT_float = 0x000e,
+ FT_dbl_prec_float = 0x000f,
+ FT_ext_prec_float = 0x0010, /* breaks "classic" svr4 SDB */
+ FT_complex = 0x0011, /* breaks "classic" svr4 SDB */
+ FT_dbl_prec_complex = 0x0012, /* breaks "classic" svr4 SDB */
+ /* 0x0013 -- reserved */
+ FT_void = 0x0014,
+ FT_boolean = 0x0015, /* breaks "classic" svr4 SDB */
+ FT_ext_prec_complex = 0x0016, /* breaks "classic" svr4 SDB */
+ FT_label = 0x0017,
+
+ /* GNU extensions
+ The low order byte must indicate the size (in bytes) for the type.
+ All of these types will probably break "classic" svr4 SDB */
+
+ FT_long_long = 0x8008,
+ FT_signed_long_long = 0x8108,
+ FT_unsigned_long_long = 0x8208,
+
+ FT_int8 = 0x9001,
+ FT_signed_int8 = 0x9101,
+ FT_unsigned_int8 = 0x9201,
+ FT_int16 = 0x9302,
+ FT_signed_int16 = 0x9402,
+ FT_unsigned_int16 = 0x9502,
+ FT_int32 = 0x9604,
+ FT_signed_int32 = 0x9704,
+ FT_unsigned_int32 = 0x9804,
+ FT_int64 = 0x9908,
+ FT_signed_int64 = 0x9a08,
+ FT_unsigned_int64 = 0x9b08,
+
+ FT_real32 = 0xa004,
+ FT_real64 = 0xa108,
+ FT_real96 = 0xa20c,
+ FT_real128 = 0xa310
+};
+
+#define FT_lo_user 0x8000 /* implementation-defined range start */
+#define FT_hi_user 0xffff /* implementation defined range end */
+
+/* Type modifier names and codes. */
+
+enum dwarf_type_modifier {
+ MOD_pointer_to = 0x01,
+ MOD_reference_to = 0x02,
+ MOD_const = 0x03,
+ MOD_volatile = 0x04
+};
+
+#define MOD_lo_user 0x80 /* implementation-defined range start */
+#define MOD_hi_user 0xff /* implementation-defined range end */
+
+/* Array ordering names and codes. */
+
+enum dwarf_array_dim_ordering {
+ ORD_row_major = 0,
+ ORD_col_major = 1
+};
+
+/* Array subscript format names and codes. */
+
+enum dwarf_subscr_data_formats {
+ FMT_FT_C_C = 0x0,
+ FMT_FT_C_X = 0x1,
+ FMT_FT_X_C = 0x2,
+ FMT_FT_X_X = 0x3,
+ FMT_UT_C_C = 0x4,
+ FMT_UT_C_X = 0x5,
+ FMT_UT_X_C = 0x6,
+ FMT_UT_X_X = 0x7,
+ FMT_ET = 0x8
+};
+
+/* Derived from above for ease of use. */
+
+#define FMT_CODE(_FUNDAMENTAL_TYPE_P, _UB_CONST_P, _LB_CONST_P) \
+ (((_FUNDAMENTAL_TYPE_P) ? 0 : 4) \
+ | ((_UB_CONST_P) ? 0 : 2) \
+ | ((_LB_CONST_P) ? 0 : 1))
+
+/* Source language names and codes. */
+
+enum dwarf_source_language {
+ LANG_C89 = 0x00000001,
+ LANG_C = 0x00000002,
+ LANG_ADA83 = 0x00000003,
+ LANG_C_PLUS_PLUS = 0x00000004,
+ LANG_COBOL74 = 0x00000005,
+ LANG_COBOL85 = 0x00000006,
+ LANG_FORTRAN77 = 0x00000007,
+ LANG_FORTRAN90 = 0x00000008,
+ LANG_PASCAL83 = 0x00000009,
+ LANG_MODULA2 = 0x0000000a,
+
+ /* GNU extensions */
+
+ LANG_CHILL = 0x00009af3 /* random value for GNU Chill */
+};
+
+#define LANG_lo_user 0x00008000 /* implementation-defined range start */
+#define LANG_hi_user 0x0000ffff /* implementation-defined range end */
+
+/* Names and codes for GNU "macinfo" extension. */
+
+enum dwarf_macinfo_record_type {
+ MACINFO_start = 's',
+ MACINFO_resume = 'r',
+ MACINFO_define = 'd',
+ MACINFO_undef = 'u'
+};
diff --git a/arch/ppc/kernel/include/elf/external.h b/arch/ppc/kernel/include/elf/external.h
new file mode 100644
index 000000000..f2ab63e1e
--- /dev/null
+++ b/arch/ppc/kernel/include/elf/external.h
@@ -0,0 +1,190 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that describe how ELF is represented externally by the BFD library.
+ I.E. it describes the in-file representation of ELF. It requires
+ the elf-common.h file which contains the portions that are common to
+ both the internal and external representations. */
+
+/* The 64-bit stuff is kind of random. Perhaps someone will publish a
+ spec someday. */
+
+/* ELF Header (32-bit implementations) */
+
+typedef struct {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ unsigned char e_type[2]; /* Identifies object file type */
+ unsigned char e_machine[2]; /* Specifies required architecture */
+ unsigned char e_version[4]; /* Identifies object file version */
+ unsigned char e_entry[4]; /* Entry point virtual address */
+ unsigned char e_phoff[4]; /* Program header table file offset */
+ unsigned char e_shoff[4]; /* Section header table file offset */
+ unsigned char e_flags[4]; /* Processor-specific flags */
+ unsigned char e_ehsize[2]; /* ELF header size in bytes */
+ unsigned char e_phentsize[2]; /* Program header table entry size */
+ unsigned char e_phnum[2]; /* Program header table entry count */
+ unsigned char e_shentsize[2]; /* Section header table entry size */
+ unsigned char e_shnum[2]; /* Section header table entry count */
+ unsigned char e_shstrndx[2]; /* Section header string table index */
+} Elf32_External_Ehdr;
+
+typedef struct {
+ unsigned char e_ident[16]; /* ELF "magic number" */
+ unsigned char e_type[2]; /* Identifies object file type */
+ unsigned char e_machine[2]; /* Specifies required architecture */
+ unsigned char e_version[4]; /* Identifies object file version */
+ unsigned char e_entry[8]; /* Entry point virtual address */
+ unsigned char e_phoff[8]; /* Program header table file offset */
+ unsigned char e_shoff[8]; /* Section header table file offset */
+ unsigned char e_flags[4]; /* Processor-specific flags */
+ unsigned char e_ehsize[2]; /* ELF header size in bytes */
+ unsigned char e_phentsize[2]; /* Program header table entry size */
+ unsigned char e_phnum[2]; /* Program header table entry count */
+ unsigned char e_shentsize[2]; /* Section header table entry size */
+ unsigned char e_shnum[2]; /* Section header table entry count */
+ unsigned char e_shstrndx[2]; /* Section header string table index */
+} Elf64_External_Ehdr;
+
+/* Program header */
+
+typedef struct {
+ unsigned char p_type[4]; /* Identifies program segment type */
+ unsigned char p_offset[4]; /* Segment file offset */
+ unsigned char p_vaddr[4]; /* Segment virtual address */
+ unsigned char p_paddr[4]; /* Segment physical address */
+ unsigned char p_filesz[4]; /* Segment size in file */
+ unsigned char p_memsz[4]; /* Segment size in memory */
+ unsigned char p_flags[4]; /* Segment flags */
+ unsigned char p_align[4]; /* Segment alignment, file & memory */
+} Elf32_External_Phdr;
+
+typedef struct {
+ unsigned char p_type[4]; /* Identifies program segment type */
+ unsigned char p_flags[4]; /* Segment flags */
+ unsigned char p_offset[8]; /* Segment file offset */
+ unsigned char p_vaddr[8]; /* Segment virtual address */
+ unsigned char p_paddr[8]; /* Segment physical address */
+ unsigned char p_filesz[8]; /* Segment size in file */
+ unsigned char p_memsz[8]; /* Segment size in memory */
+ unsigned char p_align[8]; /* Segment alignment, file & memory */
+} Elf64_External_Phdr;
+
+/* Section header */
+
+typedef struct {
+ unsigned char sh_name[4]; /* Section name, index in string tbl */
+ unsigned char sh_type[4]; /* Type of section */
+ unsigned char sh_flags[4]; /* Miscellaneous section attributes */
+ unsigned char sh_addr[4]; /* Section virtual addr at execution */
+ unsigned char sh_offset[4]; /* Section file offset */
+ unsigned char sh_size[4]; /* Size of section in bytes */
+ unsigned char sh_link[4]; /* Index of another section */
+ unsigned char sh_info[4]; /* Additional section information */
+ unsigned char sh_addralign[4]; /* Section alignment */
+ unsigned char sh_entsize[4]; /* Entry size if section holds table */
+} Elf32_External_Shdr;
+
+typedef struct {
+ unsigned char sh_name[4]; /* Section name, index in string tbl */
+ unsigned char sh_type[4]; /* Type of section */
+ unsigned char sh_flags[8]; /* Miscellaneous section attributes */
+ unsigned char sh_addr[8]; /* Section virtual addr at execution */
+ unsigned char sh_offset[8]; /* Section file offset */
+ unsigned char sh_size[8]; /* Size of section in bytes */
+ unsigned char sh_link[4]; /* Index of another section */
+ unsigned char sh_info[4]; /* Additional section information */
+ unsigned char sh_addralign[8]; /* Section alignment */
+ unsigned char sh_entsize[8]; /* Entry size if section holds table */
+} Elf64_External_Shdr;
+
+/* Symbol table entry */
+
+typedef struct {
+ unsigned char st_name[4]; /* Symbol name, index in string tbl */
+ unsigned char st_value[4]; /* Value of the symbol */
+ unsigned char st_size[4]; /* Associated symbol size */
+ unsigned char st_info[1]; /* Type and binding attributes */
+ unsigned char st_other[1]; /* No defined meaning, 0 */
+ unsigned char st_shndx[2]; /* Associated section index */
+} Elf32_External_Sym;
+
+typedef struct {
+ unsigned char st_name[4]; /* Symbol name, index in string tbl */
+ unsigned char st_info[1]; /* Type and binding attributes */
+ unsigned char st_other[1]; /* No defined meaning, 0 */
+ unsigned char st_shndx[2]; /* Associated section index */
+ unsigned char st_value[8]; /* Value of the symbol */
+ unsigned char st_size[8]; /* Associated symbol size */
+} Elf64_External_Sym;
+
+/* Note segments */
+
+typedef struct {
+ unsigned char namesz[4]; /* Size of entry's owner string */
+ unsigned char descsz[4]; /* Size of the note descriptor */
+ unsigned char type[4]; /* Interpretation of the descriptor */
+ char name[1]; /* Start of the name+desc data */
+} Elf_External_Note;
+
+/* Relocation Entries */
+typedef struct {
+ unsigned char r_offset[4]; /* Location at which to apply the action */
+ unsigned char r_info[4]; /* index and type of relocation */
+} Elf32_External_Rel;
+
+typedef struct {
+ unsigned char r_offset[4]; /* Location at which to apply the action */
+ unsigned char r_info[4]; /* index and type of relocation */
+ unsigned char r_addend[4]; /* Constant addend used to compute value */
+} Elf32_External_Rela;
+
+typedef struct {
+ unsigned char r_offset[8]; /* Location at which to apply the action */
+ unsigned char r_info[8]; /* index and type of relocation */
+} Elf64_External_Rel;
+
+typedef struct {
+ unsigned char r_offset[8]; /* Location at which to apply the action */
+ unsigned char r_info[8]; /* index and type of relocation */
+ unsigned char r_addend[8]; /* Constant addend used to compute value */
+} Elf64_External_Rela;
+
+/* dynamic section structure */
+
+typedef struct {
+ unsigned char d_tag[4]; /* entry tag value */
+ union {
+ unsigned char d_val[4];
+ unsigned char d_ptr[4];
+ } d_un;
+} Elf32_External_Dyn;
+
+typedef struct {
+ unsigned char d_tag[8]; /* entry tag value */
+ union {
+ unsigned char d_val[8];
+ unsigned char d_ptr[8];
+ } d_un;
+} Elf64_External_Dyn;
diff --git a/arch/ppc/kernel/include/elf/hppa.h b/arch/ppc/kernel/include/elf/hppa.h
new file mode 100644
index 000000000..e3f70d23d
--- /dev/null
+++ b/arch/ppc/kernel/include/elf/hppa.h
@@ -0,0 +1,90 @@
+/* HPPA ELF support for BFD.
+ Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file holds definitions specific to the HPPA ELF ABI. Note
+ that most of this is not actually implemented by BFD. */
+
+/* Processor specific flags for the ELF header e_flags field. */
+
+/* Target processor IDs to be placed in the low 16 bits of the flags
+ field. Note these names are shared with SOM, and therefore do not
+ follow ELF naming conventions. */
+
+/* PA 1.0 big endian. */
+#ifndef CPU_PA_RISC1_0
+#define CPU_PA_RISC1_0 0x0000020b
+#endif
+
+/* PA 1.1 big endian. */
+#ifndef CPU_PA_RISC1_1
+#define CPU_PA_RISC1_1 0x00000210
+#endif
+
+/* PA 1.0 little endian (unsupported) is 0x0000028b. */
+/* PA 1.1 little endian (unsupported) is 0x00000290. */
+
+/* Trap null address dereferences. */
+#define ELF_PARISC_TRAPNIL 0x00010000
+
+/* .PARISC.archext section is present. */
+#define EF_PARISC_EXT 0x00020000
+
+/* Processor specific section types. */
+
+/* Holds the global offset table, a table of pointers to external
+ data. */
+#define SHT_PARISC_GOT SHT_LOPROC+0
+
+/* Nonloadable section containing information in architecture
+ extensions used by the code. */
+#define SHT_PARISC_ARCH SHT_LOPROC+1
+
+/* Section in which $global$ is defined. */
+#define SHT_PARISC_GLOBAL SHT_LOPROC+2
+
+/* Section holding millicode routines (mul, div, rem, dyncall, etc. */
+#define SHT_PARISC_MILLI SHT_LOPROC+3
+
+/* Section holding unwind information for use by debuggers. */
+#define SHT_PARISC_UNWIND SHT_LOPROC+4
+
+/* Section holding the procedure linkage table. */
+#define SHT_PARISC_PLT SHT_LOPROC+5
+
+/* Short initialized and uninitialized data. */
+#define SHT_PARISC_SDATA SHT_LOPROC+6
+#define SHT_PARISC_SBSS SHT_LOPROC+7
+
+/* Optional section holding argument location/relocation info. */
+#define SHT_PARISC_SYMEXTN SHT_LOPROC+8
+
+/* Option section for linker stubs. */
+#define SHT_PARISC_STUBS SHT_LOPROC+9
+
+/* Processor specific section flags. */
+
+/* This section is near the global data pointer and thus allows short
+ addressing modes to be used. */
+#define SHF_PARISC_SHORT 0x20000000
+
+/* Processor specific symbol types. */
+
+/* Millicode function entry point. */
+#define STT_PARISC_MILLICODE STT_LOPROC+0
+
diff --git a/arch/ppc/kernel/include/elf/internal.h b/arch/ppc/kernel/include/elf/internal.h
new file mode 100644
index 000000000..fb6302937
--- /dev/null
+++ b/arch/ppc/kernel/include/elf/internal.h
@@ -0,0 +1,173 @@
+/* ELF support for BFD.
+ Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+
+ Written by Fred Fish @ Cygnus Support, from information published
+ in "UNIX System V Release 4, Programmers Guide: ANSI C and
+ Programming Support Tools".
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This file is part of ELF support for BFD, and contains the portions
+ that describe how ELF is represented internally in the BFD library.
+ I.E. it describes the in-memory representation of ELF. It requires
+ the elf-common.h file which contains the portions that are common to
+ both the internal and external representations. */
+
+
+/* NOTE that these structures are not kept in the same order as they appear
+ in the object file. In some cases they've been reordered for more optimal
+ packing under various circumstances. */
+
+/* ELF Header */
+
+#define EI_NIDENT 16 /* Size of e_ident[] */
+
+typedef struct elf_internal_ehdr {
+ unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
+ bfd_vma e_entry; /* Entry point virtual address */
+ bfd_signed_vma e_phoff; /* Program header table file offset */
+ bfd_signed_vma e_shoff; /* Section header table file offset */
+ unsigned long e_version; /* Identifies object file version */
+ unsigned long e_flags; /* Processor-specific flags */
+ unsigned short e_type; /* Identifies object file type */
+ unsigned short e_machine; /* Specifies required architecture */
+ unsigned short e_ehsize; /* ELF header size in bytes */
+ unsigned short e_phentsize; /* Program header table entry size */
+ unsigned short e_phnum; /* Program header table entry count */
+ unsigned short e_shentsize; /* Section header table entry size */
+ unsigned short e_shnum; /* Section header table entry count */
+ unsigned short e_shstrndx; /* Section header string table index */
+} Elf_Internal_Ehdr;
+
+#define elf32_internal_ehdr elf_internal_ehdr
+#define Elf32_Internal_Ehdr Elf_Internal_Ehdr
+#define elf64_internal_ehdr elf_internal_ehdr
+#define Elf64_Internal_Ehdr Elf_Internal_Ehdr
+
+/* Program header */
+
+struct elf_internal_phdr {
+ unsigned long p_type; /* Identifies program segment type */
+ unsigned long p_flags; /* Segment flags */
+ bfd_vma p_offset; /* Segment file offset */
+ bfd_vma p_vaddr; /* Segment virtual address */
+ bfd_vma p_paddr; /* Segment physical address */
+ bfd_vma p_filesz; /* Segment size in file */
+ bfd_vma p_memsz; /* Segment size in memory */
+ bfd_vma p_align; /* Segment alignment, file & memory */
+};
+
+typedef struct elf_internal_phdr Elf_Internal_Phdr;
+#define elf32_internal_phdr elf_internal_phdr
+#define Elf32_Internal_Phdr Elf_Internal_Phdr
+#define elf64_internal_phdr elf_internal_phdr
+#define Elf64_Internal_Phdr Elf_Internal_Phdr
+
+/* Section header */
+
+typedef struct elf_internal_shdr {
+ unsigned int sh_name; /* Section name, index in string tbl */
+ unsigned int sh_type; /* Type of section */
+ bfd_vma sh_flags; /* Miscellaneous section attributes */
+ bfd_vma sh_addr; /* Section virtual addr at execution */
+ bfd_size_type sh_size; /* Size of section in bytes */
+ bfd_size_type sh_entsize; /* Entry size if section holds table */
+ unsigned long sh_link; /* Index of another section */
+ unsigned long sh_info; /* Additional section information */
+ file_ptr sh_offset; /* Section file offset */
+ unsigned int sh_addralign; /* Section alignment */
+
+ /* The internal rep also has some cached info associated with it. */
+ asection * bfd_section; /* Associated BFD section. */
+ PTR contents; /* Section contents. */
+} Elf_Internal_Shdr;
+
+#define elf32_internal_shdr elf_internal_shdr
+#define Elf32_Internal_Shdr Elf_Internal_Shdr
+#define elf64_internal_shdr elf_internal_shdr
+#define Elf64_Internal_Shdr Elf_Internal_Shdr
+
+/* Symbol table entry */
+
+struct elf_internal_sym {
+ bfd_vma st_value; /* Value of the symbol */
+ bfd_vma st_size; /* Associated symbol size */
+ unsigned long st_name; /* Symbol name, index in string tbl */
+ unsigned char st_info; /* Type and binding attributes */
+ unsigned char st_other; /* No defined meaning, 0 */
+ unsigned short st_shndx; /* Associated section index */
+};
+
+typedef struct elf_internal_sym Elf_Internal_Sym;
+
+#define elf32_internal_sym elf_internal_sym
+#define elf64_internal_sym elf_internal_sym
+#define Elf32_Internal_Sym Elf_Internal_Sym
+#define Elf64_Internal_Sym Elf_Internal_Sym
+
+/* Note segments */
+
+typedef struct elf_internal_note {
+ unsigned long namesz; /* Size of entry's owner string */
+ unsigned long descsz; /* Size of the note descriptor */
+ unsigned long type; /* Interpretation of the descriptor */
+ char name[1]; /* Start of the name+desc data */
+} Elf_Internal_Note;
+#define Elf32_Internal_Note Elf_Internal_Note
+#define elf32_internal_note elf_internal_note
+
+/* Relocation Entries */
+
+typedef struct elf_internal_rel {
+ bfd_vma r_offset; /* Location at which to apply the action */
+ /* This needs to support 64-bit values in elf64. */
+ bfd_vma r_info; /* index and type of relocation */
+} Elf_Internal_Rel;
+
+#define elf32_internal_rel elf_internal_rel
+#define Elf32_Internal_Rel Elf_Internal_Rel
+#define elf64_internal_rel elf_internal_rel
+#define Elf64_Internal_Rel Elf_Internal_Rel
+
+typedef struct elf_internal_rela {
+ bfd_vma r_offset; /* Location at which to apply the action */
+ bfd_vma r_info; /* Index and Type of relocation */
+ bfd_signed_vma r_addend; /* Constant addend used to compute value */
+} Elf_Internal_Rela;
+
+#define elf32_internal_rela elf_internal_rela
+#define elf64_internal_rela elf_internal_rela
+#define Elf32_Internal_Rela Elf_Internal_Rela
+#define Elf64_Internal_Rela Elf_Internal_Rela
+
+/* dynamic section structure */
+
+typedef struct elf_internal_dyn {
+ /* This needs to support 64-bit values in elf64. */
+ bfd_vma d_tag; /* entry tag value */
+ union {
+ /* This needs to support 64-bit values in elf64. */
+ bfd_vma d_val;
+ bfd_vma d_ptr;
+ } d_un;
+} Elf_Internal_Dyn;
+
+#define elf32_internal_dyn elf_internal_dyn
+#define elf64_internal_dyn elf_internal_dyn
+#define Elf32_Internal_Dyn Elf_Internal_Dyn
+#define Elf64_Internal_Dyn Elf_Internal_Dyn
diff --git a/arch/ppc/kernel/include/elf/mips.h b/arch/ppc/kernel/include/elf/mips.h
new file mode 100644
index 000000000..f6beff71c
--- /dev/null
+++ b/arch/ppc/kernel/include/elf/mips.h
@@ -0,0 +1,267 @@
+/* MIPS ELF support for BFD.
+ Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+
+ By Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>, from
+ information in the System V Application Binary Interface, MIPS
+ Processor Supplement.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file holds definitions specific to the MIPS ELF ABI. Note
+ that most of this is not actually implemented by BFD. */
+
+/* Processor specific flags for the ELF header e_flags field. */
+
+/* At least one .noreorder directive appears in the source. */
+#define EF_MIPS_NOREORDER 0x00000001
+
+/* File contains position independent code. */
+#define EF_MIPS_PIC 0x00000002
+
+/* Code in file uses the standard calling sequence for calling
+ position independent code. */
+#define EF_MIPS_CPIC 0x00000004
+
+/* Four bit MIPS architecture field. */
+#define EF_MIPS_ARCH 0xf0000000
+
+/* -mips1 code. */
+#define E_MIPS_ARCH_1 0x00000000
+
+/* -mips2 code. */
+#define E_MIPS_ARCH_2 0x10000000
+
+/* -mips3 code. */
+#define E_MIPS_ARCH_3 0x20000000
+
+/* Processor specific section indices. These sections do not actually
+ exist. Symbols with a st_shndx field corresponding to one of these
+ values have a special meaning. */
+
+/* Defined and allocated common symbol. Value is virtual address. If
+ relocated, alignment must be preserved. */
+#define SHN_MIPS_ACOMMON 0xff00
+
+/* Defined and allocated text symbol. Value is virtual address.
+ Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables. */
+#define SHN_MIPS_TEXT 0xff01
+
+/* Defined and allocated data symbol. Value is virtual address.
+ Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables. */
+#define SHN_MIPS_DATA 0xff02
+
+/* Small common symbol. */
+#define SHN_MIPS_SCOMMON 0xff03
+
+/* Small undefined symbol. */
+#define SHN_MIPS_SUNDEFINED 0xff04
+
+/* Processor specific section types. */
+
+/* Section contains the set of dynamic shared objects used when
+ statically linking. */
+#define SHT_MIPS_LIBLIST 0x70000000
+
+/* I'm not sure what this is, but it's used on Irix 5. */
+#define SHT_MIPS_MSYM 0x70000001
+
+/* Section contains list of symbols whose definitions conflict with
+ symbols defined in shared objects. */
+#define SHT_MIPS_CONFLICT 0x70000002
+
+/* Section contains the global pointer table. */
+#define SHT_MIPS_GPTAB 0x70000003
+
+/* Section contains microcode information. The exact format is
+ unspecified. */
+#define SHT_MIPS_UCODE 0x70000004
+
+/* Section contains some sort of debugging information. The exact
+ format is unspecified. It's probably ECOFF symbols. */
+#define SHT_MIPS_DEBUG 0x70000005
+
+/* Section contains register usage information. */
+#define SHT_MIPS_REGINFO 0x70000006
+
+/* Section contains miscellaneous options (used on Irix). */
+#define SHT_MIPS_OPTIONS 0x7000000d
+
+/* DWARF debugging section (used on Irix 6). */
+#define SHT_MIPS_DWARF 0x7000001e
+
+/* Events section. This appears on Irix 6. I don't know what it
+ means. */
+#define SHT_MIPS_EVENTS 0x70000021
+
+/* A section of type SHT_MIPS_LIBLIST contains an array of the
+ following structure. The sh_link field is the section index of the
+ string table. The sh_info field is the number of entries in the
+ section. */
+typedef struct
+{
+ /* String table index for name of shared object. */
+ unsigned long l_name;
+ /* Time stamp. */
+ unsigned long l_time_stamp;
+ /* Checksum of symbol names and common sizes. */
+ unsigned long l_checksum;
+ /* String table index for version. */
+ unsigned long l_version;
+ /* Flags. */
+ unsigned long l_flags;
+} Elf32_Lib;
+
+/* The l_flags field of an Elf32_Lib structure may contain the
+ following flags. */
+
+/* Require an exact match at runtime. */
+#define LL_EXACT_MATCH 0x00000001
+
+/* Ignore version incompatibilities at runtime. */
+#define LL_IGNORE_INT_VER 0x00000002
+
+/* A section of type SHT_MIPS_CONFLICT is an array of indices into the
+ .dynsym section. Each element has the following type. */
+typedef unsigned long Elf32_Conflict;
+
+/* A section of type SHT_MIPS_GPTAB contains information about how
+ much GP space would be required for different -G arguments. This
+ information is only used so that the linker can provide informative
+ suggestions as to the best -G value to use. The sh_info field is
+ the index of the section for which this information applies. The
+ contents of the section are an array of the following union. The
+ first element uses the gt_header field. The remaining elements use
+ the gt_entry field. */
+typedef union
+{
+ struct
+ {
+ /* -G value actually used for this object file. */
+ unsigned long gt_current_g_value;
+ /* Unused. */
+ unsigned long gt_unused;
+ } gt_header;
+ struct
+ {
+ /* If this -G argument has been used... */
+ unsigned long gt_g_value;
+ /* ...this many GP section bytes would be required. */
+ unsigned long gt_bytes;
+ } gt_entry;
+} Elf32_gptab;
+
+/* The external version of Elf32_gptab. */
+
+typedef union
+{
+ struct
+ {
+ unsigned char gt_current_g_value[4];
+ unsigned char gt_unused[4];
+ } gt_header;
+ struct
+ {
+ unsigned char gt_g_value[4];
+ unsigned char gt_bytes[4];
+ } gt_entry;
+} Elf32_External_gptab;
+
+/* A section of type SHT_MIPS_REGINFO contains the following
+ structure. */
+typedef struct
+{
+ /* Mask of general purpose registers used. */
+ unsigned long ri_gprmask;
+ /* Mask of co-processor registers used. */
+ unsigned long ri_cprmask[4];
+ /* GP register value for this object file. */
+ long ri_gp_value;
+} Elf32_RegInfo;
+
+/* The external version of the Elf_RegInfo structure. */
+typedef struct
+{
+ unsigned char ri_gprmask[4];
+ unsigned char ri_cprmask[4][4];
+ unsigned char ri_gp_value[4];
+} Elf32_External_RegInfo;
+
+/* MIPS ELF .reginfo swapping routines. */
+extern void bfd_mips_elf32_swap_reginfo_in
+ PARAMS ((bfd *, const Elf32_External_RegInfo *, Elf32_RegInfo *));
+extern void bfd_mips_elf32_swap_reginfo_out
+ PARAMS ((bfd *, const Elf32_RegInfo *, Elf32_External_RegInfo *));
+
+/* Processor specific section flags. */
+
+/* This section must be in the global data area. */
+#define SHF_MIPS_GPREL 0x10000000
+
+/* Processor specific program header types. */
+
+/* Register usage information. Identifies one .reginfo section. */
+#define PT_MIPS_REGINFO 0x70000000
+
+/* Processor specific dynamic array tags. */
+
+/* 32 bit version number for runtime linker interface. */
+#define DT_MIPS_RLD_VERSION 0x70000001
+
+/* Time stamp. */
+#define DT_MIPS_TIME_STAMP 0x70000002
+
+/* Checksum of external strings and common sizes. */
+#define DT_MIPS_ICHECKSUM 0x70000003
+
+/* Index of version string in string table. */
+#define DT_MIPS_IVERSION 0x70000004
+
+/* 32 bits of flags. */
+#define DT_MIPS_FLAGS 0x70000005
+
+/* Base address of the segment. */
+#define DT_MIPS_BASE_ADDRESS 0x70000006
+
+/* Address of .conflict section. */
+#define DT_MIPS_CONFLICT 0x70000008
+
+/* Address of .liblist section. */
+#define DT_MIPS_LIBLIST 0x70000009
+
+/* Number of local global offset table entries. */
+#define DT_MIPS_LOCAL_GOTNO 0x7000000a
+
+/* Number of entries in the .conflict section. */
+#define DT_MIPS_CONFLICTNO 0x7000000b
+
+/* Number of entries in the .liblist section. */
+#define DT_MIPS_LIBLISTNO 0x70000010
+
+/* Number of entries in the .dynsym section. */
+#define DT_MIPS_SYMTABNO 0x70000011
+
+/* Index of first external dynamic symbol not referenced locally. */
+#define DT_MIPS_UNREFEXTNO 0x70000012
+
+/* Index of first dynamic symbol in global offset table. */
+#define DT_MIPS_GOTSYM 0x70000013
+
+/* Number of page table entries in global offset table. */
+#define DT_MIPS_HIPAGENO 0x70000014
+
+/* Address of run time loader map, used for debugging. */
+#define DT_MIPS_RLD_MAP 0x70000016
diff --git a/arch/ppc/kernel/include/elf/ppc.h b/arch/ppc/kernel/include/elf/ppc.h
new file mode 100644
index 000000000..b4907acb7
--- /dev/null
+++ b/arch/ppc/kernel/include/elf/ppc.h
@@ -0,0 +1,32 @@
+/* MIPS PPC support for BFD.
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ By Michael Meissner, Cygnus Support, <meissner@cygnus.com>, from information
+ in the System V Application Binary Interface, PowerPC Processor Supplement
+ and the PowerPC Embedded Application Binary Interface (eabi).
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file holds definitions specific to the PPC ELF ABI. Note
+ that most of this is not actually implemented by BFD. */
+
+/* Processor specific flags for the ELF header e_flags field. */
+
+#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
+
+ /* CYGNUS local bits below */
+#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag */
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
new file mode 100644
index 000000000..27d146479
--- /dev/null
+++ b/arch/ppc/kernel/irq.c
@@ -0,0 +1,554 @@
+/*
+ * linux/arch/ppc/kernel/irq.c
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ * Adapted from arch/i386 by Gary Thomas
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * 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>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+/*
+ * For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
+ * and 16..31 for other BeBox motherboard type interrupts.
+ */
+
+unsigned long isBeBox[];
+unsigned char *BeBox_IO_page;
+
+static unsigned char cache_21 = 0xff;
+static unsigned char cache_A1 = 0xff;
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned char mask;
+ int s = _disable_interrupts();
+
+ if (isBeBox[0] && (irq_nr >= 16))
+ {
+ BeBox_disable_irq(irq_nr);
+ } else
+ {
+ mask = 1 << (irq_nr & 7);
+ if (irq_nr < 8) {
+ cache_21 |= mask;
+ outb(cache_21,0x21);
+ } else
+ {
+ cache_A1 |= mask;
+ outb(cache_A1,0xA1);
+ }
+ }
+ _enable_interrupts(s);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned char mask;
+ int s = _disable_interrupts();
+
+ if (isBeBox[0] && (irq_nr >= 16))
+ {
+ BeBox_enable_irq(irq_nr);
+ _enable_interrupts(s);
+ return;
+ } else
+ {
+ mask = ~(1 << (irq_nr & 7));
+ if (irq_nr < 8) {
+ cache_21 &= mask;
+ outb(cache_21,0x21);
+ } else
+ {
+ cache_A1 &= mask;
+ outb(cache_A1,0xA1);
+ }
+ }
+ _enable_interrupts(s);
+}
+
+/*
+ * Irq handlers.
+ */
+struct irq_action {
+ void (*handler)(int, void *dev, struct pt_regs *);
+ unsigned long flags;
+ unsigned long mask;
+ const char *name;
+ int notified;
+ void *dev_id;
+};
+
+static struct irq_action irq_action[32] = {
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
+};
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ struct irq_action * action = irq_action;
+
+ for (i = 0; i < 132; i++, action++) {
+ if (!action->handler)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s\n",
+ i, kstat.interrupts[i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ }
+ return len;
+}
+
+asmlinkage void handle_IRQ(struct pt_regs *regs)
+{
+ int irq, _irq, s;
+ struct irq_action *action;
+ intr_count++;
+ if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
+ {
+ /* Figure out IRQ#, etc. */
+ outb(0x0C, 0x20); /* Poll interrupt controller */
+ irq = _irq = inb(0x20);
+ irq &= 0x07; /* Caution! */
+ if (irq == 2)
+ { /* Cascaded interrupt -> IRQ8..IRQ15 */
+ outb(0x0C, 0xA0);
+ irq = (_irq = inb(0xA0)) & 0x07;
+ irq += 8;
+ }
+ /* Mask interrupt & Issue EOI to interrupt controller */
+ if (irq > 7)
+ {
+ cache_A1 |= (1<<(irq-8));
+ outb(cache_A1, 0xA1);
+#if 0
+ outb(0x20, 0xA0);
+ /* Need to ack cascade controller as well */
+ outb(0x20, 0x20);
+#else
+ outb(0x60|(irq-8), 0xA0); /* Specific EOI */
+ /* Need to ack cascade controller as well */
+ outb(0x62, 0x20);
+#endif
+ } else
+ {
+ cache_21 |= (1<<irq);
+ outb(cache_21, 0x21);
+ outb(0x20, 0x20);
+ }
+ }
+ action = irq + irq_action;
+ kstat.interrupts[irq]++;
+ if (action->handler)
+ {
+ action->handler(irq, action->dev_id, regs);
+ } else
+ {
+ printk("Bogus interrupt #%d/%x, PC: %x\n", irq, _irq, regs->nip);
+ }
+ if (_disable_interrupts() && !action->notified)
+ {
+ action->notified = 1;
+ printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n", action->name, irq);
+ }
+ if (irq < 16)
+ {
+ if (!(action->flags & SA_ONESHOT))
+ {
+ /* Re-enable interrupt */
+ if (irq > 7)
+ {
+ cache_A1 &= ~(1<<(irq-8));
+ outb(cache_A1, 0xA1);
+ } else
+ {
+ cache_21 &= ~(1<<irq);
+ outb(cache_21, 0x21);
+ }
+ }
+ } else
+ {
+ BeBox_enable_irq(irq);
+ }
+ intr_count--;
+}
+
+/*
+ * This routine gets called when the SCSI times out on an operation.
+ * I don't know why this happens, but every so often it does and it
+ * seems to be a problem with the interrupt controller [state]. It
+ * happens a lot when there is also network activity (both devices
+ * are on the PCI bus with interrupts on the cascaded controller).
+ * Re-initializing the interrupt controller [which might lose some
+ * pending edge detected interrupts] seems to fix it.
+ */
+check_irq()
+{
+ int s;
+ unsigned char _a0, _a1, _20, _21;
+ if (isBeBox[0])
+ {
+ return;
+ }
+ s = _disable_interrupts();
+ _a1 = inb(0xA1);
+ _21 = inb(0x21);
+ outb(0x0C, 0x20); _20 = inb(0x20);
+ outb(0x0C, 0xA0); _a0 = inb(0xA0);
+#if 0
+ printk("IRQ 0x20 = %x, 0x21 = %x/%x, 0xA0 = %x, 0xA1 = %x/%x\n",
+ _20, _21, cache_21, _a0, _a1, cache_A1);
+#endif
+ /* Reset interrupt controller - see if this fixes it! */
+ /* Initialize interrupt controllers */
+ outb(0x11, 0x20); /* Start init sequence */
+ outb(0x40, 0x21); /* Vector base */
+ outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
+ outb(0x01, 0x21); /* Select 8086 mode */
+ outb(0xFF, 0x21); /* Mask all */
+ outb(0x00, 0x4D0); /* All edge triggered */
+ outb(0x11, 0xA0); /* Start init sequence */
+ outb(0x48, 0xA1); /* Vector base */
+ outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
+ outb(0x01, 0xA1); /* Select 8086 mode */
+ outb(0xFF, 0xA1); /* Mask all */
+ outb(0xCF, 0x4D1); /* Trigger mode */
+ outb(cache_A1, 0xA1);
+ outb(cache_21, 0x21);
+ enable_irq(2); /* Enable cascade interrupt */
+ _enable_interrupts(s);
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags, const char * devname, void *dev_id)
+{
+ struct irq_action * action;
+ unsigned long flags;
+
+#if 0
+_printk("Request IRQ #%d, Handler: %x\n", irq, handler);
+#endif
+ if (irq > 15)
+ {
+ if (!isBeBox[0] || (irq > 31))
+ return -EINVAL;
+ }
+ action = irq + irq_action;
+ if (action->handler)
+ return -EBUSY;
+ if (!handler)
+ return -EINVAL;
+ save_flags(flags);
+ cli();
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ enable_irq(irq);
+ restore_flags(flags);
+ return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irq_action * action = irq + irq_action;
+ unsigned long flags;
+
+ if (irq > 31) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+ if (!action->handler) {
+ printk("Trying to free free IRQ%d\n",irq);
+ return;
+ }
+ disable_irq(irq);
+ save_flags(flags);
+ cli();
+ action->handler = NULL;
+ action->flags = 0;
+ action->mask = 0;
+ action->name = NULL;
+ action->dev_id = NULL;
+ restore_flags(flags);
+}
+
+#define SA_PROBE SA_ONESHOT
+
+static void no_action(int irq, void *dev, struct pt_regs * regs)
+{
+#ifdef DEBUG
+ printk("Probe got IRQ: %d\n", irq);
+#endif
+}
+
+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, no_action, SA_PROBE, "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)cache_A1)<<8) | (unsigned int)cache_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;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+ unsigned int i, irqmask;
+
+ irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+ for (i = 15; i > 0; i--) {
+ if (irqs & (1 << i)) {
+ free_irq(i, NULL);
+ }
+ }
+#ifdef DEBUG
+ 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;
+}
+
+void init_IRQ(void)
+{
+ int i;
+
+ /* set the clock to 100 Hz */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb(LATCH >> 8 , 0x40); /* MSB */
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
+ printk("Unable to get IRQ2 for cascade\n");
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+
+ /* Set up PCI interrupts */
+ route_PCI_interrupts();
+
+ if (isBeBox[0])
+ {
+ BeBox_init_IRQ();
+ }
+}
+
+/*
+ * Wrapper for "bottom 1/2" of interrupt processing. This routine
+ * is called whenever an interrupt needs non-interrupt-time service.
+ */
+
+_do_bottom_half()
+{
+ _enable_interrupts(1);
+ do_bottom_half();
+ _disable_interrupts();
+}
+
+
+/*
+ * Support for interrupts on the BeBox
+ */
+
+#define CPU0_INT_MASK (volatile unsigned long *)(BeBox_IO_page+0x0F0)
+#define CPU1_INT_MASK (volatile unsigned long *)(BeBox_IO_page+0x1F0)
+#define INT_SOURCE (volatile unsigned long *)(BeBox_IO_page+0x2F0)
+#define CPU_RESET (volatile unsigned long *)(BeBox_IO_page+0x4F0)
+
+#define CPU_HRESET 0x20000000
+#define CPU_SRESET 0x40000000
+
+#define SCSI_IRQ 16
+
+#define INT_SCSI (1<<21)
+#define INT_8259 (1<<5)
+
+/*
+ * Map of pseudo IRQs to actual bits
+ * Note: We give out IRQ #16..31 for all interrupt sources which are
+ * not found in the 8259 PIC.
+ */
+
+unsigned long BeBox_IRQ_map[] =
+ {
+ INT_SCSI, /* 16 - SCSI */
+ 0x00000000, /* 17 - Unused */
+ 0x00000000, /* 18 - Unused */
+ 0x00000000, /* 19 - Unused */
+ 0x00000000, /* 20 - Unused */
+ 0x00000000, /* 21 - Unused */
+ 0x00000000, /* 22 - Unused */
+ 0x00000000, /* 23 - Unused */
+ 0x00000000, /* 24 - Unused */
+ 0x00000000, /* 25 - Unused */
+ 0x00000000, /* 26 - Unused */
+ 0x00000000, /* 27 - Unused */
+ 0x00000000, /* 28 - Unused */
+ 0x00000000, /* 29 - Unused */
+ 0x00000000, /* 30 - Unused */
+ 0x00000000, /* 31 - Unused */
+ };
+
+volatile int CPU1_alive;
+volatile int CPU1_trace;
+
+static
+_NOP()
+{
+}
+
+static
+_delay()
+{
+ int i;
+ for (i = 0; i < 100; i++) _NOP();
+}
+
+void
+BeBox_init_IRQ(void)
+{
+ int tmr;
+ volatile extern long BeBox_CPU1_vector;
+ *CPU0_INT_MASK = 0x0FFFFFFC; /* Clear all bits? */
+ *CPU0_INT_MASK = 0x80000003 | INT_8259;
+ *CPU1_INT_MASK = 0x0FFFFFFC;
+printk("Start CPU #1 - CPU Status: %x\n", *CPU_RESET);
+ BeBox_CPU1_vector = 0x0100; /* Reset */
+ tmr = 0;
+ while (CPU1_alive == 0)
+ {
+ if (++tmr == 1000)
+ {
+printk("CPU #1 not there? - CPU Status: %x, Trace: %x\n", *CPU_RESET, CPU1_trace);
+ break;
+ }
+ _delay();
+ }
+printk("CPU #1 running!\n");
+#if 0
+/* Temp - for SCSI */
+ *(unsigned char *)0x81000038 = 0x00;
+ *(unsigned char *)0x8080103C = 0xFF;
+ *(unsigned char *)0x8080100D = 0x32;
+#endif
+}
+
+void
+BeBox_disable_irq(int irq)
+{
+ /* Note: this clears the particular bit */
+ *CPU0_INT_MASK = BeBox_IRQ_map[irq-16];
+}
+
+void
+BeBox_enable_irq(int irq)
+{
+ int s = _disable_interrupts();
+ /* Sets a single bit */
+#if 0
+printk("BeBox IRQ Mask = %x", *CPU0_INT_MASK);
+#endif
+ *CPU0_INT_MASK = 0x80000000 | BeBox_IRQ_map[irq-16];
+#if 0
+printk("/%x\n", *CPU0_INT_MASK);
+#endif
+ _enable_interrupts(s);
+}
+
+int
+BeBox_irq(void)
+{
+ int i;
+ unsigned long cpu0_int_mask;
+ unsigned long int_state;
+ cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
+ int_state = cpu0_int_mask & *INT_SOURCE;
+ if (int_state)
+ { /* Determine the pseudo-interrupt # */
+#if 0
+ printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
+#endif
+ for (i = 0; i < 16; i++)
+ {
+ if (BeBox_IRQ_map[i] & int_state)
+ {
+ return (i+16);
+ }
+ }
+printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
+printk("Can't find BeBox IRQ!\n");
+ }
+ return (0);
+}
+
+BeBox_state()
+{
+ printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
+}
+
+BeBox_CPU1()
+{
+ CPU1_alive++;
+ while (1) ;
+}
diff --git a/arch/ppc/kernel/ksyms.c b/arch/ppc/kernel/ksyms.c
new file mode 100644
index 000000000..a0d3ec66e
--- /dev/null
+++ b/arch/ppc/kernel/ksyms.c
@@ -0,0 +1,14 @@
+#include <linux/module.h>
+#include <linux/smp.h>
+
+static struct symbol_table arch_symbol_table = {
+#include <linux/symtab_begin.h>
+ /* platform dependent support */
+#include <linux/symtab_end.h>
+};
+
+void arch_syms_export(void)
+{
+ register_symtab(&arch_symbol_table);
+}
+
diff --git a/arch/ppc/kernel/ld.script-user b/arch/ppc/kernel/ld.script-user
new file mode 100644
index 000000000..910d34ad3
--- /dev/null
+++ b/arch/ppc/kernel/ld.script-user
@@ -0,0 +1,75 @@
+OUTPUT_ARCH(powerpc)
+SEARCH_DIR(libc); SEARCH_DIR(../sa_test/libc);
+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)
+ }
+ _etext = .;
+ PROVIDE (etext = .);
+ .fini : { *(.fini) } =0
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ .rodata : { *(.rodata) }
+ .rodata1 : { *(.rodata1) }
+ /* Read-write section, merged into data segment: */
+/* . = (. + 0x0FFF) & 0xFFFFF000; */
+ .data :
+ {
+ *(.data)
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ .got : { *(.got.plt) *(.got) }
+ .dynamic : { *(.dynamic) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata : { *(.sdata) }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ }
+ _end = . ;
+ PROVIDE (end = .);
+ /* These are needed for ELF backends which have not yet been
+ converted to the new style linker. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ /* These must appear regardless of . */
+}
+
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
new file mode 100644
index 000000000..7d84bdc89
--- /dev/null
+++ b/arch/ppc/kernel/misc.S
@@ -0,0 +1,659 @@
+/*
+ * This module contains the PowerPC interrupt fielders
+ * set of code at specific locations, based on function
+ */
+
+#include <linux/sys.h>
+#include "ppc_asm.tmpl"
+
+/* Keep track of low-level exceptions - rather crude, but informative */
+#define STATS
+
+/*
+ * Increment a [64 bit] statistic counter
+ * Uses R2, R3
+ */
+#define BUMP(ctr) \
+ lis r2,ctr@h; \
+ ori r2,r2,ctr@l; \
+ lwz r3,4(r2); \
+ addic r3,r3,1; \
+ stw r3,4(r2); \
+ lwz r3,0(r2); \
+ addze r3,r3; \
+ stw r3,0(r2)
+
+/* This instruction is not implemented on the PPC 603 */
+#define tlbia \
+ li r4,64; \
+ mtspr CTR,r4; \
+ li r4,0; \
+0: tlbie r4; \
+ addi r4,r4,0x1000; \
+ bdnz 0b
+
+_TEXT()
+
+/*
+ * Disable interrupts
+ * rc = _disable_interrupts()
+ */
+_GLOBAL(_disable_interrupts)
+ mfmsr r0 /* Get current interrupt state */
+ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */
+ li r4,0 /* Need [unsigned] value of MSR_EE */
+ ori r4,r4,MSR_EE /* Set to turn off bit */
+ andc r0,r0,r4 /* Clears bit in (r4) */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0 /* Update machine state */
+ blr /* Done */
+
+/*
+ * Enable interrupts
+ * _enable_interrupts(int state)
+ * turns on interrupts if state = 1.
+ */
+_GLOBAL(_enable_interrupts)
+ mfmsr r0 /* Get current state */
+ rlwimi r0,r3,16-1,32-16,32-16 /* Insert bit */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0 /* Update machine state */
+ blr
+
+/*
+ * Get 'flags' (aka machine status register)
+ * __save_flags(long *ptr)
+ */
+_GLOBAL(__save_flags)
+ mfmsr r0 /* Get current state */
+ stw r0,0(r3)
+ mr r3,r0
+ blr
+
+/*
+ * Restore 'flags'
+ * __restore_flags(long val)
+ */
+_GLOBAL(__restore_flags)
+ sync /* Some chip revs have problems here... */
+ mtmsr r3
+ isync
+ blr
+
+/*
+ * Disable interrupts - like an 80x86
+ * cli()
+ */
+_GLOBAL(cli)
+ mfmsr r0 /* Get current interrupt state */
+ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */
+ li r4,0 /* Need [unsigned] value of MSR_EE */
+ ori r4,r4,MSR_EE /* Set to turn off bit */
+ andc r0,r0,r4 /* Clears bit in (r4) */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0 /* Update machine state */
+ blr /* Done */
+
+/*
+ * Enable interrupts - like an 80x86
+ * sti()
+ */
+_GLOBAL(sti)
+ mfmsr r0 /* Get current state */
+ ori r0,r0,MSR_EE /* Turn on 'EE' bit */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0 /* Update machine state */
+ blr
+
+/*
+ * Flush MMU TLB
+ */
+_GLOBAL(_tlbia)
+ tlbia
+ BUMP(__TLBIAs)
+ blr
+
+/*
+ * Flush MMU TLB for a particular address
+ */
+_GLOBAL(_tlbie)
+ tlbie r3
+ BUMP(__TLBIEs)
+ blr
+
+/*
+ * Fetch the current SR register
+ * get_SR(int index)
+ */
+_GLOBAL(get_SR)
+ mfsrin r3,r3
+ blr
+
+/*
+ * Atomic [test&set] exchange
+ *
+ * void *xchg_u32(void *ptr, unsigned long val)
+ * Changes the memory location '*ptr' to be val and returns
+ * the previous value stored there.
+ */
+_GLOBAL(xchg_u32)
+ mr r5,r3 /* Save pointer */
+10: lwarx r3,0,r5 /* Fetch old value & reserve */
+ stwcx. r4,0,r5 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ blr
+
+/*
+ * Atomic add/sub/inc/dec operations
+ *
+ * void atomic_add(int c, int *v)
+ * void atomic_sub(int c, int *v)
+ * void atomic_inc(int *v)
+ * void atomic_dec(int *v)
+ * void atomic_dec_and_test(int *v)
+ */
+_GLOBAL(atomic_add)
+10: lwarx r5,0,r4 /* Fetch old value & reserve */
+ add r5,r5,r3 /* Perform 'add' operation */
+ stwcx. r5,0,r4 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ blr
+_GLOBAL(atomic_sub)
+10: lwarx r5,0,r4 /* Fetch old value & reserve */
+ sub r5,r5,r3 /* Perform 'add' operation */
+ stwcx. r5,0,r4 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ blr
+_GLOBAL(atomic_inc)
+10: lwarx r5,0,r3 /* Fetch old value & reserve */
+ addi r5,r5,1 /* Perform 'add' operation */
+ stwcx. r5,0,r3 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ blr
+_GLOBAL(atomic_dec)
+10: lwarx r5,0,r3 /* Fetch old value & reserve */
+ subi r5,r5,1 /* Perform 'add' operation */
+ stwcx. r5,0,r3 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ blr
+_GLOBAL(atomic_dec_and_test)
+10: lwarx r5,0,r3 /* Fetch old value & reserve */
+ subi r5,r5,1 /* Perform 'add' operation */
+ stwcx. r5,0,r3 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ cmpi 0,r5,0 /* Return 'true' IFF 0 */
+ bne 15f
+ li r3,1
+ blr
+15: li r3,0
+ blr
+
+
+/*
+ * Delay for a specific # of "loops"
+ * __delay(int loops)
+ */
+_GLOBAL(__delay)
+ mtctr r3
+00: addi r3,r3,0 /* NOP */
+ bdnz 00b
+ blr
+
+/*
+ * Delay for a number of microseconds
+ * udelay(int usecs)
+ */
+_GLOBAL(udelay)
+00: li r0,86 /* Instructions / microsecond? */
+ mtctr r0
+10: addi r0,r0,0 /* NOP */
+ bdnz 10b
+ subic. r3,r3,1
+ bne 00b
+ blr
+
+/*
+ * Atomically increment [intr_count]
+ */
+_GLOBAL(start_bh_atomic)
+ lis r3,intr_count@h
+ ori r3,r3,intr_count@l
+10: lwarx r4,0,r3
+ addi r4,r4,1
+ stwcx. r4,0,r3
+ bne- 10b
+ blr
+
+/*
+ * Atomically decrement [intr_count]
+ */
+_GLOBAL(end_bh_atomic)
+ lis r3,intr_count@h
+ ori r3,r3,intr_count@l
+10: lwarx r4,0,r3
+ subic r4,r4,1
+ stwcx. r4,0,r3
+ bne- 10b
+ blr
+
+/*
+ * I/O string operations
+ *
+ * insw(port, buf, len)
+ * outsw(port, buf, len)
+ */
+_GLOBAL(_insw)
+ mtctr r5
+ subi r4,r4,2
+00: lhbrx r5,0,r3
+ sthu r5,2(r4)
+ bdnz 00b
+ blr
+
+_GLOBAL(_outsw)
+ mtctr r5
+ subi r4,r4,2
+00: lhzu r5,2(r4)
+ sthbrx r5,0,r3
+ bdnz 00b
+ blr
+
+#if 0
+/*
+ *extern inline int find_first_zero_bit(void * vaddr, unsigned size)
+ *{
+ * unsigned long res;
+ * unsigned long *p;
+ * unsigned long *addr = vaddr;
+ *
+ * if (!size)
+ * return 0;
+ * __asm__ __volatile__ (" moveq #-1,d0\n\t"
+ * "1:"
+ * " cmpl %1@+,d0\n\t"
+ * " bne 2f\n\t"
+ * " subql #1,%0\n\t"
+ * " bne 1b\n\t"
+ * " bra 5f\n\t"
+ * "2:"
+ * " movel %1@-,d0\n\t"
+ * " notl d0\n\t"
+ * " bfffo d0{#0,#0},%0\n\t"
+ * "5:"
+ * : "=d" (res), "=a" (p)
+ * : "0" ((size + 31) >> 5), "1" (addr)
+ * : "d0");
+ * return ((p - addr) << 5) + res;
+ *}
+ */
+_GLOBAL(find_first_zero_bit)
+ li r5,0 /* bit # */
+ subi r3,r3,4 /* Adjust pointer for auto-increment */
+00: lwzu r0,4(r3) /* Get next word */
+ not. r7,r0 /* Complement to find ones */
+ beq 10f /* Jump if all ones */
+02: andi. r7,r0,1 /* Check low-order bit */
+ beq 20f /* All done when zero found */
+ srawi r0,r0,1
+ addi r5,r5,1
+ b 02b
+10: addi r5,r5,32 /* Update bit # */
+ subic. r4,r4,32 /* Any more? */
+ bgt 00b
+20: mr r3,r5 /* Compute result */
+ blr
+
+/*
+ *static inline int find_next_zero_bit (void *vaddr, int size,
+ * int offset)
+ *{
+ * unsigned long *addr = vaddr;
+ * unsigned long *p = addr + (offset >> 5);
+ * int set = 0, bit = offset & 31, res;
+ *
+ * if (bit) {
+ * // Look for zero in first longword
+ * __asm__("bfffo %1{#0,#0},%0"
+ * : "=d" (set)
+ * : "d" (~*p << bit));
+ * if (set < (32 - bit))
+ * return set + offset;
+ * set = 32 - bit;
+ * p++;
+ * }
+ * // No zero yet, search remaining full bytes for a zero
+ * res = find_first_zero_bit (p, size - 32 * (p - addr));
+ * return (offset + set + res);
+ *}
+ */
+_GLOBAL(find_next_zero_bit)
+ addi r5,r5,1 /* bump offset to start */
+ srawi r6,r5,5 /* word offset */
+ add r6,r6,r6 /* byte offset */
+ add r6,r6,r6 /* byte offset */
+ add r3,r3,r6 /* compute byte position */
+ sub r4,r4,r5 /* adjust size by starting index */
+ andi. r0,r5,0x1F /* offset in current word? */
+ beq 10f /* at start of word */
+ lwz r0,0(r3) /* get word */
+ sraw r0,r0,r5 /* shift right */
+ not. r7,r0
+ beq 07f /* jump if only ones remain */
+05: andi. r7,r0,1 /* found zero? */
+ beq 90f /* yes - all done */
+ srawi r0,r0,1
+ addi r5,r5,1
+ b 05b
+07: andi. r6,r5,0x1F
+ subfic r0,r6,32
+ add r5,r5,r0
+ sub r4,r4,r0
+ b 20f
+10: subi r3,r3,4 /* Adjust pointer for auto-increment */
+20: lwzu r0,4(r3) /* Get next word */
+ not. r7,r0 /* Complement to find ones */
+ beq 40f /* Jump if all ones */
+30: andi. r7,r0,1 /* Check low-order bit */
+ beq 90f /* All done when zero found */
+ srawi r0,r0,1
+ addi r5,r5,1
+ b 30b
+40: addi r5,r5,32 /* Update bit # */
+ subic. r4,r4,32 /* Any more? */
+ bgt 20b
+90: mr r3,r5 /* Compute result */
+ blr
+#endif
+
+/*
+ *
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ *
+ *extern inline unsigned long ffz(unsigned long word)
+ *{
+ * __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
+ * : "=d" (word)
+ * : "d" (~(word)));
+ * return word;
+ *}
+ */
+_GLOBAL(ffz)
+ mr r4,r3
+ li r3,0
+10: andi. r0,r4,1 /* Find the zero we know is there */
+ srawi r4,r4,1
+ beq 90f
+ addi r3,r3,1
+ b 10b
+90: blr
+
+/*
+ * Extended precision shifts
+ *
+ * R3/R4 has 64 bit value
+ * R5 has shift count
+ * result in R3/R4
+ *
+ * ashrdi3: XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ
+ * ashldi3: XXXYYY/ZZZAAA -> YYYZZZ/AAA000
+ */
+_GLOBAL(__ashrdi3)
+ li r6,32
+ sub r6,r6,r5
+ slw r7,r3,r6 /* isolate YYY */
+ srw r4,r4,r5 /* isolate ZZZ */
+ or r4,r4,r7 /* YYYZZZ */
+ sraw r3,r3,r5 /* SSSXXX */
+ blr
+
+_GLOBAL(__ashldi3)
+ li r6,32
+ sub r6,r6,r5
+ srw r7,r4,r6 /* isolate ZZZ */
+ slw r4,r4,r5 /* AAA000 */
+ slw r3,r3,r5 /* YYY--- */
+ or r3,r3,r7 /* YYYZZZ */
+ blr
+
+_GLOBAL(abort)
+ .long 0
+
+_GLOBAL(bzero)
+#define bufp r3
+#define len r4
+#define pat r5
+/* R3 has buffer */
+/* R4 has length */
+/* R5 has pattern */
+ cmpi 0,len,0 /* Exit if len <= 0 */
+ ble 99f
+ andi. r0,bufp,3 /* Must be on longword boundary */
+ bne 10f /* Use byte loop if not aligned */
+ andi. r0,len,3 /* Check for overrage */
+ subi bufp,bufp,4 /* Adjust pointer */
+ srawi len,len,2 /* Divide by 4 */
+ blt 99f /* If negative - bug out! */
+ mtspr CTR,len /* Set up counter */
+ li pat,0
+00: stwu pat,4(bufp) /* Store value */
+ bdnz 00b /* Loop [based on counter] */
+ mr len,r0 /* Get remainder (bytes) */
+10: cmpi 0,len,0 /* Any bytes left */
+ ble 99f /* No - all done */
+ mtspr CTR,len /* Set up counter */
+ subi bufp,bufp,1 /* Adjust pointer */
+ li pat,0
+20: stbu pat,1(bufp) /* Store value */
+ bdnz 20b /* Loop [based on counter] */
+99: blr
+
+_GLOBAL(abs)
+ cmpi 0,r3,0
+ bge 10f
+ neg r3,r3
+10: blr
+
+_GLOBAL(_get_SP)
+ mr r3,r1 /* Close enough */
+ blr
+
+_GLOBAL(_get_SDR1)
+ mfspr r3,SDR1
+ blr
+
+_GLOBAL(_get_SRx)
+ mfsrin r3,r3
+ blr
+
+_GLOBAL(_get_PVR)
+ mfspr r3,PVR
+ blr
+
+/*
+ * Create a kernel thread
+ * __kernel_thread(flags, fn, arg)
+ */
+#if 0
+#define SYS_CLONE 120
+_GLOBAL(__kernel_thread)
+__kernel_thread:
+ li r0,SYS_CLONE
+ sc
+ cmpi 0,r3,0
+ bnelr
+ mtlr r4
+ mr r3,r5
+ blr
+#endif
+/* Why isn't this a) automatic, b) written in 'C'? */
+ .data
+ .align 4
+ .globl sys_call_table
+sys_call_table:
+ .long sys_setup /* 0 */
+ .long sys_exit
+ .long sys_fork
+ .long sys_read
+ .long sys_write
+ .long sys_open /* 5 */
+ .long sys_close
+ .long sys_waitpid
+ .long sys_creat
+ .long sys_link
+ .long sys_unlink /* 10 */
+ .long sys_execve
+ .long sys_chdir
+ .long sys_time
+ .long sys_mknod
+ .long sys_chmod /* 15 */
+ .long sys_chown
+ .long sys_break
+ .long sys_stat
+ .long sys_lseek
+ .long sys_getpid /* 20 */
+ .long sys_mount
+ .long sys_umount
+ .long sys_setuid
+ .long sys_getuid
+ .long sys_stime /* 25 */
+ .long sys_ptrace
+ .long sys_alarm
+ .long sys_fstat
+ .long sys_pause
+ .long sys_utime /* 30 */
+ .long sys_stty
+ .long sys_gtty
+ .long sys_access
+ .long sys_nice
+ .long sys_ftime /* 35 */
+ .long sys_sync
+ .long sys_kill
+ .long sys_rename
+ .long sys_mkdir
+ .long sys_rmdir /* 40 */
+ .long sys_dup
+ .long sys_pipe
+ .long sys_times
+ .long sys_prof
+ .long sys_brk /* 45 */
+ .long sys_setgid
+ .long sys_getgid
+ .long sys_signal
+ .long sys_geteuid
+ .long sys_getegid /* 50 */
+ .long sys_acct
+ .long sys_phys
+ .long sys_lock
+ .long sys_ioctl
+ .long sys_fcntl /* 55 */
+ .long sys_mpx
+ .long sys_setpgid
+ .long sys_ulimit
+ .long sys_olduname
+ .long sys_umask /* 60 */
+ .long sys_chroot
+ .long sys_ustat
+ .long sys_dup2
+ .long sys_getppid
+ .long sys_getpgrp /* 65 */
+ .long sys_setsid
+ .long sys_sigaction
+ .long sys_sgetmask
+ .long sys_ssetmask
+ .long sys_setreuid /* 70 */
+ .long sys_setregid
+ .long sys_sigsuspend
+ .long sys_sigpending
+ .long sys_sethostname
+ .long sys_setrlimit /* 75 */
+ .long sys_getrlimit
+ .long sys_getrusage
+ .long sys_gettimeofday
+ .long sys_settimeofday
+ .long sys_getgroups /* 80 */
+ .long sys_setgroups
+ .long sys_select
+ .long sys_symlink
+ .long sys_lstat
+ .long sys_readlink /* 85 */
+ .long sys_uselib
+ .long sys_swapon
+ .long sys_reboot
+ .long old_readdir /* was sys_readdir */
+ .long sys_mmap /* 90 */
+ .long sys_munmap
+ .long sys_truncate
+ .long sys_ftruncate
+ .long sys_fchmod
+ .long sys_fchown /* 95 */
+ .long sys_getpriority
+ .long sys_setpriority
+ .long sys_profil
+ .long sys_statfs
+ .long sys_fstatfs /* 100 */
+ .long sys_ioperm
+ .long sys_socketcall
+ .long sys_syslog
+ .long sys_setitimer
+ .long sys_getitimer /* 105 */
+ .long sys_newstat
+ .long sys_newlstat
+ .long sys_newfstat
+ .long sys_uname
+ .long sys_iopl /* 110 */
+ .long sys_vhangup
+ .long sys_idle
+ .long sys_vm86
+ .long sys_wait4
+ .long sys_swapoff /* 115 */
+ .long sys_sysinfo
+ .long sys_ipc
+ .long sys_fsync
+ .long sys_sigreturn
+ .long sys_clone /* 120 */
+ .long sys_setdomainname
+ .long sys_newuname
+ .long sys_modify_ldt
+ .long sys_adjtimex
+ .long sys_mprotect /* 125 */
+ .long sys_sigprocmask
+ .long sys_create_module
+ .long sys_init_module
+ .long sys_delete_module
+ .long sys_get_kernel_syms /* 130 */
+ .long sys_quotactl
+ .long sys_getpgid
+ .long sys_fchdir
+ .long sys_bdflush
+ .long sys_sysfs /* 135 */
+ .long sys_personality
+ .long 0 /* for afs_syscall */
+ .long sys_setfsuid
+ .long sys_setfsgid
+ .long sys_llseek /* 140 */
+ .long sys_getdents
+ .long sys_newselect
+ .long sys_flock
+ .long sys_msync
+ .long sys_readv /* 145 */
+ .long sys_writev
+ .long sys_getsid
+ .long sys_fdatasync
+ .long sys_sysctl
+ .long sys_mlock /* 150 */
+ .long sys_munlock
+ .long sys_mlockall
+ .long sys_munlockall
+ .long sys_sched_setparam
+ .long sys_sched_getparam /* 155 */
+ .long sys_sched_setscheduler
+ .long sys_sched_getscheduler
+ .long sys_sched_yield
+ .long sys_sched_get_priority_max
+ .long sys_sched_get_priority_min /* 160 */
+ .long sys_sched_rr_get_interval
+ .long sys_nanosleep
+ .long sys_mremap
+ .space (NR_syscalls-163)*4
+
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
new file mode 100644
index 000000000..e63e5c04a
--- /dev/null
+++ b/arch/ppc/kernel/mk_defs.c
@@ -0,0 +1,161 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ */
+#define MK_DEFS
+#include <stdio.h>
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+
+extern int errno;
+
+main(int argc, char *argv[])
+{
+ FILE *out;
+ struct task_struct task;
+ struct thread_struct tss;
+ struct pt_regs regs;
+ if (!(out = fopen(argv[1], "w")))
+ {
+ fprintf(stderr, "Can't create output file: %s\n", strerror(errno));
+ exit(1);
+ }
+ fprintf(out, "/*\n");
+ fprintf(out, " * WARNING! This file is automatically generated - DO NOT EDIT!\n");
+ fprintf(out, " */\n");
+ put_line(out, "STATE", (int)&task.state-(int)&task);
+ put_line(out, "COUNTER", (int)&task.counter-(int)&task);
+ put_line(out, "BLOCKED", (int)&task.blocked-(int)&task);
+ put_line(out, "SIGNAL", (int)&task.signal-(int)&task);
+ put_line(out, "KERNEL_STACK_PAGE", (int)&task.kernel_stack_page-(int)&task);
+ put_line(out, "TSS", (int)&task.tss-(int)&task);
+ put_line(out, "KSP", (int)&tss.ksp-(int)&tss);
+ put_line(out, "LAST_PC", (int)&tss.last_pc-(int)&tss);
+ put_line(out, "USER_STACK", (int)&tss.user_stack-(int)&tss);
+ put_line(out, "PT_REGS", (int)&tss.regs-(int)&tss);
+ put_line(out, "PF_TRACESYS", PF_TRACESYS);
+ put_line(out, "TASK_FLAGS", (int)&task.flags-(int)&task);
+ put_line(out, "MMU_SEG0", (int)&tss.segs[0]-(int)&tss);
+ put_line(out, "MMU_SEG1", (int)&tss.segs[1]-(int)&tss);
+ put_line(out, "MMU_SEG2", (int)&tss.segs[2]-(int)&tss);
+ put_line(out, "MMU_SEG3", (int)&tss.segs[3]-(int)&tss);
+ put_line(out, "MMU_SEG4", (int)&tss.segs[4]-(int)&tss);
+ put_line(out, "MMU_SEG5", (int)&tss.segs[5]-(int)&tss);
+ put_line(out, "MMU_SEG6", (int)&tss.segs[6]-(int)&tss);
+ put_line(out, "MMU_SEG7", (int)&tss.segs[7]-(int)&tss);
+ put_line(out, "MMU_SEG8", (int)&tss.segs[8]-(int)&tss);
+ put_line(out, "MMU_SEG9", (int)&tss.segs[9]-(int)&tss);
+ put_line(out, "MMU_SEG10", (int)&tss.segs[10]-(int)&tss);
+ put_line(out, "MMU_SEG11", (int)&tss.segs[11]-(int)&tss);
+ put_line(out, "MMU_SEG12", (int)&tss.segs[12]-(int)&tss);
+ put_line(out, "MMU_SEG13", (int)&tss.segs[13]-(int)&tss);
+ put_line(out, "MMU_SEG14", (int)&tss.segs[14]-(int)&tss);
+ put_line(out, "MMU_SEG15", (int)&tss.segs[15]-(int)&tss);
+ put_line(out, "TSS_FPR0", (int)&tss.fpr[0]-(int)&tss);
+ put_line(out, "TSS_FPR1", (int)&tss.fpr[1]-(int)&tss);
+ put_line(out, "TSS_FPR2", (int)&tss.fpr[2]-(int)&tss);
+ put_line(out, "TSS_FPR3", (int)&tss.fpr[3]-(int)&tss);
+ put_line(out, "TSS_FPR4", (int)&tss.fpr[4]-(int)&tss);
+ put_line(out, "TSS_FPR5", (int)&tss.fpr[5]-(int)&tss);
+ put_line(out, "TSS_FPR6", (int)&tss.fpr[6]-(int)&tss);
+ put_line(out, "TSS_FPR7", (int)&tss.fpr[7]-(int)&tss);
+ put_line(out, "TSS_FPR8", (int)&tss.fpr[8]-(int)&tss);
+ put_line(out, "TSS_FPR9", (int)&tss.fpr[9]-(int)&tss);
+ put_line(out, "TSS_FPR10", (int)&tss.fpr[10]-(int)&tss);
+ put_line(out, "TSS_FPR11", (int)&tss.fpr[11]-(int)&tss);
+ put_line(out, "TSS_FPR12", (int)&tss.fpr[12]-(int)&tss);
+ put_line(out, "TSS_FPR13", (int)&tss.fpr[13]-(int)&tss);
+ put_line(out, "TSS_FPR14", (int)&tss.fpr[14]-(int)&tss);
+ put_line(out, "TSS_FPR15", (int)&tss.fpr[15]-(int)&tss);
+ put_line(out, "TSS_FPR16", (int)&tss.fpr[16]-(int)&tss);
+ put_line(out, "TSS_FPR17", (int)&tss.fpr[17]-(int)&tss);
+ put_line(out, "TSS_FPR18", (int)&tss.fpr[18]-(int)&tss);
+ put_line(out, "TSS_FPR19", (int)&tss.fpr[19]-(int)&tss);
+ put_line(out, "TSS_FPR20", (int)&tss.fpr[20]-(int)&tss);
+ put_line(out, "TSS_FPR21", (int)&tss.fpr[21]-(int)&tss);
+ put_line(out, "TSS_FPR22", (int)&tss.fpr[22]-(int)&tss);
+ put_line(out, "TSS_FPR23", (int)&tss.fpr[23]-(int)&tss);
+ put_line(out, "TSS_FPR24", (int)&tss.fpr[24]-(int)&tss);
+ put_line(out, "TSS_FPR25", (int)&tss.fpr[25]-(int)&tss);
+ put_line(out, "TSS_FPR26", (int)&tss.fpr[26]-(int)&tss);
+ put_line(out, "TSS_FPR27", (int)&tss.fpr[27]-(int)&tss);
+ put_line(out, "TSS_FPR28", (int)&tss.fpr[28]-(int)&tss);
+ put_line(out, "TSS_FPR29", (int)&tss.fpr[29]-(int)&tss);
+ put_line(out, "TSS_FPR30", (int)&tss.fpr[30]-(int)&tss);
+ put_line(out, "TSS_FPR31", (int)&tss.fpr[31]-(int)&tss);
+ /* Interrupt register frame */
+ put_line(out, "INT_FRAME_SIZE", sizeof(regs));
+ put_line(out, "GPR0", (int)&regs.gpr[0]-(int)&regs);
+ put_line(out, "GPR1", (int)&regs.gpr[1]-(int)&regs);
+ put_line(out, "GPR2", (int)&regs.gpr[2]-(int)&regs);
+ put_line(out, "GPR3", (int)&regs.gpr[3]-(int)&regs);
+ put_line(out, "GPR4", (int)&regs.gpr[4]-(int)&regs);
+ put_line(out, "GPR5", (int)&regs.gpr[5]-(int)&regs);
+ put_line(out, "GPR6", (int)&regs.gpr[6]-(int)&regs);
+ put_line(out, "GPR7", (int)&regs.gpr[7]-(int)&regs);
+ put_line(out, "GPR8", (int)&regs.gpr[8]-(int)&regs);
+ put_line(out, "GPR9", (int)&regs.gpr[9]-(int)&regs);
+ put_line(out, "GPR10", (int)&regs.gpr[10]-(int)&regs);
+ put_line(out, "GPR11", (int)&regs.gpr[11]-(int)&regs);
+ put_line(out, "GPR12", (int)&regs.gpr[12]-(int)&regs);
+ put_line(out, "GPR13", (int)&regs.gpr[13]-(int)&regs);
+ put_line(out, "GPR14", (int)&regs.gpr[14]-(int)&regs);
+ put_line(out, "GPR15", (int)&regs.gpr[15]-(int)&regs);
+ put_line(out, "GPR16", (int)&regs.gpr[16]-(int)&regs);
+ put_line(out, "GPR17", (int)&regs.gpr[17]-(int)&regs);
+ put_line(out, "GPR18", (int)&regs.gpr[18]-(int)&regs);
+ put_line(out, "GPR19", (int)&regs.gpr[19]-(int)&regs);
+ put_line(out, "GPR20", (int)&regs.gpr[20]-(int)&regs);
+ put_line(out, "GPR21", (int)&regs.gpr[21]-(int)&regs);
+ put_line(out, "GPR22", (int)&regs.gpr[22]-(int)&regs);
+ put_line(out, "GPR23", (int)&regs.gpr[23]-(int)&regs);
+ put_line(out, "GPR24", (int)&regs.gpr[24]-(int)&regs);
+ put_line(out, "GPR25", (int)&regs.gpr[25]-(int)&regs);
+ put_line(out, "GPR26", (int)&regs.gpr[26]-(int)&regs);
+ put_line(out, "GPR27", (int)&regs.gpr[27]-(int)&regs);
+ put_line(out, "GPR28", (int)&regs.gpr[28]-(int)&regs);
+ put_line(out, "GPR29", (int)&regs.gpr[29]-(int)&regs);
+ put_line(out, "GPR30", (int)&regs.gpr[30]-(int)&regs);
+ put_line(out, "GPR31", (int)&regs.gpr[31]-(int)&regs);
+ put_line(out, "FPR0", (int)&regs.fpr[0]-(int)&regs);
+ put_line(out, "FPR1", (int)&regs.fpr[1]-(int)&regs);
+ put_line(out, "FPR2", (int)&regs.fpr[2]-(int)&regs);
+ put_line(out, "FPR3", (int)&regs.fpr[3]-(int)&regs);
+ put_line(out, "FPCSR", (int)&regs.fpcsr-(int)&regs);
+ /* Note: these symbols include "_" because they overlap with special register names */
+ put_line(out, "_NIP", (int)&regs.nip-(int)&regs);
+ put_line(out, "_MSR", (int)&regs.msr-(int)&regs);
+ put_line(out, "_CTR", (int)&regs.ctr-(int)&regs);
+ put_line(out, "_LINK", (int)&regs.link-(int)&regs);
+ put_line(out, "_CCR", (int)&regs.ccr-(int)&regs);
+ put_line(out, "_XER", (int)&regs.xer-(int)&regs);
+ put_line(out, "_DAR", (int)&regs.dar-(int)&regs);
+ put_line(out, "_DSISR", (int)&regs.dsisr-(int)&regs);
+ put_line(out, "_HASH1", (int)&regs.hash1-(int)&regs);
+ put_line(out, "_HASH2", (int)&regs.hash2-(int)&regs);
+ put_line(out, "_IMISS", (int)&regs.imiss-(int)&regs);
+ put_line(out, "_DMISS", (int)&regs.dmiss-(int)&regs);
+ put_line(out, "_ICMP", (int)&regs.icmp-(int)&regs);
+ put_line(out, "_DCMP", (int)&regs.dcmp-(int)&regs);
+ put_line(out, "ORIG_GPR3", (int)&regs.orig_gpr3-(int)&regs);
+ put_line(out, "RESULT", (int)&regs.result-(int)&regs);
+ put_line(out, "TRAP", (int)&regs.trap-(int)&regs);
+ put_line(out, "MARKER", (int)&regs.marker-(int)&regs);
+ exit(0);
+}
+
+put_line(FILE *out, char *name, int offset)
+{
+ fprintf(out, "#define %s %d\n", name, offset);
+}
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
new file mode 100644
index 000000000..ff50a6c5e
--- /dev/null
+++ b/arch/ppc/kernel/pci.c
@@ -0,0 +1,488 @@
+/*
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.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;
+
+/* 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 */
+ };
+
+/* #define PCI_DEBUG */
+
+#ifdef PCI_STATS
+int PCI_conversions[2];
+#endif
+
+unsigned long pcibios_init(unsigned long mem_start,
+ unsigned long mem_end)
+{
+ return mem_start;
+}
+
+unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
+{
+ return mem_start;
+}
+
+
+unsigned long
+_LE_to_BE_long(unsigned long val)
+{
+ unsigned char *p = (unsigned char *)&val;
+#ifdef PCI_STATS
+ PCI_conversions[0]++;
+#endif
+ return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0] << 0));
+}
+
+unsigned short
+_LE_to_BE_short(unsigned long val)
+{
+ unsigned char *p = (unsigned char *)&val;
+#ifdef PCI_STATS
+ PCI_conversions[1]++;
+#endif
+ return ((p[3] << 8) | (p[2] << 0));
+}
+
+int
+pcibios_present (void)
+{
+#ifdef PCI_DEBUG
+ printk("PCI [BIOS] present?\n");
+#endif
+ return (1);
+}
+
+int
+pcibios_read_config_dword (unsigned char bus,
+ unsigned char dev, 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 = _LE_to_BE_long(*ptr);
+ }
+#ifdef PCI_DEBUG
+ printk("%x\n", _val);
+#endif
+ *val = _val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+pcibios_read_config_word (unsigned char bus,
+ unsigned char dev, unsigned char offset, unsigned short *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 = 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else
+ {
+ ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+#ifdef PCI_DEBUG
+ printk("[%x] ", ptr);
+#endif
+ _val = _LE_to_BE_short(*ptr);
+ }
+#ifdef PCI_DEBUG
+ printk("%x\n", _val);
+#endif
+ *val = _val;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int
+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)
+ {
+ if (Motherboard_map[dev] <= 4)
+ {
+ *val = 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;
+}
+
+int
+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 = _LE_to_BE_long(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;
+}
+
+int
+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 = _LE_to_BE_short(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;
+}
+
+int
+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;
+#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;
+}
+
+int
+pcibios_find_device (unsigned short vendor, unsigned short device_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *dev)
+{
+ 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;
+}
+
+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);
+ }
+}
+
+/*
+ * Note: This routine has to access the PCI configuration space
+ * for the PCI bridge chip (Intel 82378).
+ */
+
+void route_PCI_interrupts(void)
+{
+ unsigned char *ibc_pirq = (unsigned char *)0x80800860;
+ unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
+ extern unsigned long isBeBox[];
+ int i;
+ /* Decide which motherboard this is & how the PCI interrupts are routed */
+ if (isBeBox[0])
+ {
+ Motherboard_map = BeBox_pci_IRQ_map;
+ Motherboard_routes = BeBox_pci_IRQ_routes;
+ } else
+ { /* Motorola hardware */
+ switch (inb(0x800) & 0xF0)
+ {
+ case 0x10: /* MVME16xx */
+ Motherboard_map = Genesis_pci_IRQ_map;
+ Motherboard_routes = Genesis_pci_IRQ_routes;
+ break;
+ case 0x20: /* 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 = Blackhawk_pci_IRQ_map;
+ Motherboard_routes = Blackhawk_pci_IRQ_routes;
+ break;
+ }
+ }
+ /* Set up mapping from slots */
+ for (i = 1; i <= 4; i++)
+ {
+ ibc_pirq[i-1] = Motherboard_routes[i];
+ }
+ /* Enable PCI interrupts */
+ *ibc_pcicon |= 0x20;
+}
diff --git a/arch/ppc/kernel/port_io.c b/arch/ppc/kernel/port_io.c
new file mode 100644
index 000000000..3693112b2
--- /dev/null
+++ b/arch/ppc/kernel/port_io.c
@@ -0,0 +1,143 @@
+/*
+ * I/O 'port' access routines
+ */
+
+/* This is really only correct for the MVME16xx (PreP)? */
+
+#define _IO_BASE ((unsigned long)0x80000000)
+
+unsigned char
+inb(int port)
+{
+ return (*((unsigned char *)(_IO_BASE+port)));
+}
+
+unsigned short
+inw(int port)
+{
+ return (_LE_to_BE_short(*((unsigned short *)(_IO_BASE+port))));
+}
+
+unsigned long
+inl(int port)
+{
+ return (_LE_to_BE_long(*((unsigned long *)(_IO_BASE+port))));
+}
+
+void insb(int port, char *ptr, int len)
+{
+ unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
+ while (len-- > 0)
+ {
+ *ptr++ = *io_ptr;
+ }
+}
+
+#if 0
+void insw(int port, short *ptr, int len)
+{
+ unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
+ while (len-- > 0)
+ {
+ *ptr++ = _LE_to_BE_short(*io_ptr);
+ }
+}
+#else
+void insw(int port, short *ptr, int len)
+{
+ unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
+ _insw(io_ptr, ptr, len);
+}
+#endif
+
+void insw_unswapped(int port, short *ptr, int len)
+{
+ unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
+ while (len-- > 0)
+ {
+ *ptr++ = *io_ptr;
+ }
+}
+
+void insl(int port, long *ptr, int len)
+{
+ unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+ while (len-- > 0)
+ {
+ *ptr++ = _LE_to_BE_long(*io_ptr);
+ }
+}
+
+unsigned char inb_p(int port) {return (inb(port)); }
+unsigned short inw_p(int port) {return (inw(port)); }
+unsigned long inl_p(int port) {return (inl(port)); }
+
+unsigned char
+outb(unsigned char val,int port)
+{
+ *((unsigned char *)(_IO_BASE+port)) = (val);
+ return (val);
+}
+
+unsigned short
+outw(unsigned short val,int port)
+{
+ *((unsigned short *)(_IO_BASE+port)) = _LE_to_BE_short(val);
+ return (val);
+}
+
+unsigned long
+outl(unsigned long val,int port)
+{
+ *((unsigned long *)(_IO_BASE+port)) = _LE_to_BE_long(val);
+ return (val);
+}
+
+void outsb(int port, char *ptr, int len)
+{
+ unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
+ while (len-- > 0)
+ {
+ *io_ptr = *ptr++;
+ }
+}
+
+#if 0
+void outsw(int port, short *ptr, int len)
+{
+ unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
+ while (len-- > 0)
+ {
+ *io_ptr = _LE_to_BE_short(*ptr++);
+ }
+}
+#else
+void outsw(int port, short *ptr, int len)
+{
+ unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
+ _outsw(io_ptr, ptr, len);
+}
+#endif
+
+void outsw_unswapped(int port, short *ptr, int len)
+{
+ unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
+ while (len-- > 0)
+ {
+ *io_ptr = *ptr++;
+ }
+}
+
+void outsl(int port, long *ptr, int len)
+{
+ unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+ while (len-- > 0)
+ {
+ *io_ptr = _LE_to_BE_long(*ptr++);
+ }
+}
+
+unsigned char outb_p(unsigned char val,int port) { return (outb(val,port)); }
+unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
+unsigned long outl_p(unsigned long val,int port) { return (outl(val,port)); }
+
diff --git a/arch/ppc/kernel/ppc_asm.tmpl b/arch/ppc/kernel/ppc_asm.tmpl
new file mode 100644
index 000000000..b6fa91a3c
--- /dev/null
+++ b/arch/ppc/kernel/ppc_asm.tmpl
@@ -0,0 +1,168 @@
+/*
+ * This file contains all the macros and symbols which define
+ * a PowerPC assembly language environment.
+ */
+
+#define _TEXT()\
+ .text
+
+#if 0 /* Old way */
+#define _EXTERN(n) .##n
+
+#define _GLOBAL(n)\
+ .globl n;\
+n: .long _EXTERN(n);\
+ .globl _EXTERN(n);\
+_EXTERN(n):
+#else
+#define _EXTERN(n) n
+
+#define _GLOBAL(n)\
+ .globl n;\
+n:
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+#define _ORG(n)\
+ .org n
+
+/* Register names */
+#define r0 0
+#define r1 1
+#define r2 2
+#define r3 3
+#define r4 4
+#define r5 5
+#define r6 6
+#define r7 7
+#define r8 8
+#define r9 9
+#define r10 10
+#define r11 11
+#define r12 12
+#define r13 13
+#define r14 14
+#define r15 15
+#define r16 16
+#define r17 17
+#define r18 18
+#define r19 19
+#define r20 20
+#define r21 21
+#define r22 22
+#define r23 23
+#define r24 24
+#define r25 25
+#define r26 26
+#define r27 27
+#define r28 28
+#define r29 29
+#define r30 30
+#define r31 31
+
+#define fr0 0
+#define fr1 1
+#define fr2 2
+#define fr3 3
+#define fr4 4
+#define fr5 5
+#define fr6 6
+#define fr7 7
+#define fr8 8
+#define fr9 9
+#define fr10 10
+#define fr11 11
+#define fr12 12
+#define fr13 13
+#define fr14 14
+#define fr15 15
+#define fr16 16
+#define fr17 17
+#define fr18 18
+#define fr19 19
+#define fr20 20
+#define fr21 21
+#define fr22 22
+#define fr23 23
+#define fr24 24
+#define fr25 25
+#define fr26 26
+#define fr27 27
+#define fr28 28
+#define fr29 29
+#define fr30 30
+#define fr31 31
+
+/* Some special registers */
+
+#define TBRU 269 /* Time base Upper/Lower (Reading) */
+#define TBRL 268
+#define TBWU 284 /* Time base Upper/Lower (Writing) */
+#define TBWL 285
+#define XER 1
+#define LR 8
+#define CTR 9
+#define HID0 1008 /* Hardware Implementation */
+#define PVR 287 /* Processor Version */
+#define IBAT0U 528 /* Instruction BAT #0 Upper/Lower */
+#define IBAT0L 529
+#define IBAT1U 530 /* Instruction BAT #1 Upper/Lower */
+#define IBAT1L 531
+#define IBAT2U 532 /* Instruction BAT #2 Upper/Lower */
+#define IBAT2L 533
+#define IBAT3U 534 /* Instruction BAT #3 Upper/Lower */
+#define IBAT3L 535
+#define DBAT0U 536 /* Data BAT #0 Upper/Lower */
+#define DBAT0L 537
+#define DBAT1U 538 /* Data BAT #1 Upper/Lower */
+#define DBAT1L 539
+#define DBAT2U 540 /* Data BAT #2 Upper/Lower */
+#define DBAT2L 541
+#define DBAT3U 542 /* Data BAT #3 Upper/Lower */
+#define DBAT3L 543
+#define DMISS 976 /* TLB Lookup/Refresh registers */
+#define DCMP 977
+#define HASH1 978
+#define HASH2 979
+#define IMISS 980
+#define ICMP 981
+#define RPA 982
+#define SDR1 25 /* MMU hash base register */
+#define DAR 19 /* Data Address Register */
+#define SPR0 272 /* Supervisor Private Registers */
+#define SPR1 273
+#define SPR2 274
+#define SPR3 275
+#define DSISR 18
+#define SRR0 26 /* Saved Registers (exception) */
+#define SRR1 27
+#define IABR 1010 /* Instruction Address Breakpoint */
+#define DEC 22 /* Decrementer */
+#define EAR 282 /* External Address Register */
+
+/* Segment Registers */
+#define SR0 0
+#define SR1 1
+#define SR2 2
+#define SR3 3
+#define SR4 4
+#define SR5 5
+#define SR6 6
+#define SR7 7
+#define SR8 8
+#define SR9 9
+#define SR10 10
+#define SR11 11
+#define SR12 12
+#define SR13 13
+#define SR14 14
+#define SR15 15
+
+/* Missing instructions */
+#define bdne bc 0,2,
+
+#include "asm/ppc_machine.h"
diff --git a/arch/ppc/kernel/ppc_defs.h b/arch/ppc/kernel/ppc_defs.h
new file mode 100644
index 000000000..1965f83e1
--- /dev/null
+++ b/arch/ppc/kernel/ppc_defs.h
@@ -0,0 +1,119 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
+#define STATE 0
+#define COUNTER 4
+#define BLOCKED 16
+#define SIGNAL 12
+#define KERNEL_STACK_PAGE 88
+#define TSS 528
+#define KSP 0
+#define LAST_PC 72
+#define USER_STACK 76
+#define PT_REGS 340
+#define PF_TRACESYS 32
+#define TASK_FLAGS 20
+#define MMU_SEG0 8
+#define MMU_SEG1 12
+#define MMU_SEG2 16
+#define MMU_SEG3 20
+#define MMU_SEG4 24
+#define MMU_SEG5 28
+#define MMU_SEG6 32
+#define MMU_SEG7 36
+#define MMU_SEG8 40
+#define MMU_SEG9 44
+#define MMU_SEG10 48
+#define MMU_SEG11 52
+#define MMU_SEG12 56
+#define MMU_SEG13 60
+#define MMU_SEG14 64
+#define MMU_SEG15 68
+#define TSS_FPR0 80
+#define TSS_FPR1 88
+#define TSS_FPR2 96
+#define TSS_FPR3 104
+#define TSS_FPR4 112
+#define TSS_FPR5 120
+#define TSS_FPR6 128
+#define TSS_FPR7 136
+#define TSS_FPR8 144
+#define TSS_FPR9 152
+#define TSS_FPR10 160
+#define TSS_FPR11 168
+#define TSS_FPR12 176
+#define TSS_FPR13 184
+#define TSS_FPR14 192
+#define TSS_FPR15 200
+#define TSS_FPR16 208
+#define TSS_FPR17 216
+#define TSS_FPR18 224
+#define TSS_FPR19 232
+#define TSS_FPR20 240
+#define TSS_FPR21 248
+#define TSS_FPR22 256
+#define TSS_FPR23 264
+#define TSS_FPR24 272
+#define TSS_FPR25 280
+#define TSS_FPR26 288
+#define TSS_FPR27 296
+#define TSS_FPR28 304
+#define TSS_FPR29 312
+#define TSS_FPR30 320
+#define TSS_FPR31 328
+#define INT_FRAME_SIZE 384
+#define GPR0 56
+#define GPR1 60
+#define GPR2 64
+#define GPR3 68
+#define GPR4 72
+#define GPR5 76
+#define GPR6 80
+#define GPR7 84
+#define GPR8 88
+#define GPR9 92
+#define GPR10 96
+#define GPR11 100
+#define GPR12 104
+#define GPR13 108
+#define GPR14 112
+#define GPR15 116
+#define GPR16 120
+#define GPR17 124
+#define GPR18 128
+#define GPR19 132
+#define GPR20 136
+#define GPR21 140
+#define GPR22 144
+#define GPR23 148
+#define GPR24 152
+#define GPR25 156
+#define GPR26 160
+#define GPR27 164
+#define GPR28 168
+#define GPR29 172
+#define GPR30 176
+#define GPR31 180
+#define FPR0 248
+#define FPR1 256
+#define FPR2 264
+#define FPR3 272
+#define FPCSR 280
+#define _NIP 184
+#define _MSR 188
+#define _CTR 192
+#define _LINK 196
+#define _CCR 200
+#define _XER 204
+#define _DAR 208
+#define _DSISR 212
+#define _HASH1 216
+#define _HASH2 220
+#define _IMISS 224
+#define _DMISS 228
+#define _ICMP 232
+#define _DCMP 236
+#define ORIG_GPR3 240
+#define RESULT 244
+#define TRAP 288
+#define MARKER 292
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
new file mode 100644
index 000000000..11ddb7678
--- /dev/null
+++ b/arch/ppc/kernel/process.c
@@ -0,0 +1,270 @@
+/*
+ * linux/arch/ppc/kernel/process.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted for PowerPC by Gary Thomas
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#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/ldt.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <asm/ppc_machine.h>
+
+int
+dump_fpu()
+{
+ return (1);
+}
+
+void
+switch_to(struct task_struct *prev, struct task_struct *new)
+{
+ struct pt_regs *regs;
+ struct thread_struct *new_tss, *old_tss;
+ int s = _disable_interrupts();
+ regs = new->tss.ksp;
+#if 0
+ printk("Task %x(%d) -> %x(%d)", current, current->pid, new, new->pid);
+ printk(" - IP: %x, SR: %x, SP: %x\n", regs->nip, regs->msr, regs);
+#endif
+ new_tss = &new->tss;
+ old_tss = &current->tss;
+ current_set[0] = new; /* FIX ME! */
+ _switch(old_tss, new_tss);
+#if 0
+ printk("Back in task %x(%d)\n", current, current->pid);
+#endif
+ _enable_interrupts(s);
+}
+
+asmlinkage int sys_idle(void)
+{
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* endless idle loop with no priority at all */
+ current->counter = -100;
+ for (;;) {
+ schedule();
+ }
+}
+
+void hard_reset_now(void)
+{
+ halt();
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ _panic("show_regs");
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+}
+
+void
+release_thread(struct task_struct *t)
+{
+}
+
+/*
+ * Copy a thread..
+ */
+void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ struct task_struct * p, struct pt_regs * regs)
+{
+ int i;
+ SEGREG *segs;
+ struct pt_regs * childregs;
+#if 0
+printk("copy thread - NR: %d, Flags: %x, USP: %x, Task: %x, Regs: %x\n", nr, clone_flags, usp, p, regs);
+#endif
+ /* Construct segment registers */
+ segs = p->tss.segs;
+ for (i = 0; i < 8; i++)
+ {
+ segs[i].ks = 0;
+ segs[i].kp = 1;
+ segs[i].vsid = i | (nr << 4);
+ }
+ if ((p->mm->context == 0) || (p->mm->count == 1))
+ {
+ p->mm->context = (nr<<4);
+#if 0
+printk("Setting MM[%x] Context = %x Task = %x Current = %x/%x\n", p->mm, p->mm->context, p, current, current->mm);
+#endif
+ }
+ /* Last 8 are shared with kernel & everybody else... */
+ for (i = 8; i < 16; i++)
+ {
+ segs[i].ks = 0;
+ segs[i].kp = 1;
+ segs[i].vsid = i;
+ }
+ /* Copy registers */
+#ifdef STACK_HAS_TWO_PAGES
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + 2*PAGE_SIZE)) - 2;
+#else
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + 1*PAGE_SIZE)) - 2;
+#endif
+ *childregs = *regs; /* STRUCT COPY */
+ childregs->gpr[3] = 0; /* Result from fork() */
+ p->tss.ksp = childregs;
+ if (usp >= (unsigned long)regs)
+ { /* Stack is in kernel space - must adjust */
+ childregs->gpr[1] = childregs+1;
+ } else
+ { /* Provided stack is in user space */
+ childregs->gpr[1] = usp;
+ }
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+}
+
+#if 0
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
+{
+ regs->nip = eip;
+ regs->gpr[1] = esp;
+ regs->msr = MSR_USER;
+#if 0
+{
+ int len;
+ len = (unsigned long)0x80000000 - esp;
+ if (len > 128) len = 128;
+ printk("Start thread [%x] at PC: %x, SR: %x, SP: %x\n", regs, eip, regs->msr, esp);
+ dump_buf(esp, len);
+ dump_buf(eip, 0x80);
+}
+#endif
+}
+#endif
+
+asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+{
+ return do_fork(SIGCHLD, regs->gpr[1], regs);
+}
+
+/*
+ * sys_execve() executes a new program.
+ *
+ * This works due to the PowerPC calling sequence: the first 6 args
+ * are gotten from registers, while the rest is on the stack, so
+ * we get a0-a5 for free, and then magically find "struct pt_regs"
+ * on the stack for us..
+ *
+ * Don't do this at home.
+ */
+asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs *regs)
+{
+ int error;
+ char * filename;
+
+ error = getname((char *) a0, &filename);
+ if (error)
+ {
+printk("Error getting EXEC name: %d\n", error);
+ return error;
+ }
+ flush_instruction_cache();
+ error = do_execve(filename, (char **) a1, (char **) a2, regs);
+#if 0
+if (error)
+{
+printk("EXECVE - file = '%s', error = %d\n", filename, error);
+}
+#endif
+ putname(filename);
+ return error;
+}
+
+/*
+ * This doesn't actually work correctly like this: we need to do the
+ * same stack setups that fork() does first.
+ */
+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;
+ res = do_fork(clone_flags, regs->gpr[1], regs);
+ return res;
+}
+
+void
+print_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ printk("... Call backtrace:\n");
+ while (*sp)
+ {
+ printk("%08X ", sp[1]);
+ sp = *sp;
+ if (++cnt == 8)
+ {
+ printk("\n");
+ }
+ if (cnt > 32) break;
+ }
+ printk("\n");
+}
+
+void
+print_user_backtrace(unsigned long *sp)
+{
+ int cnt = 0;
+ printk("... [User] Call backtrace:\n");
+ while (valid_addr(sp) && *sp)
+ {
+ printk("%08X ", sp[1]);
+ sp = *sp;
+ if (++cnt == 8)
+ {
+ printk("\n");
+ }
+ if (cnt > 16) break;
+ }
+ printk("\n");
+}
+
+void
+print_kernel_backtrace(void)
+{
+ unsigned long *_get_SP(void);
+ print_backtrace(_get_SP());
+}
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
new file mode 100644
index 000000000..dc4012f57
--- /dev/null
+++ b/arch/ppc/kernel/ptrace.c
@@ -0,0 +1,579 @@
+/*
+ * linux/arch/ppc/kernel/ptrace.c
+ *
+ * Copyright (C) 1994 by Hamish Macdonald
+ * Taken from linux/kernel/ptrace.c and modified for M680x0.
+ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * Adapted from 'linux/arch/m68k/kernel/ptrace.c'
+ * PowerPC version by Gary Thomas (gdt@linuxppc.org)
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#include <stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* Find the stack offset for a register, relative to tss.ksp. */
+#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
+/* Mapping from PT_xxx to the stack offset at which the register is
+ saved. Notice that usp has no stack-slot and needs to be treated
+ specially (see get_reg/put_reg below). */
+static int regoff[] = {
+};
+
+/* change a pid into a task struct. */
+static inline struct task_struct * get_task(int pid)
+{
+ int i;
+
+ for (i = 1; i < NR_TASKS; i++) {
+ if (task[i] != NULL && (task[i]->pid == pid))
+ return task[i];
+ }
+ return NULL;
+}
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+ struct pt_regs *regs = task->tss.regs;
+ if (regno <= PT_R31)
+ {
+ return (regs->gpr[regno]);
+ } else
+ if (regno == PT_NIP)
+ {
+ return (regs->nip);
+ } else
+ if (regno == PT_MSR)
+ {
+ return (regs->msr);
+ } else
+ if (regno == PT_ORIG_R3)
+ {
+ return (regs->orig_gpr3);
+ } else
+ if (regno == PT_CTR)
+ {
+ return (regs->ctr);
+ } else
+ if (regno == PT_LNK)
+ {
+ return (regs->link);
+ } else
+ if (regno == PT_XER)
+ {
+ return (regs->xer);
+ } else
+ if (regno == PT_CCR)
+ {
+ return (regs->ccr);
+ }
+ return (0);
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, int regno,
+ unsigned long data)
+{
+ struct pt_regs *regs = task->tss.regs;
+ if (regno <= PT_R31)
+ {
+ regs->gpr[regno] = data;
+ } else
+ if (regno == PT_NIP)
+ {
+ regs->nip = data;
+ } else
+ if (regno == PT_MSR)
+ {
+ regs->msr = data;
+ } else
+ if (regno == PT_CTR)
+ {
+ regs->ctr = data;
+ } else
+ if (regno == PT_LNK)
+ {
+ regs->link = data;
+ } else
+ if (regno == PT_XER)
+ {
+ regs->xer = data;
+ } else
+ if (regno == PT_CCR)
+ {
+ regs->ccr = data;
+ } else
+ { /* Invalid register */
+ return (-1);
+ }
+ return (0);
+}
+
+static inline
+set_single_step(struct task_struct *task)
+{
+ struct pt_regs *regs = task->tss.regs;
+printk("Set single step - Task: %x, Regs: %x", task, regs);
+printk(", MSR: %x/", regs->msr);
+ regs->msr |= MSR_SE;
+printk("%x\n", regs->msr);
+}
+
+static inline
+clear_single_step(struct task_struct *task)
+{
+ struct pt_regs *regs = task->tss.regs;
+ regs->msr &= ~MSR_SE;
+}
+
+/*
+ * This routine gets a long from any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ */
+static unsigned long get_long(struct task_struct * tsk,
+ struct vm_area_struct * vma, unsigned long addr)
+{
+ pgd_t * pgdir;
+ pmd_t * pgmiddle;
+ pte_t * pgtable;
+ unsigned long page;
+
+repeat:
+ pgdir = pgd_offset(vma->vm_mm, addr);
+ if (pgd_none(*pgdir)) {
+ do_no_page(tsk, vma, addr, 0);
+ goto repeat;
+ }
+ if (pgd_bad(*pgdir)) {
+ printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+ pgd_clear(pgdir);
+ return 0;
+ }
+ pgmiddle = pmd_offset(pgdir,addr);
+ if (pmd_none(*pgmiddle)) {
+ do_no_page(tsk, vma, addr, 0);
+ goto repeat;
+ }
+ if (pmd_bad(*pgmiddle)) {
+ printk("ptrace: bad page directory %08lx\n",
+ pmd_val(*pgmiddle));
+ pmd_clear(pgmiddle);
+ return 0;
+ }
+ pgtable = pte_offset(pgmiddle, addr);
+ if (!pte_present(*pgtable)) {
+ do_no_page(tsk, vma, addr, 0);
+ goto repeat;
+ }
+ page = pte_page(*pgtable);
+/* this is a hack for non-kernel-mapped video buffers and similar */
+ if (page >= high_memory)
+ return 0;
+ page += addr & ~PAGE_MASK;
+ return *(unsigned long *) page;
+}
+
+/*
+ * This routine puts a long into any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ * Now keeps R/W state of page so that a text page stays readonly
+ * even if a debugger scribbles breakpoints into it. -M.U-
+ */
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
+ unsigned long data)
+{
+ pgd_t *pgdir;
+ pmd_t *pgmiddle;
+ pte_t *pgtable;
+ unsigned long page;
+
+repeat:
+ pgdir = pgd_offset(vma->vm_mm, addr);
+ if (!pgd_present(*pgdir)) {
+ do_no_page(tsk, vma, addr, 1);
+ goto repeat;
+ }
+ if (pgd_bad(*pgdir)) {
+ printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+ pgd_clear(pgdir);
+ return;
+ }
+ pgmiddle = pmd_offset(pgdir,addr);
+ if (pmd_none(*pgmiddle)) {
+ do_no_page(tsk, vma, addr, 1);
+ goto repeat;
+ }
+ if (pmd_bad(*pgmiddle)) {
+ printk("ptrace: bad page directory %08lx\n",
+ pmd_val(*pgmiddle));
+ pmd_clear(pgmiddle);
+ return;
+ }
+ pgtable = pte_offset(pgmiddle, addr);
+ if (!pte_present(*pgtable)) {
+ do_no_page(tsk, vma, addr, 1);
+ goto repeat;
+ }
+ page = pte_page(*pgtable);
+ if (!pte_write(*pgtable)) {
+ do_wp_page(tsk, vma, addr, 2);
+ goto repeat;
+ }
+/* this is a hack for non-kernel-mapped video buffers and similar */
+ if (page < high_memory) {
+ *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+ }
+/* 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 */
+ *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+ flush_tlb_all();
+}
+
+static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
+{
+ struct vm_area_struct * vma;
+
+ addr &= PAGE_MASK;
+ vma = find_vma(tsk,addr);
+ if (!vma)
+ return NULL;
+ if (vma->vm_start <= addr)
+ return vma;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ return NULL;
+ if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
+ return NULL;
+ vma->vm_offset -= vma->vm_start - addr;
+ vma->vm_start = addr;
+ return vma;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls get_long() to read a long.
+ */
+static int read_long(struct task_struct * tsk, unsigned long addr,
+ unsigned long * result)
+{
+ struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+ if (!vma)
+ return -EIO;
+ if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
+ unsigned long low,high;
+ struct vm_area_struct * vma_low = vma;
+
+ if (addr + sizeof(long) >= vma->vm_end) {
+ vma_low = vma->vm_next;
+ if (!vma_low || vma_low->vm_start != vma->vm_end)
+ return -EIO;
+ }
+ high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
+ low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
+ switch (addr & (sizeof(long)-1)) {
+ case 3:
+ low >>= 8;
+ low |= high << 24;
+ break;
+ case 2:
+ low >>= 16;
+ low |= high << 16;
+ break;
+ case 1:
+ low >>= 24;
+ low |= high << 8;
+ break;
+ }
+ *result = low;
+ } else
+ *result = get_long(tsk, vma,addr);
+ return 0;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls put_long() to write a long.
+ */
+static int write_long(struct task_struct * tsk, unsigned long addr,
+ unsigned long data)
+{
+ struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+ if (!vma)
+ return -EIO;
+ if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
+ unsigned long low,high;
+ struct vm_area_struct * vma_low = vma;
+
+ if (addr + sizeof(long) >= vma->vm_end) {
+ vma_low = vma->vm_next;
+ if (!vma_low || vma_low->vm_start != vma->vm_end)
+ return -EIO;
+ }
+ high = get_long(tsk, vma,addr & ~(sizeof(long)-1));
+ low = get_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1));
+ switch (addr & (sizeof(long)-1)) {
+ case 0: /* shouldn't happen, but safety first */
+ high = data;
+ break;
+ case 3:
+ low &= 0x000000ff;
+ low |= data << 8;
+ high &= ~0xff;
+ high |= data >> 24;
+ break;
+ case 2:
+ low &= 0x0000ffff;
+ low |= data << 16;
+ high &= ~0xffff;
+ high |= data >> 16;
+ break;
+ case 1:
+ low &= 0x00ffffff;
+ low |= data << 24;
+ high &= ~0xffffff;
+ high |= data >> 8;
+ break;
+ }
+ put_long(tsk, vma,addr & ~(sizeof(long)-1),high);
+ put_long(tsk, vma_low,(addr+sizeof(long)) & ~(sizeof(long)-1),low);
+ } else
+ put_long(tsk, vma,addr,data);
+ return 0;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+ struct task_struct *child;
+ struct user * dummy;
+
+ dummy = NULL;
+
+ if (request == PTRACE_TRACEME) {
+ /* are we already being traced? */
+ if (current->flags & PF_PTRACED)
+ return -EPERM;
+ /* set the ptrace bit in the process flags. */
+ current->flags |= PF_PTRACED;
+ return 0;
+ }
+ if (pid == 1) /* you may not mess with init */
+ return -EPERM;
+ if (!(child = get_task(pid)))
+ return -ESRCH;
+ if (request == PTRACE_ATTACH) {
+ if (child == current)
+ return -EPERM;
+ if ((!child->dumpable ||
+ (current->uid != child->euid) ||
+ (current->uid != child->uid) ||
+ (current->gid != child->egid) ||
+ (current->gid != child->gid)) && !suser())
+ return -EPERM;
+ /* the same process cannot be attached many times */
+ if (child->flags & PF_PTRACED)
+ return -EPERM;
+ child->flags |= PF_PTRACED;
+ if (child->p_pptr != current) {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+ send_sig(SIGSTOP, child, 1);
+ return 0;
+ }
+ if (!(child->flags & PF_PTRACED))
+ return -ESRCH;
+ if (child->state != TASK_STOPPED) {
+ if (request != PTRACE_KILL)
+ return -ESRCH;
+ }
+ if (child->p_pptr != current)
+ return -ESRCH;
+
+ switch (request) {
+ /* If I and D space are separate, these will need to be fixed. */
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA: {
+ unsigned long tmp;
+ int res;
+
+ res = read_long(child, addr, &tmp);
+ if (res < 0)
+ return res;
+ res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
+ if (!res)
+ put_user(tmp, (unsigned long *) data);
+ return res;
+ }
+
+ /* read the word at location addr in the USER area. */
+ case PTRACE_PEEKUSR: {
+ unsigned long tmp;
+ int res;
+
+ if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+ return -EIO;
+
+ res = verify_area(VERIFY_WRITE, (void *) data,
+ sizeof(long));
+ if (res)
+ return res;
+ tmp = 0; /* Default return condition */
+ addr = addr >> 2; /* temporary hack. */
+ if (addr < PT_FPR0) {
+ tmp = get_reg(child, addr);
+ }
+#if 0
+ else if (addr >= PT_FPR0 && addr < PT_FPR31)
+ tmp = child->tss.fpr[addr - PT_FPR0];
+#endif
+ else
+ return -EIO;
+ put_user(tmp,(unsigned long *) data);
+ return 0;
+ }
+
+ /* If I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ return write_long(child,addr,data);
+
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+ return -EIO;
+
+ addr = addr >> 2; /* temporary hack. */
+
+ if (addr == PT_ORIG_R3)
+ return -EIO;
+#if 0 /* Let this check be in 'put_reg' */
+ if (addr == PT_SR) {
+ data &= SR_MASK;
+ data <<= 16;
+ data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+ }
+#endif
+ if (addr < PT_FPR0) {
+ if (put_reg(child, addr, data))
+ return -EIO;
+ return 0;
+ }
+#if 0
+ if (addr >= 21 && addr < 48)
+ {
+ child->tss.fp[addr - 21] = data;
+ return 0;
+ }
+#endif
+ return -EIO;
+
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ if ((unsigned long) data >= NSIG)
+ return -EIO;
+ if (request == PTRACE_SYSCALL)
+ child->flags |= PF_TRACESYS;
+ else
+ child->flags &= ~PF_TRACESYS;
+ child->exit_code = data;
+ wake_up_process(child);
+ /* make sure the single step bit is not set. */
+ clear_single_step(child);
+ return 0;
+ }
+
+/*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ case PTRACE_KILL: {
+ if (child->state == TASK_ZOMBIE) /* already dead */
+ return 0;
+ wake_up_process(child);
+ child->exit_code = SIGKILL;
+ /* make sure the single step bit is not set. */
+ clear_single_step(child);
+ return 0;
+ }
+
+ case PTRACE_SINGLESTEP: { /* set the trap flag. */
+ if ((unsigned long) data >= NSIG)
+ return -EIO;
+ child->flags &= ~PF_TRACESYS;
+ set_single_step(child);
+ wake_up_process(child);
+ child->exit_code = data;
+ /* give it a chance to run. */
+ return 0;
+ }
+
+ case PTRACE_DETACH: { /* detach a process that was attached. */
+ if ((unsigned long) data >= NSIG)
+ return -EIO;
+ child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ wake_up_process(child);
+ child->exit_code = data;
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ /* make sure the single step bit is not set. */
+ clear_single_step(child);
+ return 0;
+ }
+
+ default:
+ return -EIO;
+ }
+}
+
+asmlinkage void syscall_trace(void)
+{
+ if ((current->flags & (PF_PTRACED|PF_TRACESYS))
+ != (PF_PTRACED|PF_TRACESYS))
+ return;
+ current->exit_code = SIGTRAP;
+ current->state = TASK_STOPPED;
+ notify_parent(current);
+ schedule();
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (current->exit_code)
+ current->signal |= (1 << (current->exit_code - 1));
+ current->exit_code = 0;
+ return;
+}
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
new file mode 100644
index 000000000..6f330b052
--- /dev/null
+++ b/arch/ppc/kernel/setup.c
@@ -0,0 +1,246 @@
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#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/ldt.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+
+#define SIO_CONFIG_RA 0x398
+#define SIO_CONFIG_RD 0x399
+
+#include <asm/pgtable.h>
+
+extern unsigned long *end_of_DRAM;
+extern PTE *Hash;
+extern unsigned long Hash_size, Hash_mask;
+
+char sda_root[] = "root=/dev/sda1";
+extern int root_mountflags;
+
+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
+
+/*
+ * The format of "screen_info" is strange, and due to early
+ * i386-setup code. This is just enough to make the console
+ * code think we're on a EGA+ colour display.
+ */
+ /* this is changed only in minor ways from the original
+ -- Cort
+ */
+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 */
+};
+
+
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+ return memory_start;
+}
+
+unsigned long find_end_of_memory(void)
+{
+ unsigned char dram_size = inb(0x0804);
+ unsigned long total;
+ extern BAT BAT2;
+printk("DRAM Size = %x\n", dram_size);
+printk("Config registers = %x/%x/%x/%x\n", inb(0x0800), inb(0x0801), inb(0x0802), inb(0x0803));
+ switch (dram_size & 0x07)
+ {
+ case 0:
+ total = 0x08000000; /* 128M */
+ break;
+ case 1:
+ total = 0x02000000; /* 32M */
+ break;
+ case 2:
+ total = 0x00800000; /* 8M */
+ break;
+ case 3:
+ total = 0x00400000; /* 4M - can't happen! */
+ break;
+ case 4:
+ total = 0x10000000; /* 256M */
+ break;
+ case 5:
+ total = 0x04000000; /* 64M */
+ break;
+ case 6:
+ total = 0x01000000; /* 16M */
+ break;
+ case 7:
+ total = 0x04000000; /* Can't happen */
+ break;
+ }
+ switch ((dram_size>>4) & 0x07)
+ {
+ case 0:
+ total += 0x08000000; /* 128M */
+ break;
+ case 1:
+ total += 0x02000000; /* 32M */
+ break;
+ case 2:
+ total += 0x00800000; /* 8M */
+ break;
+ case 3:
+ total += 0x00000000; /* Module not present */
+ break;
+ case 4:
+ total += 0x10000000; /* 256M */
+ break;
+ case 5:
+ total += 0x04000000; /* 64M */
+ break;
+ case 6:
+ total += 0x01000000; /* 16M */
+ break;
+ case 7:
+ total += 0x00000000; /* Module not present */
+ break;
+ }
+/* TEMP */ total = 0x01000000;
+/* _cnpause(); */
+/* CAUTION!! This can be done more elegantly! */
+ if (total < 0x01000000)
+ {
+ Hash_size = HASH_TABLE_SIZE_64K;
+ Hash_mask = HASH_TABLE_MASK_64K;
+ } else
+ {
+ Hash_size = HASH_TABLE_SIZE_128K;
+ Hash_mask = HASH_TABLE_MASK_128K;
+ }
+ switch(total)
+ {
+ case 0x01000000:
+/* BAT2[0][1] = BL_16M;*/
+ break;
+ default:
+ printk("WARNING: setup.c: find_end_of_memory() unknown total ram size %x\n", total);
+ break;
+ }
+
+ Hash = (PTE *)((total-Hash_size)+KERNELBASE);
+ bzero(Hash, Hash_size);
+ return ((unsigned long)Hash);
+}
+
+int size_memory;
+
+/* #define DEFAULT_ROOT_DEVICE 0x0200 /* fd0 */
+#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 */
+
+void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+ extern int _end;
+ extern char cmd_line[];
+ unsigned char reg;
+
+ /* 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! */
+ ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+ /*ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);*/ /* nfs */
+ aux_device_present = 0xaa;
+ /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
+ strcpy(cmd_line,
+ "nfsaddrs=129.138.6.13:129.138.6.90:129.138.6.1:255.255.255.0:pandora");
+ /* strcpy(cmd_line,"root=/dev/sda1");*/
+ *cmdline_p = cmd_line;
+ *memory_start_p = (unsigned long) &_end;
+ *memory_end_p = (unsigned long *)end_of_DRAM;
+ size_memory = *memory_end_p - KERNELBASE; /* Relative size of memory */
+
+#ifdef CONFIG_BLK_DEV_RAM
+ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+ rd_prompt = 0;
+ rd_doload = 0;
+ rd_image_start = 0;
+#endif
+}
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+ return -EIO;
+}
+#if 0
+extern char builtin_ramdisk_image;
+extern long builtin_ramdisk_size;
+
+void
+builtin_ramdisk_init(void)
+{
+ if ((ROOT_DEV == to_kdev_t(DEFAULT_ROOT_DEVICE)) && (builtin_ramdisk_size != 0))
+ {
+ rd_preloaded_init(&builtin_ramdisk_image, builtin_ramdisk_size);
+ } else
+ { /* Not ramdisk - assume root needs to be mounted read only */
+ root_mountflags |= MS_RDONLY;
+ }
+}
+#endif
+#define MAJOR(n) (((n)&0xFF00)>>8)
+#define MINOR(n) ((n)&0x00FF)
+
+int
+get_cpuinfo(char *buffer)
+{
+ int pvr = _get_PVR();
+ char *model;
+ switch (pvr>>16)
+ {
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+ return sprintf(buffer, "PowerPC %s rev %d.%d\n", model, MAJOR(pvr), MINOR(pvr));
+}
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
new file mode 100644
index 000000000..18a0a10d9
--- /dev/null
+++ b/arch/ppc/kernel/signal.c
@@ -0,0 +1,239 @@
+/*
+ * linux/arch/ppc/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Adapted for PowerPC by Gary Thomas
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs)
+{
+ unsigned long mask;
+
+ mask = current->blocked;
+ current->blocked = set & _BLOCKABLE;
+ regs->gpr[3] = -EINTR;
+#if 0
+printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set);
+#endif
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(mask,regs))
+ return -EINTR;
+ }
+}
+
+/*
+ * 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;
+ sc = (struct sigcontext_struct *)regs->gpr[1];
+ current->blocked = sc->oldmask & _BLOCKABLE;
+ int_regs = sc->regs;
+ signo = sc->signal;
+ sc++; /* Pop signal 'context' */
+ if (sc == (struct sigcontext_struct *)(int_regs))
+ { /* Last stacked signal */
+#if 0
+ /* This doesn't work - it blows away the return address! */
+ memcpy(regs, int_regs, sizeof(*regs));
+#else
+ /* Don't mess up 'my' stack frame */
+ memcpy(&regs->gpr, &int_regs->gpr, sizeof(*regs)-sizeof(regs->_overhead));
+#endif
+ if ((int)regs->orig_gpr3 >= 0 &&
+ ((int)regs->result == -ERESTARTNOHAND ||
+ (int)regs->result == -ERESTARTSYS ||
+ (int)regs->result == -ERESTARTNOINTR))
+ {
+ regs->gpr[3] = regs->orig_gpr3;
+ regs->nip -= 4; /* Back up & retry system call */
+ regs->result = 0;
+ }
+ return (regs->result);
+ } else
+ { /* More signals to go */
+ regs->gpr[1] = (unsigned long)sc;
+ regs->gpr[3] = sc->signal;
+ regs->gpr[4] = sc->regs;
+ regs->link = (unsigned long)((sc->regs)+1);
+ regs->nip = sc->handler;
+ return (sc->signal);
+ }
+}
+
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
+{
+ unsigned long mask = ~current->blocked;
+ unsigned long handler_signal = 0;
+ unsigned long *frame = NULL;
+ unsigned long *trampoline;
+ unsigned long *regs_ptr;
+ unsigned long nip = 0;
+ unsigned long signr;
+ int bitno;
+ struct sigcontext_struct *sc;
+ struct sigaction * sa;
+ int s = _disable_interrupts();
+ while ((signr = current->signal & mask)) {
+#if 0
+ signr = ffz(~signr); /* Compute bit # */
+#else
+ for (bitno = 0; bitno < 32; bitno++)
+ {
+ if (signr & (1<<bitno)) break;
+ }
+ signr = bitno;
+#endif
+ current->signal &= ~(1<<signr); /* Clear bit */
+ sa = current->sig->action + signr;
+ signr++;
+ if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ current->exit_code = signr;
+ current->state = TASK_STOPPED;
+ notify_parent(current);
+ schedule();
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+ if (signr == SIGSTOP)
+ continue;
+ if (_S(signr) & current->blocked) {
+ current->signal |= _S(signr);
+ continue;
+ }
+ sa = current->sig->action + signr - 1;
+ }
+ if (sa->sa_handler == SIG_IGN) {
+ if (signr != SIGCHLD)
+ continue;
+ /* check for SIGCHLD: it's special */
+ while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+ /* nothing */;
+ continue;
+ }
+ if (sa->sa_handler == SIG_DFL) {
+ if (current->pid == 1)
+ continue;
+ switch (signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (current->flags & PF_PTRACED)
+ continue;
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+ SA_NOCLDSTOP))
+ notify_parent(current);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGIOT: case SIGFPE: case SIGSEGV:
+ if (current->binfmt && current->binfmt->core_dump) {
+ if (current->binfmt->core_dump(signr, regs))
+ signr |= 0x80;
+ }
+ /* fall through */
+ default:
+ current->signal |= _S(signr & 0x7f);
+ do_exit(signr);
+ }
+ }
+ /*
+ * OK, we're invoking a handler
+ */
+ if ((int)regs->orig_gpr3 >= 0) {
+ if ((int)regs->result == -ERESTARTNOHAND ||
+ ((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
+ (int)regs->result = -EINTR;
+ }
+ handler_signal |= 1 << (signr-1);
+ mask &= ~sa->sa_mask;
+ }
+ if (!handler_signal) /* no handler will be called - return 0 */
+ {
+ _enable_interrupts(s);
+ return 0;
+ }
+ nip = regs->nip;
+ frame = (unsigned long *) regs->gpr[1];
+ /* Build trampoline code on stack */
+ frame -= 2;
+ trampoline = frame;
+ trampoline[0] = 0x38007777; /* li r0,0x7777 */
+ trampoline[1] = 0x44000002; /* sc */
+ frame -= sizeof(*regs) / sizeof(long);
+ regs_ptr = frame;
+ memcpy(regs_ptr, regs, sizeof(*regs));
+ signr = 1;
+ sa = current->sig->action;
+ for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
+ if (mask > handler_signal)
+ break;
+ if (!(mask & handler_signal))
+ continue;
+ frame -= sizeof(struct sigcontext_struct) / sizeof(long);
+ sc = (struct sigcontext_struct *)frame;
+ nip = (unsigned long) sa->sa_handler;
+#if 0 /* Old compiler */
+ nip = *(unsigned long *)nip;
+#endif
+ if (sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ sc->handler = nip;
+ sc->oldmask = current->blocked;
+ sc->regs = (unsigned long)regs_ptr;
+ sc->signal = signr;
+ current->blocked |= sa->sa_mask;
+ regs->gpr[3] = signr;
+ regs->gpr[4] = (unsigned long)regs_ptr;
+ }
+ regs->link = (unsigned long)trampoline;
+ regs->nip = nip;
+ regs->gpr[1] = (unsigned long)sc;
+ /* The DATA cache must be flushed here to insure coherency */
+ /* between the DATA & INSTRUCTION caches. Since we just */
+ /* created an instruction stream using the DATA [cache] space */
+ /* and since the instruction cache will not look in the DATA */
+ /* 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 */
+ flush_instruction_cache();
+ _enable_interrupts(s);
+ return 1;
+}
diff --git a/arch/ppc/kernel/stubs.c b/arch/ppc/kernel/stubs.c
new file mode 100644
index 000000000..b7af6dd44
--- /dev/null
+++ b/arch/ppc/kernel/stubs.c
@@ -0,0 +1,59 @@
+#include <linux/in.h>
+
+void sys_iopl(void) { _panic("sys_iopl"); }
+void sys_vm86(void) { _panic("sys_vm86"); }
+void sys_modify_ldt(void) { _panic("sys_modify_ldt"); }
+
+void sys_ipc(void) {_panic("sys_ipc"); }
+void sys_newselect(void) {_panic("sys_newselect"); }
+
+halt()
+{
+ printk("\n...Halt!\n");
+ abort();
+}
+
+_panic(char *msg)
+{
+ printk("Panic: %s\n", msg);
+ printk("Panic: %s\n", msg);
+ abort();
+}
+
+_warn(char *msg)
+{
+ printk("*** Warning: %s UNIMPLEMENTED!\n", msg);
+}
+
+
+void
+saved_command_line(void)
+{
+ panic("saved_command_line");
+}
+
+void
+KSTK_EIP(void)
+{
+ panic("KSTK_EIP");
+}
+
+void
+KSTK_ESP(void)
+{
+ panic("KSTK_ESP");
+}
+
+void
+scsi_register_module(void)
+{
+ panic("scsi_register_module");
+}
+
+void
+scsi_unregister_module(void)
+{
+ panic("scsi_unregister_module");
+}
+
+
diff --git a/arch/ppc/kernel/support.c b/arch/ppc/kernel/support.c
new file mode 100644
index 000000000..cd2b58b8a
--- /dev/null
+++ b/arch/ppc/kernel/support.c
@@ -0,0 +1,84 @@
+/*
+ * Miscellaneous support routines
+ */
+
+#include <asm/bitops.h>
+
+/*extern __inline__*/ int find_first_zero_bit(void *add, int len)
+{
+ int mask, nr, i;
+ BITFIELD *addr = add;
+ nr = 0;
+ while (len)
+ {
+ if (~*addr != 0)
+ { /* Contains at least one zero */
+ for (i = 0; i < 32; i++, nr++)
+ {
+ mask = BIT(nr);
+ if ((mask & *addr) == 0)
+ {
+ return (nr);
+ }
+ }
+ }
+ len -= 32;
+ addr++;
+ nr += 32;
+ }
+ return (0); /* Shouldn't happen */
+}
+
+/*extern __inline__*/ int find_next_zero_bit(void *add, int last_bit, int nr)
+{
+ int mask, i;
+ BITFIELD *addr = add;
+#if 0
+printk("Find next (%x, %x)", addr, nr);
+#endif
+ addr += nr >> 5;
+#if 0
+printk(" - Pat: %x(%08X)\n", addr, *addr);
+#endif
+ if ((nr & 0x1F) != 0)
+ {
+ if (*addr != 0xFFFFFFFF)
+ { /* At least one more bit available in this longword */
+ for (i = (nr&0x1F); i < 32; i++, nr++)
+ {
+ mask = BIT(nr);
+ if ((mask & *addr) == 0)
+ {
+#if 0
+printk("(1)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
+#endif
+ return (nr);
+ }
+ }
+ }
+ addr++;
+ nr = (nr + 0x1F) & ~0x1F;
+ }
+ while (nr < last_bit)
+ {
+ if (*addr != 0xFFFFFFFF)
+ { /* Contains at least one zero */
+ for (i = 0; i < 32; i++, nr++)
+ {
+ mask = BIT(nr);
+ if ((mask & *addr) == 0)
+ {
+#if 0
+printk("(2)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
+#endif
+ return (nr);
+ }
+ }
+ }
+ addr++;
+ nr += 32;
+ }
+ return (nr); /* Shouldn't happen */
+}
+
+
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
new file mode 100644
index 000000000..7dd34510c
--- /dev/null
+++ b/arch/ppc/kernel/syscalls.c
@@ -0,0 +1,188 @@
+/*
+ * linux/arch/ppc/kernel/sys_ppc.c
+ *
+ * Adapted from the i386 version by Gary Thomas
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/PPC
+ * platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+
+/*
+ * 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)
+{
+ int error;
+ error = verify_area(VERIFY_WRITE,fildes,8);
+ if (error)
+ return error;
+ error = do_pipe(fildes);
+ if (error)
+ return error;
+ return 0;
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
+ int flags, int fd, off_t offset)
+{
+ struct file * file = NULL;
+
+ if (!(flags & MAP_ANONYMOUS)) {
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ }
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+ return do_mmap(file, addr, len, prot, flags, offset);
+}
+
+#if 0
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+asmlinkage int old_mmap(unsigned long *buffer)
+{
+ int error;
+ unsigned long flags;
+ struct file * file = NULL;
+
+ error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
+ if (error)
+ return error;
+ flags = get_user(buffer+3);
+ if (!(flags & MAP_ANONYMOUS)) {
+ unsigned long fd = get_user(buffer+4);
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ }
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ return do_mmap(file, get_user(buffer), get_user(buffer+1),
+ get_user(buffer+2), flags, get_user(buffer+5));
+}
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+asmlinkage int old_select(unsigned long *buffer)
+{
+ int n;
+ fd_set *inp;
+ fd_set *outp;
+ fd_set *exp;
+ struct timeval *tvp;
+
+ n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
+ if (n)
+ return n;
+ n = get_user(buffer);
+ inp = (fd_set *) get_user(buffer+1);
+ outp = (fd_set *) get_user(buffer+2);
+ exp = (fd_set *) get_user(buffer+3);
+ tvp = (struct timeval *) get_user(buffer+4);
+ return sys_select(n, inp, outp, exp, tvp);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+{
+ int version;
+
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ if (call <= SEMCTL)
+ switch (call) {
+ case SEMOP:
+ return sys_semop (first, (struct sembuf *)ptr, second);
+ case SEMGET:
+ return sys_semget (first, second, third);
+ case SEMCTL: {
+ union semun fourth;
+ int err;
+ if (!ptr)
+ return -EINVAL;
+ if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
+ return err;
+ fourth.__pad = (void *) get_fs_long(ptr);
+ return sys_semctl (first, second, third, fourth);
+ }
+ default:
+ return -EINVAL;
+ }
+ if (call <= MSGCTL)
+ switch (call) {
+ case MSGSND:
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
+ second, third);
+ case MSGRCV:
+ switch (version) {
+ case 0: {
+ struct ipc_kludge tmp;
+ int err;
+ if (!ptr)
+ return -EINVAL;
+ if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+ return err;
+ memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
+ sizeof (tmp));
+ return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+ }
+ case 1: default:
+ return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+ }
+ case MSGGET:
+ return sys_msgget ((key_t) first, second);
+ case MSGCTL:
+ return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+ default:
+ return -EINVAL;
+ }
+ if (call <= SHMCTL)
+ switch (call) {
+ case SHMAT:
+ switch (version) {
+ case 0: default: {
+ ulong raddr;
+ int err;
+ if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
+ return err;
+ err = sys_shmat (first, (char *) ptr, second, &raddr);
+ if (err)
+ return err;
+ put_fs_long (raddr, (ulong *) third);
+ return 0;
+ }
+ case 1: /* iBCS2 emulator entry point */
+ if (get_fs() != get_ds())
+ return -EINVAL;
+ return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+ }
+ case SHMDT:
+ return sys_shmdt ((char *)ptr);
+ case SHMGET:
+ return sys_shmget (first, second, third);
+ case SHMCTL:
+ return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+#endif
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
new file mode 100644
index 000000000..a0e2e0534
--- /dev/null
+++ b/arch/ppc/kernel/time.c
@@ -0,0 +1,336 @@
+/*
+ * linux/arch/i386/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * Adapted for PowerPC (PreP) by Gary Thomas
+ *
+ * This file contains the PC-specific time handling details:
+ * reading the RTC at bootup, etc..
+ * 1994-07-02 Alan Modra
+ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ * 1995-03-26 Markus Kuhn
+ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
+ * precision CMOS clock update
+ */
+#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/segment.h>
+#include <asm/io.h>
+#include <asm/nvram.h>
+#include <asm/mc146818rtc.h>
+
+#include <linux/timex.h>
+#include <linux/config.h>
+
+extern int isBeBox[];
+
+#define TIMER_IRQ 0
+
+/* Cycle counter value at the previous timer interrupt.. */
+static unsigned long long last_timer_cc = 0;
+static unsigned long long init_timer_cc = 0;
+
+static inline int CMOS_READ(int addr)
+{
+ outb(addr>>8, NVRAM_AS1);
+ outb(addr, NVRAM_AS0);
+ return (inb(NVRAM_DATA));
+}
+
+/* This function must be called with interrupts disabled
+ * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
+ *
+ * However, the pc-audio speaker driver changes the divisor so that
+ * it gets interrupted rather more often - it loads 64 into the
+ * counter rather than 11932! This has an adverse impact on
+ * do_gettimeoffset() -- it stops working! What is also not
+ * good is that the interval that our timer function gets called
+ * is no longer 10.0002 ms, but 9.9767 ms. To get around this
+ * would require using a different timing source. Maybe someone
+ * could use the RTC - I know that this can interrupt at frequencies
+ * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
+ * it so that at startup, the timer code in sched.c would select
+ * using either the RTC or the 8253 timer. The decision would be
+ * based on whether there was any other device around that needed
+ * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
+ * and then do some jiggery to have a version of do_timer that
+ * advanced the clock by 1/1024 s. Every time that reached over 1/100
+ * of a second, then do all the old code. If the time was kept correct
+ * then do_gettimeoffset could just return 0 - there is no low order
+ * divider that can be accessed.
+ *
+ * Ideally, you would be able to use the RTC for the speaker driver,
+ * but it appears that the speaker driver really needs interrupt more
+ * often than every 120 us or so.
+ *
+ * Anyway, this needs more thought.... pjsg (1993-08-28)
+ *
+ * If you are really that interested, you should be reading
+ * comp.protocols.time.ntp!
+ */
+
+#define TICK_SIZE tick
+
+static unsigned long do_slow_gettimeoffset(void)
+{
+ int count;
+ unsigned long offset = 0;
+
+ /* timer count may underflow right here */
+ outb_p(0x00, 0x43); /* latch the count ASAP */
+ count = inb_p(0x40); /* read the latched count */
+ count |= inb(0x40) << 8;
+ /* we know probability of underflow is always MUCH less than 1% */
+ if (count > (LATCH - LATCH/100)) {
+ /* check for pending timer interrupt */
+ outb_p(0x0a, 0x20);
+ if (inb(0x20) & 1)
+ offset = TICK_SIZE;
+ }
+ count = ((LATCH-1) - count) * TICK_SIZE;
+ count = (count + LATCH/2) / LATCH;
+ return offset + count;
+}
+
+static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ *tv = xtime;
+ tv->tv_usec += do_gettimeoffset();
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ cli();
+ /* This is revolting. We need to set the xtime.tv_usec
+ * correctly. However, the value in this location is
+ * is value at the last tick.
+ * Discover what correction gettimeofday
+ * would have done, and then undo it!
+ */
+ tv->tv_usec -= do_gettimeoffset();
+
+ if (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_state = TIME_BAD;
+ time_maxerror = 0x70000000;
+ time_esterror = 0x70000000;
+ sti();
+}
+
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+
+#ifdef __powerpc__
+return (-1); /* Not implemented */
+#else
+
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(cmos_minutes);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ }
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else
+ retval = -1;
+
+ /* 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
+ */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ return retval;
+#endif
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * 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)
+{
+ do_timer(regs);
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. 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 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+#if 0
+ /* As we return to user mode fire off the other CPU schedulers.. this is
+ basically because we don't yet share IRQ's around. This message is
+ rigged to be safe on the 386 - basically its a hack, so don't look
+ closely for now.. */
+ smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
+#endif
+}
+
+/* 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)
+ */
+static 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 */
+}
+
+unsigned long get_cmos_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ if (isBeBox[0])
+ {
+#ifndef __powerpc__
+ /* 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 (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+#endif
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
+ min = CMOS_MCRTC_READ(MCRTC_MINUTES);
+ hour = CMOS_MCRTC_READ(MCRTC_HOURS);
+ day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
+ mon = CMOS_MCRTC_READ(MCRTC_MONTH);
+ year = CMOS_MCRTC_READ(MCRTC_YEAR);
+ } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
+ } else
+ { /* Motorola PowerStack etc. */
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+ } while (sec != CMOS_READ(RTC_SECONDS));
+ 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 0
+printk("CMOS TOD - M/D/Y H:M:S = %d/%d/%d %d:%02d:%02d\n", mon, day, year, hour, min, sec);
+#endif
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+void time_init(void)
+{
+ void (*irq_handler)(int, struct pt_regs *);
+ xtime.tv_sec = get_cmos_time();
+ xtime.tv_usec = 0;
+
+ /* 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!");
+}
+
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
new file mode 100644
index 000000000..e9f5e8e5b
--- /dev/null
+++ b/arch/ppc/kernel/traps.c
@@ -0,0 +1,134 @@
+/*
+ * linux/arch/ppc/kernel/traps.c
+ *
+ * Copyright (C) 1995 Gary Thomas
+ * Adapted for PowerPC by Gary Thomas
+ */
+
+/*
+ * This file handles the architecture-dependent parts of hardware exceptions
+ */
+
+#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/ldt.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <asm/ppc_machine.h>
+
+/*
+ * Trap & Exception support
+ */
+
+void
+trap_init(void)
+{
+}
+
+void
+_exception(int signr, struct pt_regs *regs)
+{
+/* dump_regs(regs);*/
+ force_sig(signr, current);
+ if (!user_mode(regs))
+ {
+ printk("Failure in kernel at PC: %x, MSR: %x\n", regs->nip, regs->msr);
+ while (1) ;
+ }
+}
+
+MachineCheckException(struct pt_regs *regs)
+{
+/* printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
+ _exception(SIGSEGV, regs);
+}
+
+ProgramCheckException(struct pt_regs *regs)
+{
+/* printk("Program check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
+ if (current->flags & PF_PTRACED)
+ {
+ _exception(SIGTRAP, regs);
+ } else
+ {
+ _exception(SIGILL, regs);
+ }
+}
+
+SingleStepException(struct pt_regs *regs)
+{
+/* printk("Single step at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
+ regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+ _exception(SIGTRAP, regs);
+}
+
+FloatingPointCheckException(struct pt_regs *regs)
+{
+/* printk("Floating point check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
+ _exception(SIGFPE, regs);
+}
+
+AlignmentException(struct pt_regs *regs)
+{
+/* printk("Alignment error at PC: %x, SR: %x\n", regs->nip, regs->msr);
+ dump_regs(regs);
+ printk("Alignment error at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
+ _exception(SIGBUS, regs);
+}
+
+bad_stack(struct pt_regs *regs)
+{
+/* printk("Kernel stack overflow at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);
+ dump_regs(regs);*/
+ while (1) ;
+}
+
+dump_regs(struct pt_regs *regs)
+{
+ int i;
+ printk("NIP: %08X, MSR: %08X, XER: %08X, LR: %08X, FRAME: %08X\n", regs->nip, regs->msr, regs->xer, regs->link, regs);
+#if 0
+ printk("HASH = %08X/%08X, MISS = %08X/%08X, CMP = %08X/%08X\n", regs->hash1, regs->hash2, regs->imiss, regs->dmiss, regs->icmp, regs->dcmp);
+#endif
+ printk("TASK = %x[%d] '%s'\n", current, current->pid, current->comm);
+ for (i = 0; i < 32; i++)
+ {
+ if ((i % 8) == 0)
+ {
+ printk("GPR%02d: ", i);
+ }
+ printk("%08X ", regs->gpr[i]);
+ if ((i % 8) == 7)
+ {
+ printk("\n");
+ }
+ }
+#if 0
+ if (regs->nip >= 0x1000)
+ dump_buf(regs->nip-32, 64);
+ dump_buf((regs->nip&0x0FFFFFFF)|KERNELBASE, 32);
+#endif
+}
+
+trace_syscall(struct pt_regs *regs)
+{
+ static int count;
+ printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n", current, current->pid, regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
+ if (++count == 20)
+ {
+ count = 0;
+ }
+}
+