head_e500.s
来自「优龙2410linux2.6.8内核源代码」· S 代码 · 共 1,332 行 · 第 1/3 页
S
1,332 行
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,CSRR0; \ stw r1,GPR1(r11); \ mfspr r9,CSRR1; \ 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 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. */#define START_EXCEPTION(label) \ .align 5; \label:#define FINISH_EXCEPTION(func) \ bl transfer_to_handler_full; \ .long func; \ .long ret_from_except_full#define EXCEPTION(n, label, hdlr, xfer) \ START_EXCEPTION(label); \ NORMAL_EXCEPTION_PROLOG; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ xfer(n, hdlr)#define CRITICAL_EXCEPTION(n, label, hdlr) \ START_EXCEPTION(label); \ CRITICAL_EXCEPTION_PROLOG; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ NOCOPY, transfer_to_handler_full, \ ret_from_except_full)#define MCHECK_EXCEPTION(n, label, hdlr) \ START_EXCEPTION(label); \ MCHECK_EXCEPTION_PROLOG; \ 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); \ lis r10,msr@h; \ ori r10,r10,msr@l; \ copyee(r10, r9); \ bl tfer; \ .long hdlr; \ .long ret#define COPY_EE(d, s) rlwimi d,s,0,16,16#define NOCOPY(d, s)#define EXC_XFER_STD(n, hdlr) \ EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ ret_from_except_full)#define EXC_XFER_LITE(n, hdlr) \ EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ ret_from_except)#define EXC_XFER_EE(n, hdlr) \ EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ ret_from_except_full)#define EXC_XFER_EE_LITE(n, hdlr) \ EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ ret_from_except)interrupt_base: /* Critical Input Interrupt */ CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException) /* Machine Check Interrupt */ MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException) /* Data Storage Interrupt */ START_EXCEPTION(DataStorage) mtspr SPRG0, r10 /* Save some working registers */ mtspr SPRG1, r11 mtspr SPRG4W, r12 mtspr SPRG5W, r13 mfcr r11 mtspr SPRG7W, r11 /* * Check if it was a store fault, if not then bail * because a user tried to access a kernel or * read-protected page. Otherwise, get the * offending address and handle it. */ mfspr r10, SPRN_ESR andis. r10, r10, ESR_ST@h beq 2f mfspr r10, SPRN_DEAR /* Get faulting address */ /* If we are faulting a kernel address, we have to use the * kernel page tables. */ lis r11, TASK_SIZE@h ori r11, r11, TASK_SIZE@l cmplw 0, r10, r11 bge 2f /* Get the PGD for the current thread */3: mfspr r11,SPRG3 lwz r11,PGDIR(r11)4: rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ lwz r11, 0(r11) /* Get L1 entry */ rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ beq 2f /* Bail if no table */ rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ lwz r11, 0(r12) /* Get Linux PTE */ /* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */ andi. r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE cmpwi 0, r13, _PAGE_RW|_PAGE_USER bne 2f /* Bail if not */ /* Update 'changed'. */ ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE stw r11, 0(r12) /* Update Linux page table */ /* MAS2 not updated as the entry does exist in the tlb, this fault taken to detect state transition (eg: COW -> DIRTY) */ lis r12, MAS3_RPN@h ori r12, r12, _PAGE_HWEXEC | MAS3_RPN@l and r11, r11, r12 rlwimi r11, r11, 31, 27, 27 /* SX <- _PAGE_HWEXEC */ ori r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */ /* update search PID in MAS6, AS = 0 */ mfspr r12, SPRN_PID0 slwi r12, r12, 16 mtspr SPRN_MAS6, r12 /* find the TLB index that caused the fault. It has to be here. */ tlbsx 0, r10 mtspr SPRN_MAS3,r11 tlbwe /* Done...restore registers and get out of here. */ mfspr r11, SPRG7R mtcr r11 mfspr r13, SPRG5R mfspr r12, SPRG4R mfspr r11, SPRG1 mfspr r10, SPRG0 rfi /* Force context change */2: /* * The bailout. Restore registers to pre-exception conditions * and call the heavyweights to help us out. */ mfspr r11, SPRG7R mtcr r11 mfspr r13, SPRG5R mfspr r12, SPRG4R mfspr r11, SPRG1 mfspr r10, SPRG0 b data_access /* Instruction Storage Interrupt */ START_EXCEPTION(InstructionStorage) NORMAL_EXCEPTION_PROLOG mfspr r5,SPRN_ESR /* Grab the ESR and save it */ stw r5,_ESR(r11) mr r4,r12 /* Pass SRR0 as arg2 */ li r5,0 /* Pass zero as arg3 */ EXC_XFER_EE_LITE(0x0400, handle_page_fault) /* External Input Interrupt */ EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE) /* Alignment Interrupt */ START_EXCEPTION(Alignment) NORMAL_EXCEPTION_PROLOG mfspr r4,SPRN_DEAR /* Grab the DEAR and save it */ stw r4,_DEAR(r11) addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE(0x0600, AlignmentException) /* Program Interrupt */ START_EXCEPTION(Program) NORMAL_EXCEPTION_PROLOG mfspr r4,SPRN_ESR /* Grab the ESR and save it */ stw r4,_ESR(r11) addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_STD(0x0700, ProgramCheckException) /* Floating Point Unavailable Interrupt */ EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE) /* System Call Interrupt */ START_EXCEPTION(SystemCall) NORMAL_EXCEPTION_PROLOG EXC_XFER_EE_LITE(0x0c00, DoSyscall) /* Auxillary Processor Unavailable Interrupt */ EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE) /* Decrementer Interrupt */ START_EXCEPTION(Decrementer) NORMAL_EXCEPTION_PROLOG lis r0,TSR_DIS@h /* Setup the DEC interrupt mask */ mtspr SPRN_TSR,r0 /* Clear the DEC interrupt */ addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_LITE(0x0900, timer_interrupt) /* Fixed Internal Timer Interrupt */ /* TODO: Add FIT support */ EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE) /* Watchdog Timer Interrupt */ /* TODO: Add watchdog support */ CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException) /* Data TLB Error Interrupt */ START_EXCEPTION(DataTLBError) mtspr SPRG0, r10 /* Save some working registers */ mtspr SPRG1, r11 mtspr SPRG4W, r12 mtspr SPRG5W, r13 mfcr r11 mtspr SPRG7W, r11 mfspr r10, SPRN_DEAR /* Get faulting address */ /* If we are faulting a kernel address, we have to use the * kernel page tables. */ lis r11, TASK_SIZE@h ori r11, r11, TASK_SIZE@l cmplw 5, r10, r11 blt 5, 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l mfspr r12,SPRN_MAS1 /* Set TID to 0 */ li r13,MAS1_TID@l andc r12,r12,r13 mtspr SPRN_MAS1,r12 b 4f /* Get the PGD for the current thread */3: mfspr r11,SPRG3 lwz r11,PGDIR(r11)4: rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ lwz r11, 0(r11) /* Get L1 entry */ rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ beq 2f /* Bail if no table */ rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ lwz r11, 0(r12) /* Get Linux PTE */ andi. r13, r11, _PAGE_PRESENT beq 2f ori r11, r11, _PAGE_ACCESSED stw r11, 0(r12) /* Jump to common tlb load */ b finish_tlb_load2: /* The bailout. Restore registers to pre-exception conditions * and call the heavyweights to help us out. */ mfspr r11, SPRG7R mtcr r11 mfspr r13, SPRG5R mfspr r12, SPRG4R mfspr r11, SPRG1 mfspr r10, SPRG0 b data_access /* Instruction TLB Error Interrupt */ /* * Nearly the same as above, except we get our * information from different registers and bailout * to a different point. */ START_EXCEPTION(InstructionTLBError) mtspr SPRG0, r10 /* Save some working registers */ mtspr SPRG1, r11 mtspr SPRG4W, r12 mtspr SPRG5W, r13 mfcr r11 mtspr SPRG7W, r11 mfspr r10, SRR0 /* Get faulting address */ /* If we are faulting a kernel address, we have to use the * kernel page tables. */ lis r11, TASK_SIZE@h ori r11, r11, TASK_SIZE@l cmplw 5, r10, r11 blt 5, 3f lis r11, swapper_pg_dir@h ori r11, r11, swapper_pg_dir@l mfspr r12,SPRN_MAS1 /* Set TID to 0 */ li r13,MAS1_TID@l andc r12,r12,r13 mtspr SPRN_MAS1,r12 b 4f /* Get the PGD for the current thread */3: mfspr r11,SPRG3 lwz r11,PGDIR(r11)4: rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ lwz r11, 0(r11) /* Get L1 entry */ rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ beq 2f /* Bail if no table */ rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ lwz r11, 0(r12) /* Get Linux PTE */ andi. r13, r11, _PAGE_PRESENT beq 2f ori r11, r11, _PAGE_ACCESSED stw r11, 0(r12) /* Jump to common TLB load point */ b finish_tlb_load2: /* The bailout. Restore registers to pre-exception conditions * and call the heavyweights to help us out. */ mfspr r11, SPRG7R mtcr r11 mfspr r13, SPRG5R mfspr r12, SPRG4R mfspr r11, SPRG1 mfspr r10, SPRG0 b InstructionStorage#ifdef CONFIG_SPE /* SPE Unavailable */ START_EXCEPTION(SPEUnavailable) NORMAL_EXCEPTION_PROLOG bne load_up_spe addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE_LITE(0x2010, KernelSPE)#else
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?