📄 head.s
字号:
slbie r22 sync3: /* All done -- return from exception. */ mfsprg r20,3 /* Load the PACA pointer */ ld r21,PACAEXCSP(r20) /* Get the exception frame pointer */ addi r21,r21,EXC_FRAME_SIZE ld r23,EX_DAR(r21) /* get saved CR */ /* note that this is almost identical to maskable_exception_exit */ mtcr r23 /* restore CR */ ld r22,EX_SRR0(r21) /* Get SRR0 from exc. frame */ ld r23,EX_SRR1(r21) /* Get SRR1 from exc. frame */ mtspr SRR0,r22 mtspr SRR1,r23 ld r22,EX_R22(r21) /* restore r22 and r23 */ ld r23,EX_R23(r21) mfspr r20,SPRG2 mfspr r21,SPRG1 rfid_TRACEBACK(do_stab_bolted)/* * r20 points to the PACA, r21 to the exception frame, * r23 contains the saved CR. * r20 - r23, SRR0 and SRR1 are saved in the exception frame. * We assume we aren't going to take any exceptions during this procedure. */_GLOBAL(do_slb_bolted) std r23,48(r21) /* save CR in exc. frame */ /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */ mfspr r21,DAR rldicl r20,r21,36,32 /* Permits a full 32b of ESID */ rldicr r20,r20,15,48 rldicl r21,r21,4,60 or r20,r20,r21 li r21,9 /* VSID_RANDOMIZER */ sldi r21,r21,32 oris r21,r21,58231 ori r21,r21,39831 mulld r20,r20,r21 clrldi r20,r20,28 /* r20 = vsid */ /* Search the SLB for a free entry */ li r22,11: slbmfee r23,r22 rldicl r23,r23,37,63 cmpwi r23,0 beq 3f /* Found an invalid entry */ addi r22,r22,1 cmpldi r22,64 blt 1b /* No free entry - just take the next entry, round-robin */ /* XXX we should get the number of SLB entries from the naca */SLB_NUM_ENTRIES = 64 mfspr r21,SPRG3 ld r22,PACASTABRR(r21) addi r23,r22,1 cmpdi r23,SLB_NUM_ENTRIES blt 2f li r23,12: std r23,PACASTABRR(r21) /* r20 = vsid, r22 = entry */3: /* Put together the vsid portion of the entry. */ li r21,0 rldimi r21,r20,12,0 ori r20,r21,1024 ori r20,r20,128 /* set class bit for kernel region */#ifndef CONFIG_PPC_ISERIES ori r20,r20,256 /* map kernel region with large ptes */#endif /* Put together the esid portion of the entry. */ mfspr r21,DAR /* Get the new esid */ rldicl r21,r21,36,28 /* Permits a full 36b of ESID */ li r23,0 rldimi r23,r21,28,0 /* Insert esid */ oris r21,r23,2048 /* valid bit */ rldimi r21,r22,0,52 /* Insert entry */ isync slbmte r20,r21 isync /* All done -- return from exception. */ mfsprg r20,3 /* Load the PACA pointer */ ld r21,PACAEXCSP(r20) /* Get the exception frame pointer */ addi r21,r21,EXC_FRAME_SIZE ld r23,EX_DAR(r21) /* get saved CR */ /* note that this is almost identical to maskable_exception_exit */ mtcr r23 /* restore CR */ ld r22,EX_SRR0(r21) /* Get SRR0 from exc. frame */ ld r23,EX_SRR1(r21) /* Get SRR1 from exc. frame */ mtspr SRR0,r22 mtspr SRR1,r23 ld r22,EX_R22(r21) /* restore r22 and r23 */ ld r23,EX_R23(r21) mfspr r20,SPRG2 mfspr r21,SPRG1 rfid_TRACEBACK(do_slb_bolted)_GLOBAL(do_stab_SI) mflr r21 /* Save LR in r21 */ /* * r3 contains the faulting address * r4 contains the required access permissions * * at return r3 = 0 for success */ bl .ste_allocate /* build STE if possible */ or. r3,r3,r3 /* Check return code */ beq fast_exception_return /* Return from exception on success */ mtlr r21 /* restore LR */ blr /* Return to DSI or ISI on failure *//* * This code finishes saving the registers to the exception frame. * Address translation is already on. */_GLOBAL(save_remaining_regs) /* * Save the rest of the registers into the pt_regs structure */ std r22,_NIP(r1) std r23,_MSR(r1) std r6,TRAP(r1) ld r6,GPR6(r1) SAVE_2GPRS(14, r1) SAVE_4GPRS(16, r1) SAVE_8GPRS(24, r1) /* * Clear the RESULT field */ li r22,0 std r22,RESULT(r1) /* * Test if from user state; result will be tested later */ andi. r23,r23,MSR_PR /* Set CR for later branch */ /* * Indicate that r1 contains the kernel stack and * get the Kernel TOC and CURRENT pointers from the Paca */ mfspr r23,SPRG3 /* Get PACA */ std r22,PACAKSAVE(r23) /* r1 is now kernel sp */ ld r2,PACATOC(r23) /* Get Kernel TOC pointer */ /* * If from user state, update THREAD.regs */ beq 2f /* Modify THREAD.regs if from user */ addi r24,r1,STACK_FRAME_OVERHEAD std r24,THREAD+PT_REGS(r13)2: SET_REG_TO_CONST(r22, MSR_KERNEL)#ifdef DO_SOFT_DISABLE stb r20,PACAPROCENABLED(r23) /* possibly soft enable */ ori r22,r22,MSR_EE /* always hard enable */#else rldimi r22,r20,15,48 /* Insert desired EE value */#endif mtmsrd r22 blrdo_profile: ld r22,8(r21) /* Get SRR1 */ andi. r22,r22,MSR_PR /* Test if in kernel */ bnelr /* return if not in kernel */ ld r22,0(r21) /* Get SRR0 */ ld r25,PACAPROFSTEXT(r20) /* _stext */ subf r22,r25,r22 /* offset into kernel */ lwz r25,PACAPROFSHIFT(r20) srd r22,r22,r25 lwz r25,PACAPROFLEN(r20) /* length of profile table (-1) */ cmp 0,r22,r25 /* off end? */ ble 1f mr r22,r25 /* force into last entry */1: sldi r22,r22,2 /* convert to offset into buffer */ ld r25,PACAPROFBUFFER(r20) /* profile buffer */ add r25,r25,r222: lwarx r22,0,r25 /* atomically increment */ addi r22,r22,1 stwcx. r22,0,r25 bne- 2b blr/* * On pSeries, secondary processors spin in the following code. * At entry, r3 = this processor's number (in Linux terms, not hardware). */_GLOBAL(pseries_secondary_smp_init) /* turn on 64-bit mode */ bl .enable_64b_mode isync /* Set up a Paca value for this processor. */ LOADADDR(r24, xPaca) /* Get base vaddr of Paca array */ mulli r25,r3,PACA_SIZE /* Calculate vaddr of right Paca */ add r25,r25,r24 /* for this processor. */ mtspr SPRG3,r25 /* Save vaddr of Paca in SPRG3 */ mr r24,r3 /* __secondary_start needs cpu# */1: HMT_LOW lbz r23,PACAPROCSTART(r25) /* Test if this processor should */ /* start. */ sync /* Create a temp kernel stack for use before relocation is on. */ mr r1,r25 addi r1,r1,PACAGUARD addi r1,r1,0x1000 subi r1,r1,STACK_FRAME_OVERHEAD cmpi 0,r23,0#ifdef CONFIG_SMP#ifdef SECONDARY_PROCESSORS bne .__secondary_start#endif#endif b 1b /* Loop until told to go */_GLOBAL(__start_initialization_iSeries) LOADADDR(r1,init_thread_union) addi r1,r1,THREAD_SIZE li r0,0 stdu r0,-STACK_FRAME_OVERHEAD(r1) LOADADDR(r2,__toc_start) addi r2,r2,0x4000 addi r2,r2,0x4000 LOADADDR(r9,naca) SET_REG_TO_CONST(r4, KERNELBASE) addi r4,r4,0x4000 std r4,0(r9) /* set the naca pointer */ /* Get the pointer to the segment table */ ld r6,PACA(r4) /* Get the base Paca pointer */ ld r4,PACASTABVIRT(r6) bl .iSeries_fixup_klimit b .start_here_common_GLOBAL(__start_initialization_pSeries) mr r31,r3 /* save parameters */ mr r30,r4 mr r29,r5 mr r28,r6 mr r27,r7 mr r26,r8 /* YABOOT: debug_print() routine */ mr r25,r9 /* YABOOT: debug_delay() routine */ mr r24,r10 /* YABOOT: debug_prom() routine */ bl .enable_64b_mode /* put a relocation offset into r3 */ bl .reloc_offset LOADADDR(r2,__toc_start) addi r2,r2,0x4000 addi r2,r2,0x4000 /* Relocate the TOC from a virt addr to a real addr */ sub r2,r2,r3 /* setup the naca pointer which is needed by prom_init */ LOADADDR(r9,naca) sub r9,r9,r3 /* addr of the variable naca */ SET_REG_TO_CONST(r4, KERNELBASE) sub r4,r4,r3 addi r4,r4,0x4000 std r4,0(r9) /* set the value of naca */ /* DRENG / PPPBBB Fix the following comment!!! -Peter */ /* The following copies the first 0x100 bytes of code from the */ /* load addr to physical addr 0x0. This code causes secondary */ /* processors to spin until a flag in the PACA is set. This */ /* is done at this time rather than with the entire kernel */ /* relocation which is done below because we need to cause the */ /* processors to spin on code that is not going to move while OF */ /* is still alive. Although the spin code is not actually run on */ /* a uniprocessor, we always do this copy. */ SET_REG_TO_CONST(r4, KERNELBASE)/* Src addr */ sub r4,r4,r3 /* current address of __start */ /* the source addr */ li r3,0 /* Dest addr */ li r5,0x100 /* # bytes of memory to copy */ li r6,0 /* Destination offset */ bl .copy_and_flush /* copy the first 0x100 bytes */ mr r3,r31 mr r4,r30 mr r5,r29 mr r6,r28 mr r7,r27 mr r8,r26 mr r9,r25 mr r10,r24 bl .prom_init li r24,0 /* cpu # *//* * At this point, r3 contains the physical address we are running at, * returned by prom_init() */_STATIC(__after_prom_start)/* * We need to run with __start at physical address 0. * This will leave some code in the first 256B of * real memory, which are reserved for software use. * The remainder of the first page is loaded with the fixed * interrupt vectors. The next two pages are filled with * unknown exception placeholders. * * Note: This process overwrites the OF exception vectors. * r26 == relocation offset * r27 == KERNELBASE */ bl .reloc_offset mr r26,r3 SET_REG_TO_CONST(r27,KERNELBASE) li r3,0 /* target addr */ sub r4,r27,r26 /* source addr */ /* current address of _start */ /* i.e. where we are running */ /* the source addr */ LOADADDR(r5,copy_to_here) /* # bytes of memory to copy */ sub r5,r5,r27 li r6,0x100 /* Start offset, the first 0x100 */ /* bytes were copied earlier. */ bl .copy_and_flush /* copy the first n bytes */ /* this includes the code being */ /* executed here. */ li r0,4f@l /* Jump to the copy of this code */ mtctr r0 /* that we just made */ bctr4: LOADADDR(r9,rtas) sub r9,r9,r26 ld r5,RTASBASE(r9) /* get the value of rtas->base */ ld r9,RTASSIZE(r9) /* get the value of rtas->size */ bl .copy_and_flush /* copy upto rtas->base */ add r6,r6,r9 /* then skip over rtas->size bytes */ LOADADDR(r5,klimit) sub r5,r5,r26 ld r5,0(r5) /* get the value of klimit */ sub r5,r5,r27 bl .copy_and_flush /* copy the rest */ b .start_here_pSeries/* * Copy routine used to copy the kernel to start at physical address 0 * and flush and invalidate the caches as needed. * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. * * Note: this routine *only* clobbers r0, r6 and lr */_STATIC(copy_and_flush) addi r5,r5,-8 addi r6,r6,-84: li r0,16 /* Use the least common */ /* denominator cache line */ /* size. This results in */ /* extra cache line flushes */ /* but operation is correct. */ /* Can't get cache line size */ /* from NACA as it is being */ /* moved too. */ mtctr r0 /* put # words/line in ctr */3: addi r6,r6,8 /* copy a cache line */ ldx r0,r6,r4 stdx r0,r6,r3 bdnz 3b dcbst r6,r3 /* write it to memory */ sync icbi r6,r3 /* flush the icache line */ cmpld 0,r6,r5 blt 4b sync addi r5,r5,8 addi r6,r6,8 blr.align 8copy_to_here:/* * Disable FP for the task which had the FPU previously, * and save its floating-point registers in its thread_struct. * Enables the FPU for use in the kernel on return. * On SMP we know the fpu is free, since we give it up every * switch. -- Cort */_STATIC(load_up_fpu) mfmsr r5 /* grab the current MSR */ ori r5,r5,MSR_FP mtmsrd r5 /* enable use of fpu now */ isync/* * For SMP, we don't do lazy FPU switching because it just gets too * horrendously complex, especially when a task switches from one CPU * to another. Instead we call giveup_fpu in switch_to. * */#ifndef CONFIG_SMP LOADBASE(r3,last_task_used_math) ld r4,last_task_used_math@l(r3) cmpi 0,r4,0 beq 1f addi r4,r4,THREAD /* want THREAD of last_task_used_math */ SAVE_32FPRS(0, r4) mffs fr0 stfd fr0,THREAD_FPSCR-4(r4) ld r5,PT_REGS(r4) ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) li r20,MSR_FP|MSR_FE0|MSR_FE1 andc r4,r4,r20 /* disable FP for previous task */ std r4,_MSR-STACK_FRAME_OVERHEAD(r5)1:#endif /* CONFIG_SMP */ /* enable use of FP after return */ ori r23,r23,MSR_FP|MSR_FE0|MSR_FE1 addi r5,r13,THREAD /* Get THREAD */ lfd fr0,THREAD_FPSCR-4(r5)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -