diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /arch/ppc/kernel | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/ppc/kernel')
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)®s.gpr[0]-(int)®s); + put_line(out, "GPR1", (int)®s.gpr[1]-(int)®s); + put_line(out, "GPR2", (int)®s.gpr[2]-(int)®s); + put_line(out, "GPR3", (int)®s.gpr[3]-(int)®s); + put_line(out, "GPR4", (int)®s.gpr[4]-(int)®s); + put_line(out, "GPR5", (int)®s.gpr[5]-(int)®s); + put_line(out, "GPR6", (int)®s.gpr[6]-(int)®s); + put_line(out, "GPR7", (int)®s.gpr[7]-(int)®s); + put_line(out, "GPR8", (int)®s.gpr[8]-(int)®s); + put_line(out, "GPR9", (int)®s.gpr[9]-(int)®s); + put_line(out, "GPR10", (int)®s.gpr[10]-(int)®s); + put_line(out, "GPR11", (int)®s.gpr[11]-(int)®s); + put_line(out, "GPR12", (int)®s.gpr[12]-(int)®s); + put_line(out, "GPR13", (int)®s.gpr[13]-(int)®s); + put_line(out, "GPR14", (int)®s.gpr[14]-(int)®s); + put_line(out, "GPR15", (int)®s.gpr[15]-(int)®s); + put_line(out, "GPR16", (int)®s.gpr[16]-(int)®s); + put_line(out, "GPR17", (int)®s.gpr[17]-(int)®s); + put_line(out, "GPR18", (int)®s.gpr[18]-(int)®s); + put_line(out, "GPR19", (int)®s.gpr[19]-(int)®s); + put_line(out, "GPR20", (int)®s.gpr[20]-(int)®s); + put_line(out, "GPR21", (int)®s.gpr[21]-(int)®s); + put_line(out, "GPR22", (int)®s.gpr[22]-(int)®s); + put_line(out, "GPR23", (int)®s.gpr[23]-(int)®s); + put_line(out, "GPR24", (int)®s.gpr[24]-(int)®s); + put_line(out, "GPR25", (int)®s.gpr[25]-(int)®s); + put_line(out, "GPR26", (int)®s.gpr[26]-(int)®s); + put_line(out, "GPR27", (int)®s.gpr[27]-(int)®s); + put_line(out, "GPR28", (int)®s.gpr[28]-(int)®s); + put_line(out, "GPR29", (int)®s.gpr[29]-(int)®s); + put_line(out, "GPR30", (int)®s.gpr[30]-(int)®s); + put_line(out, "GPR31", (int)®s.gpr[31]-(int)®s); + put_line(out, "FPR0", (int)®s.fpr[0]-(int)®s); + put_line(out, "FPR1", (int)®s.fpr[1]-(int)®s); + put_line(out, "FPR2", (int)®s.fpr[2]-(int)®s); + put_line(out, "FPR3", (int)®s.fpr[3]-(int)®s); + put_line(out, "FPCSR", (int)®s.fpcsr-(int)®s); + /* Note: these symbols include "_" because they overlap with special register names */ + put_line(out, "_NIP", (int)®s.nip-(int)®s); + put_line(out, "_MSR", (int)®s.msr-(int)®s); + put_line(out, "_CTR", (int)®s.ctr-(int)®s); + put_line(out, "_LINK", (int)®s.link-(int)®s); + put_line(out, "_CCR", (int)®s.ccr-(int)®s); + put_line(out, "_XER", (int)®s.xer-(int)®s); + put_line(out, "_DAR", (int)®s.dar-(int)®s); + put_line(out, "_DSISR", (int)®s.dsisr-(int)®s); + put_line(out, "_HASH1", (int)®s.hash1-(int)®s); + put_line(out, "_HASH2", (int)®s.hash2-(int)®s); + put_line(out, "_IMISS", (int)®s.imiss-(int)®s); + put_line(out, "_DMISS", (int)®s.dmiss-(int)®s); + put_line(out, "_ICMP", (int)®s.icmp-(int)®s); + put_line(out, "_DCMP", (int)®s.dcmp-(int)®s); + put_line(out, "ORIG_GPR3", (int)®s.orig_gpr3-(int)®s); + put_line(out, "RESULT", (int)®s.result-(int)®s); + put_line(out, "TRAP", (int)®s.trap-(int)®s); + put_line(out, "MARKER", (int)®s.marker-(int)®s); + 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 = ¤t->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(®s->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; + } +} + |