X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc%2Fkernel%2Fhead_44x.S;h=f38298cbba86239dd461ec205e9d9bd8aca7754d;hb=da7238bfbc1c5267bb3c9a79e03b6c296839a07e;hp=e4c59673c6f1fe9cf2c90701ed94eae648731ec0;hpb=86090fcac5e27b630656fe3d963a6b80e26dac44;p=linux-2.6.git diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S index e4c59673c..f38298cbb 100644 --- a/arch/ppc/kernel/head_44x.S +++ b/arch/ppc/kernel/head_44x.S @@ -313,7 +313,7 @@ skpinv: addi r4,r4,1 /* Increment */ #define NORMAL_EXCEPTION_PROLOG \ mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ mtspr SPRN_SPRG1,r11; \ - mtspr SPRN_SPRG2,r1; \ + mtspr SPRN_SPRG4W,r1; \ mfcr r10; /* save CR in r10 for now */\ mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ andi. r11,r11,MSR_PR; \ @@ -332,7 +332,7 @@ skpinv: addi r4,r4,1 /* Increment */ stw r12,GPR11(r11); \ mflr r10; \ stw r10,_LINK(r11); \ - mfspr r10,SPRG2; \ + mfspr r10,SPRG4R; \ mfspr r12,SRR0; \ stw r10,GPR1(r11); \ mfspr r9,SRR1; \ @@ -348,30 +348,34 @@ skpinv: addi r4,r4,1 /* Increment */ * can potentially occur at any point during normal exception processing. * Thus we cannot use the same SPRG registers as the normal prolog above. * Instead we use a couple of words of memory at low physical addresses. - * This is OK since we don't support SMP on these processors. + * This is OK since we don't support SMP on these processors. For Book E + * processors, we also have a reserved register (SPRG2) that is only used + * in critical exceptions so we can free up a GPR to use as the base for + * indirect access to the critical exception save area. This is necessary + * since the MMU is always on and the save area is offset from KERNELBASE. */ -/* XXX but we don't have RAM mapped at 0 in space 0 -- paulus. */ #define CRITICAL_EXCEPTION_PROLOG \ - stw r10,crit_r10@l(0); /* save two registers to work with */\ - stw r11,crit_r11@l(0); \ + mtspr SPRG2,r8; /* SPRG2 only used in criticals */ \ + lis r8,crit_save@ha; \ + stw r10,crit_r10@l(r8); \ + stw r11,crit_r11@l(r8); \ mfspr r10,SPRG0; \ - stw r10,crit_sprg0@l(0); \ + stw r10,crit_sprg0@l(r8); \ mfspr r10,SPRG1; \ - stw r10,crit_sprg1@l(0); \ + stw r10,crit_sprg1@l(r8); \ mfspr r10,SPRG4R; \ - stw r10,crit_sprg4@l(0); \ + stw r10,crit_sprg4@l(r8); \ mfspr r10,SPRG5R; \ - stw r10,crit_sprg5@l(0); \ - mfspr r10,SPRG6R; \ - stw r10,crit_sprg6@l(0); \ + stw r10,crit_sprg5@l(r8); \ mfspr r10,SPRG7R; \ - stw r10,crit_sprg7@l(0); \ + stw r10,crit_sprg7@l(r8); \ mfspr r10,SPRN_PID; \ - stw r10,crit_pid@l(0); \ + stw r10,crit_pid@l(r8); \ mfspr r10,SRR0; \ - stw r10,crit_srr0@l(0); \ + stw r10,crit_srr0@l(r8); \ mfspr r10,SRR1; \ - stw r10,crit_srr1@l(0); \ + stw r10,crit_srr1@l(r8); \ + mfspr r8,SPRG2; /* SPRG2 only used in criticals */ \ mfcr r10; /* save CR in r10 for now */\ mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ andi. r11,r11,MSR_PR; \ @@ -383,7 +387,6 @@ skpinv: addi r4,r4,1 /* Increment */ lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ addi r11,r11,THREAD_SIZE; \ 1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - tophys(r11,r11); \ stw r10,_CCR(r11); /* save various registers */\ stw r12,GPR12(r11); \ stw r9,GPR9(r11); \ @@ -403,6 +406,71 @@ skpinv: addi r4,r4,1 /* Increment */ SAVE_4GPRS(3, r11); \ SAVE_2GPRS(7, r11) +/* + * Exception prolog for machine check exceptions. This is similar to + * the critical exception prolog, except that machine check exceptions + * have their own save area. For Book E processors, we also have a + * reserved register (SPRG6) that is only used in machine check exceptions + * so we can free up a GPR to use as the base for indirect access to the + * machine check exception save area. This is necessary since the MMU + * is always on and the save area is offset from KERNELBASE. + */ +#define MCHECK_EXCEPTION_PROLOG \ + mtspr SPRG6W,r8; /* SPRG6 used in machine checks */ \ + lis r8,mcheck_save@ha; \ + stw r10,mcheck_r10@l(r8); \ + stw r11,mcheck_r11@l(r8); \ + mfspr r10,SPRG0; \ + stw r10,mcheck_sprg0@l(r8); \ + mfspr r10,SPRG1; \ + stw r10,mcheck_sprg1@l(r8); \ + mfspr r10,SPRG4R; \ + stw r10,mcheck_sprg4@l(r8); \ + mfspr r10,SPRG5R; \ + stw r10,mcheck_sprg5@l(r8); \ + mfspr r10,SPRG7R; \ + stw r10,mcheck_sprg7@l(r8); \ + mfspr r10,SPRN_PID; \ + stw r10,mcheck_pid@l(r8); \ + mfspr r10,SRR0; \ + stw r10,mcheck_srr0@l(r8); \ + mfspr r10,SRR1; \ + stw r10,mcheck_srr1@l(r8); \ + mfspr r10,CSRR0; \ + stw r10,mcheck_csrr0@l(r8); \ + mfspr r10,CSRR1; \ + stw r10,mcheck_csrr1@l(r8); \ + mfspr r8,SPRG6R; /* SPRG6 used in machine checks */ \ + mfcr r10; /* save CR in r10 for now */\ + mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ + andi. r11,r11,MSR_PR; \ + lis r11,mcheck_stack_top@h; \ + ori r11,r11,mcheck_stack_top@l; \ + beq 1f; \ + /* COMING FROM USER MODE */ \ + mfspr r11,SPRG3; /* if from user, start at top of */\ + lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ + addi r11,r11,THREAD_SIZE; \ +1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ + stw r10,_CCR(r11); /* save various registers */\ + stw r12,GPR12(r11); \ + stw r9,GPR9(r11); \ + mflr r10; \ + stw r10,_LINK(r11); \ + mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ + stw r12,_DEAR(r11); /* since they may have had stuff */\ + mfspr r9,SPRN_ESR; /* in them at the point where the */\ + stw r9,_ESR(r11); /* exception was taken */\ + mfspr r12,MCSRR0; \ + stw r1,GPR1(r11); \ + mfspr r9,MCSRR1; \ + stw r1,0(r11); \ + tovirt(r1,r11); \ + rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ + stw r0,GPR0(r11); \ + SAVE_4GPRS(3, r11); \ + SAVE_2GPRS(7, r11) + /* * Exception vectors. */ @@ -429,6 +497,18 @@ label: NOCOPY, transfer_to_handler_full, \ ret_from_except_full) +#define MCHECK_EXCEPTION(n, label, hdlr) \ + START_EXCEPTION(label); \ + MCHECK_EXCEPTION_PROLOG; \ + lis r4,MCSR_MCS@h; \ + mtspr SPRN_MCSR,r4; \ + mfspr r5,SPRN_ESR; \ + stw r5,_ESR(r11); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, mcheck_transfer_to_handler, \ + ret_from_mcheck_exc) + #define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ li r10,trap; \ stw r10,TRAP(r11); \ @@ -463,7 +543,11 @@ interrupt_base: CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) /* Machine Check Interrupt */ +#ifdef CONFIG_440A + MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#else CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException) +#endif /* Data Storage Interrupt */ START_EXCEPTION(DataStorage) @@ -471,7 +555,6 @@ interrupt_base: mtspr SPRG1, r11 mtspr SPRG4W, r12 mtspr SPRG5W, r13 - mtspr SPRG6W, r14 mfcr r11 mtspr SPRG7W, r11 @@ -544,15 +627,14 @@ interrupt_base: rlwinm r11,r11,0,20,15 /* Clear U0-U3 */ /* find the TLB index that caused the fault. It has to be here. */ - tlbsx r14, 0, r10 + tlbsx r10, 0, r10 - tlbwe r11, r14, PPC44x_TLB_ATTRIB /* Write ATTRIB */ + tlbwe r11, r10, PPC44x_TLB_ATTRIB /* Write ATTRIB */ /* Done...restore registers and get out of here. */ mfspr r11, SPRG7R mtcr r11 - mfspr r14, SPRG6R mfspr r13, SPRG5R mfspr r12, SPRG4R @@ -567,7 +649,6 @@ interrupt_base: */ mfspr r11, SPRG7R mtcr r11 - mfspr r14, SPRG6R mfspr r13, SPRG5R mfspr r12, SPRG4R @@ -580,8 +661,7 @@ interrupt_base: NORMAL_EXCEPTION_PROLOG mr r4,r12 /* Pass SRR0 as arg2 */ li r5,0 /* Pass zero as arg3 */ - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE_LITE(0x0400, do_page_fault) + EXC_XFER_EE_LITE(0x0400, handle_page_fault) /* External Input Interrupt */ EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE) @@ -635,7 +715,6 @@ interrupt_base: mtspr SPRG1, r11 mtspr SPRG4W, r12 mtspr SPRG5W, r13 - mtspr SPRG6W, r14 mfcr r11 mtspr SPRG7W, r11 mfspr r10, SPRN_DEAR /* Get faulting address */ @@ -688,7 +767,6 @@ interrupt_base: */ mfspr r11, SPRG7R mtcr r11 - mfspr r14, SPRG6R mfspr r13, SPRG5R mfspr r12, SPRG4R mfspr r11, SPRG1 @@ -706,7 +784,6 @@ interrupt_base: mtspr SPRG1, r11 mtspr SPRG4W, r12 mtspr SPRG5W, r13 - mtspr SPRG6W, r14 mfcr r11 mtspr SPRG7W, r11 mfspr r10, SRR0 /* Get faulting address */ @@ -759,7 +836,6 @@ interrupt_base: */ mfspr r11, SPRG7R mtcr r11 - mfspr r14, SPRG6R mfspr r13, SPRG5R mfspr r12, SPRG4R mfspr r11, SPRG1 @@ -780,61 +856,50 @@ interrupt_base: * the MSR_DE bit set. */ /* Debug Interrupt */ - CRITICAL_EXCEPTION(0x2000, Debug, DebugException) -#if 0 START_EXCEPTION(Debug) - /* This first instruction was already executed by the exception - * handler and must be the first instruction of every exception - * handler. - */ - mtspr SPRN_SPRG0,r10 /* Save some working registers... */ - mtspr SPRN_SPRG1,r11 - mtspr SPRN_SPRG4W,r12 - mfcr r10 /* ..and the cr because we change it */ - - mfspr r11,SPRN_CSRR1 /* MSR at the time of fault */ - andi. r11,r11,MSR_PR - bne+ 2f /* trapped from problem state */ - - mfspr r11,SPRN_CSRR0 /* Faulting instruction address */ - lis r12, KERNELBASE@h - ori r12, r12, KERNELBASE@l - cmplw r11,r12 - blt+ 2f /* addr below exception vectors */ - - lis r12, Debug@h - ori r12, r12, Debug@l - cmplw r11,r12 - bgt+ 2f /* addr above TLB exception vectors */ - - lis r11,DBSR_IC@h /* Remove the trap status */ - mtspr SPRN_DBSR,r11 - - mfspr r11,SPRN_CSRR1 - rlwinm r11,r11,0,23,21 /* clear MSR_DE */ - mtspr SPRN_CSRR1, r11 /* restore MSR at rcfi without DE */ - - mtcrf 0xff,r10 /* restore registers */ - mfspr r12,SPRN_SPRG4R - mfspr r11,SPRN_SPRG1 - mfspr r10,SPRN_SPRG0 - - sync - rfci /* return to the exception handler */ - b . /* prevent prefetch past rfci */ - -2: - mtcrf 0xff,r10 /* restore registers */ - mfspr r12,SPRN_SPRG4R - mfspr r11,SPRN_SPRG1 - mfspr r10,SPRN_SPRG0 + CRITICAL_EXCEPTION_PROLOG - CRIT_EXCEPTION_PROLOG + /* + * If this is a single step or branch-taken exception in an + * exception entry sequence, it was probably meant to apply to + * the code where the exception occurred (since exception entry + * doesn't turn off DE automatically). We simulate the effect + * of turning off DE on entry to an exception handler by turning + * off DE in the CSRR1 value and clearing the debug status. + */ + mfspr r10,SPRN_DBSR /* check single-step/branch taken */ + andis. r10,r10,(DBSR_IC|DBSR_BT)@h + beq+ 1f + andi. r0,r9,MSR_PR /* check supervisor */ + beq 2f /* branch if we need to fix it up... */ + + /* continue normal handling for a critical exception... */ +1: mfspr r4,SPRN_DBSR addi r3,r1,STACK_FRAME_OVERHEAD - li r7,CRIT_EXC; - li r9,MSR_KERNEL - FINISH_EXCEPTION(DebugException) -#endif + EXC_XFER_TEMPLATE(DebugException, 0x2002, \ + (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ + NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) + + /* here it looks like we got an inappropriate debug exception. */ +2: rlwinm r9,r9,0,~MSR_DE /* clear DE in the CSRR1 value */ + mtspr SPRN_DBSR,r10 /* clear the IC/BT debug intr status */ + /* restore state and get out */ + lwz r10,_CCR(r11) + lwz r0,GPR0(r11) + lwz r1,GPR1(r11) + mtcrf 0x80,r10 + mtspr CSRR0,r12 + mtspr CSRR1,r9 + lwz r9,GPR9(r11) + + mtspr SPRG2,r8; /* SPRG2 only used in criticals */ + lis r8,crit_save@ha; + lwz r10,crit_r10@l(r8) + lwz r11,crit_r11@l(r8) + mfspr r8,SPRG2 + + rfci + b . /* * Local functions @@ -848,9 +913,7 @@ data_access: mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ stw r5,_ESR(r11) mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ - stw r4,_DEAR(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE_LITE(0x0300, do_page_fault) + EXC_XFER_EE_LITE(0x0300, handle_page_fault) /* @@ -860,7 +923,6 @@ data_access: * r11 - available to use * r12 - Pointer to the 64-bit PTE * r13 - available to use - * r14 - available to use * MMUCR - loaded with proper value when we get here * Upon exit, we reload everything and RFI. */ @@ -875,51 +937,50 @@ finish_tlb_load: /* Load the next available TLB index */ lis r13, tlb_44x_index@ha - lwz r14, tlb_44x_index@l(r13) + lwz r13, tlb_44x_index@l(r13) /* Load the TLB high watermark */ - lis r13, tlb_44x_hwater@ha - lwz r11, tlb_44x_hwater@l(r13) + lis r11, tlb_44x_hwater@ha + lwz r11, tlb_44x_hwater@l(r11) /* Increment, rollover, and store TLB index */ - addi r14, r14, 1 - cmpw 0, r14, r11 /* reserve entries */ + addi r13, r13, 1 + cmpw 0, r13, r11 /* reserve entries */ ble 7f - li r14, 0 + li r13, 0 7: /* Store the next available TLB index */ - lis r13, tlb_44x_index@ha - stw r14, tlb_44x_index@l(r13) + lis r11, tlb_44x_index@ha + stw r13, tlb_44x_index@l(r11) - lwz r13, 0(r12) /* Get MS word of PTE */ - lwz r11, 4(r12) /* Get LS word of PTE */ - rlwimi r13, r11, 0, 0 , 19 /* Insert RPN */ - tlbwe r13, r14, PPC44x_TLB_XLAT /* Write XLAT */ + lwz r11, 0(r12) /* Get MS word of PTE */ + lwz r12, 4(r12) /* Get LS word of PTE */ + rlwimi r11, r12, 0, 0 , 19 /* Insert RPN */ + tlbwe r11, r13, PPC44x_TLB_XLAT /* Write XLAT */ /* * Create PAGEID. This is the faulting address, * page size, and valid flag. */ - li r12, PPC44x_TLB_VALID | PPC44x_TLB_4K - rlwimi r10, r12, 0, 20, 31 /* Insert valid and page size */ - tlbwe r10, r14, PPC44x_TLB_PAGEID /* Write PAGEID */ - - li r13, PPC44x_TLB_SR@l /* Set SR */ - rlwimi r13, r11, 0, 30, 30 /* Set SW = _PAGE_RW */ - rlwimi r13, r11, 29, 29, 29 /* SX = _PAGE_HWEXEC */ - rlwimi r13, r11, 29, 28, 28 /* UR = _PAGE_USER */ - rlwimi r12, r11, 31, 26, 26 /* (_PAGE_USER>>1)->r12 */ - and r12, r12, r11 /* HWEXEC & USER */ - rlwimi r13, r12, 0, 26, 26 /* UX = HWEXEC & USER */ - - rlwimi r11, r13, 0, 26, 31 /* Insert static perms */ - rlwinm r11, r11, 0, 20, 15 /* Clear U0-U3 */ - tlbwe r11, r14, PPC44x_TLB_ATTRIB /* Write ATTRIB */ + li r11, PPC44x_TLB_VALID | PPC44x_TLB_4K + rlwimi r10, r11, 0, 20, 31 /* Insert valid and page size */ + tlbwe r10, r13, PPC44x_TLB_PAGEID /* Write PAGEID */ + + li r10, PPC44x_TLB_SR@l /* Set SR */ + rlwimi r10, r12, 0, 30, 30 /* Set SW = _PAGE_RW */ + rlwimi r10, r12, 29, 29, 29 /* SX = _PAGE_HWEXEC */ + rlwimi r10, r12, 29, 28, 28 /* UR = _PAGE_USER */ + rlwimi r11, r12, 31, 26, 26 /* (_PAGE_USER>>1)->r12 */ + and r11, r12, r11 /* HWEXEC & USER */ + rlwimi r10, r11, 0, 26, 26 /* UX = HWEXEC & USER */ + + rlwimi r12, r10, 0, 26, 31 /* Insert static perms */ + rlwinm r12, r12, 0, 20, 15 /* Clear U0-U3 */ + tlbwe r12, r13, PPC44x_TLB_ATTRIB /* Write ATTRIB */ /* Done...restore registers and get out of here. */ mfspr r11, SPRG7R mtcr r11 - mfspr r14, SPRG6R mfspr r13, SPRG5R mfspr r12, SPRG4R mfspr r11, SPRG1 @@ -985,32 +1046,30 @@ _GLOBAL(empty_zero_page) _GLOBAL(swapper_pg_dir) .space 8192 -/* Stack for handling critical exceptions from kernel mode */ .section .bss +/* Stack for handling critical exceptions from kernel mode */ critical_stack_bottom: .space 4096 critical_stack_top: .previous -/* - * This space gets a copy of optional info passed to us by the bootstrap - * which is used to pass parameters into the kernel like root=/dev/sda1, etc. - */ -_GLOBAL(cmd_line) - .space 512 - -/* - * Room for two PTE pointers, usually the kernel and current user pointers - * to their respective root page table. - */ -abatron_pteptrs: - .space 8 +/* Stack for handling machine check exceptions from kernel mode */ +mcheck_stack_bottom: + .space 4096 +mcheck_stack_top: + .previous /* * This area is used for temporarily saving registers during the - * critical exception prolog. + * critical and machine check exception prologs. It must always + * follow the page aligned allocations, so it starts on a page + * boundary, ensuring that all crit_save areas are in a single + * page. */ -crit_save: + +/* crit_save */ +_GLOBAL(crit_save) + .space 4 _GLOBAL(crit_r10) .space 4 _GLOBAL(crit_r11) @@ -1023,8 +1082,6 @@ _GLOBAL(crit_sprg4) .space 4 _GLOBAL(crit_sprg5) .space 4 -_GLOBAL(crit_sprg6) - .space 4 _GLOBAL(crit_sprg7) .space 4 _GLOBAL(crit_pid) @@ -1033,3 +1090,47 @@ _GLOBAL(crit_srr0) .space 4 _GLOBAL(crit_srr1) .space 4 + +/* mcheck_save */ +_GLOBAL(mcheck_save) + .space 4 +_GLOBAL(mcheck_r10) + .space 4 +_GLOBAL(mcheck_r11) + .space 4 +_GLOBAL(mcheck_sprg0) + .space 4 +_GLOBAL(mcheck_sprg1) + .space 4 +_GLOBAL(mcheck_sprg4) + .space 4 +_GLOBAL(mcheck_sprg5) + .space 4 +_GLOBAL(mcheck_sprg7) + .space 4 +_GLOBAL(mcheck_pid) + .space 4 +_GLOBAL(mcheck_srr0) + .space 4 +_GLOBAL(mcheck_srr1) + .space 4 +_GLOBAL(mcheck_csrr0) + .space 4 +_GLOBAL(mcheck_csrr1) + .space 4 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * which is used to pass parameters into the kernel like root=/dev/sda1, etc. + */ +_GLOBAL(cmd_line) + .space 512 + +/* + * Room for two PTE pointers, usually the kernel and current user pointers + * to their respective root page table. + */ +abatron_pteptrs: + .space 8 + +