diff options
Diffstat (limited to 'arch/ppc/kernel/head.S')
-rw-r--r-- | arch/ppc/kernel/head.S | 1754 |
1 files changed, 1754 insertions, 0 deletions
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 + |