📄 entry.s
字号:
ld.q SP, FRAME_R(52), r52 ld.q SP, FRAME_R(53), r53 ld.q SP, FRAME_R(54), r54 ld.q SP, FRAME_R(55), r55 ld.q SP, FRAME_R(56), r56 ld.q SP, FRAME_R(57), r57 ld.q SP, FRAME_R(58), r58 getcon SR, r59 movi SR_BLOCK_EXC, r60 or r59, r60, r59 putcon r59, SR /* SR.BL = 1, keep nesting out */ ld.q SP, FRAME_S(FSSR), r61 ld.q SP, FRAME_S(FSPC), r62 movi SR_ASID_MASK, r60 and r59, r60, r59 andc r61, r60, r61 /* Clear out older ASID */ or r59, r61, r61 /* Retain current ASID */ putcon r61, SSR putcon r62, SPC /* Ignore FSYSCALL_ID */ ld.q SP, FRAME_R(59), r59 ld.q SP, FRAME_R(60), r60 ld.q SP, FRAME_R(61), r61 ld.q SP, FRAME_R(62), r62 /* Last touch */ ld.q SP, FRAME_R(15), SP rte nop/* * Third level handlers for VBR-based exceptions. Adapting args to * and/or deflecting to fourth level handlers. * * Fourth level handlers interface. * Most are C-coded handlers directly pointed by the trap_jtable. * (Third = Fourth level) * Inputs: * (r2) fault/interrupt code, entry number (e.g. NMI = 14, * IRL0-3 (0000) = 16, RTLBMISS = 2, SYSCALL = 11, etc ...) * (r3) struct pt_regs *, original register's frame pointer * (r4) Event (0 = interrupt, 1 = TLB miss fault, 2 = Not TLB miss fault) * (r5) TRA control register (for syscall/debug benefit only) * (LINK) return address * (SP) = r3 * * Kernel TLB fault handlers will get a slightly different interface. * (r2) struct pt_regs *, original register's frame pointer * (r3) writeaccess, whether it's a store fault as opposed to load fault * (r4) execaccess, whether it's a ITLB fault as opposed to DTLB fault * (r5) Effective Address of fault * (LINK) return address * (SP) = r2 * * fpu_error_or_IRQ? is a helper to deflect to the right cause. * */tlb_miss_load: or SP, ZERO, r2 or ZERO, ZERO, r3 /* Read */ or ZERO, ZERO, r4 /* Data */ getcon TEA, r5 pta call_do_page_fault, tr0 beq ZERO, ZERO, tr0tlb_miss_store: or SP, ZERO, r2 movi 1, r3 /* Write */ or ZERO, ZERO, r4 /* Data */ getcon TEA, r5 pta call_do_page_fault, tr0 beq ZERO, ZERO, tr0itlb_miss_or_IRQ: pta its_IRQ, tr0 beqi/u r4, EVENT_INTERRUPT, tr0 or SP, ZERO, r2 or ZERO, ZERO, r3 /* Read */ movi 1, r4 /* Text */ getcon TEA, r5 /* Fall through */call_do_page_fault: movi do_page_fault, r6 ptabs r6, tr0 blink tr0, ZEROfpu_error_or_IRQA: pta its_IRQ, tr0 beqi/l r4, EVENT_INTERRUPT, tr0#ifdef CONFIG_SH_FPU movi do_fpu_state_restore, r6#else movi do_exception_error, r6#endif ptabs r6, tr0 blink tr0, ZEROfpu_error_or_IRQB: pta its_IRQ, tr0 beqi/l r4, EVENT_INTERRUPT, tr0#ifdef CONFIG_SH_FPU movi do_fpu_state_restore, r6#else movi do_exception_error, r6#endif ptabs r6, tr0 blink tr0, ZEROits_IRQ: movi do_IRQ, r6 ptabs r6, tr0 blink tr0, ZERO/* * system_call/unknown_trap third level handler: * * Inputs: * (r2) fault/interrupt code, entry number (TRAP = 11) * (r3) struct pt_regs *, original register's frame pointer * (r4) Not used. Event (0=interrupt, 1=TLB miss fault, 2=Not TLB miss fault) * (r5) TRA Control Reg (0x00xyzzzz: x=1 SYSCALL, y = #args, z=nr) * (SP) = r3 * (LINK) return address: ret_from_exception * (*r3) Syscall parms: SC#, arg0, arg1, ..., arg5 in order (Saved r2/r7) * * Outputs: * (*r3) Syscall reply (Saved r2) * (LINK) In case of syscall only it can be scrapped. * Common second level post handler will be ret_from_syscall. * Common (non-trace) exit point to that is syscall_ret (saving * result to r2). Common bad exit point is syscall_bad (returning * ENOSYS then saved to r2). * */unknown_trap: /* Unknown Trap or User Trace */ movi do_unknown_trapa, r6 ptabs r6, tr0 ld.q r3, FRAME_R(9), r2 /* r2 = #arg << 16 | syscall # */ andi r2, 0x1ff, r2 /* r2 = syscall # */ blink tr0, LINK pta syscall_ret, tr0 blink tr0, ZERO /* New syscall implementation*/system_call: pta unknown_trap, tr0 or r5, ZERO, r4 /* TRA (=r5) -> r4 */ shlri r4, 20, r4 bnei r4, 1, tr0 /* unknown_trap if not 0x1yzzzz */ /* It's a system call */ st.q r3, FRAME_S(FSYSCALL_ID), r5 /* ID (0x1yzzzz) -> stack */ andi r5, 0x1ff, r5 /* syscall # -> r5 */ STI() pta syscall_allowed, tr0 movi NR_syscalls - 1, r4 /* Last valid */ bgeu/l r4, r5, tr0syscall_bad: /* Return ENOSYS ! */ movi -(ENOSYS), r2 /* Fall-through */ .global syscall_retsyscall_ret: st.q SP, FRAME_R(9), r2 /* Expecting SP back to BASIC frame */#ifdef CONFIG_POOR_MANS_STRACE /* nothing useful in registers at this point */ movi evt_debug2, r5 ori r5, 1, r5 ptabs r5, tr0 ld.q SP, FRAME_R(9), r2 or SP, ZERO, r3 blink tr0, LINK#endif ld.q SP, FRAME_S(FSPC), r2 addi r2, 4, r2 /* Move PC, being pre-execution event */ st.q SP, FRAME_S(FSPC), r2 pta ret_from_syscall, tr0 blink tr0, ZERO/* A different return path for ret_from_fork, because we now need * to call schedule_tail with the later kernels. Because prev is * loaded into r2 by switch_to() means we can just call it straight away */.global ret_from_forkret_from_fork: movi schedule_tail,r5 ori r5, 1, r5 ptabs r5, tr0 blink tr0, LINK#ifdef CONFIG_POOR_MANS_STRACE /* nothing useful in registers at this point */ movi evt_debug2, r5 ori r5, 1, r5 ptabs r5, tr0 ld.q SP, FRAME_R(9), r2 or SP, ZERO, r3 blink tr0, LINK#endif ld.q SP, FRAME_S(FSPC), r2 addi r2, 4, r2 /* Move PC, being pre-execution event */ st.q SP, FRAME_S(FSPC), r2 pta ret_from_syscall, tr0 blink tr0, ZEROsyscall_allowed: /* Use LINK to deflect the exit point, default is syscall_ret */ pta syscall_ret, tr0 gettr tr0, LINK pta syscall_notrace, tr0 getcon KCR0, r2 ld.l r2, TI_FLAGS, r4 movi (1 << TIF_SYSCALL_TRACE), r6 and r6, r4, r6 beq/l r6, ZERO, tr0 /* Trace it by calling syscall_trace before and after */ movi syscall_trace, r4 ptabs r4, tr0 blink tr0, LINK /* Reload syscall number as r5 is trashed by syscall_trace */ ld.q SP, FRAME_S(FSYSCALL_ID), r5 andi r5, 0x1ff, r5 pta syscall_ret_trace, tr0 gettr tr0, LINKsyscall_notrace: /* Now point to the appropriate 4th level syscall handler */ movi sys_call_table, r4 shlli r5, 2, r5 ldx.l r4, r5, r5 ptabs r5, tr0 /* Prepare original args */ ld.q SP, FRAME_R(2), r2 ld.q SP, FRAME_R(3), r3 ld.q SP, FRAME_R(4), r4 ld.q SP, FRAME_R(5), r5 ld.q SP, FRAME_R(6), r6 ld.q SP, FRAME_R(7), r7 /* And now the trick for those syscalls requiring regs * ! */ or SP, ZERO, r8 /* Call it */ blink tr0, ZERO /* LINK is already properly set */syscall_ret_trace: /* We get back here only if under trace */ st.q SP, FRAME_R(9), r2 /* Save return value */ movi syscall_trace, LINK ptabs LINK, tr0 blink tr0, LINK /* This needs to be done after any syscall tracing */ ld.q SP, FRAME_S(FSPC), r2 addi r2, 4, r2 /* Move PC, being pre-execution event */ st.q SP, FRAME_S(FSPC), r2 pta ret_from_syscall, tr0 blink tr0, ZERO /* Resume normal return sequence *//* * --- Switch to running under a particular ASID and return the previous ASID value * --- The caller is assumed to have done a cli before calling this. * * Input r2 : new ASID * Output r2 : old ASID */ .global switch_and_save_asidswitch_and_save_asid: getcon sr, r0 movi 255, r4 shlli r4, 16, r4 /* r4 = mask to select ASID */ and r0, r4, r3 /* r3 = shifted old ASID */ andi r2, 255, r2 /* mask down new ASID */ shlli r2, 16, r2 /* align new ASID against SR.ASID */ andc r0, r4, r0 /* efface old ASID from SR */ or r0, r2, r0 /* insert the new ASID */ putcon r0, ssr movi 1f, r0 putcon r0, spc rte nop1: ptabs LINK, tr0 shlri r3, 16, r2 /* r2 = old ASID */ blink tr0, r63 .global route_to_panic_handlerroute_to_panic_handler: /* Switch to real mode, goto panic_handler, don't return. Useful for last-chance debugging, e.g. if no output wants to go to the console. */ movi panic_handler - CONFIG_CACHED_MEMORY_OFFSET, r1 ptabs r1, tr0 pta 1f, tr1 gettr tr1, r0 putcon r0, spc getcon sr, r0 movi 1, r1 shlli r1, 31, r1 andc r0, r1, r0 putcon r0, ssr rte nop1: /* Now in real mode */ blink tr0, r63 nop .global peek_real_address_qpeek_real_address_q: /* Two args: r2 : real mode address to peek r2(out) : result quadword This is provided as a cheapskate way of manipulating device registers for debugging (to avoid the need to onchip_remap the debug module, and to avoid the need to onchip_remap the watchpoint controller in a way that identity maps sufficient bits to avoid the SH5-101 cut2 silicon defect). This code is not performance critical */ add.l r2, r63, r2 /* sign extend address */ getcon sr, r0 /* r0 = saved original SR */ movi 1, r1 shlli r1, 28, r1 or r0, r1, r1 /* r0 with block bit set */ putcon r1, sr /* now in critical section */ movi 1, r36 shlli r36, 31, r36 andc r1, r36, r1 /* turn sr.mmu off in real mode section */ putcon r1, ssr movi .peek0 - CONFIG_CACHED_MEMORY_OFFSET, r36 /* real mode target address */ movi 1f, r37 /* virtual mode return addr */ putcon r36, spc synco rte nop.peek0: /* come here in real mode, don't touch caches!! still in critical section (sr.bl==1) */ putcon r0, ssr putcon r37, spc /* Here's the actual peek. If the address is bad, all bets are now off * what will happen (handlers invoked in real-mode = bad news) */ ld.q r2, 0, r2 synco rte /* Back to virtual mode */ nop1: ptabs LINK, tr0 blink tr0, r63 .global poke_real_address_qpoke_real_address_q: /* Two args: r2 : real mode address to poke r3 : quadword value to write. This is provided as a cheapskate way of manipulating device registers for debugging (to avoid the need to onchip_remap the debug module, and to avoid the need to onchip_remap the watchpoint controller in a way that identity maps sufficient bits to avoid the SH5-101 cut2 silicon defect). This code is not performance critical */ add.l r2, r63, r2 /* sign extend address */ getcon sr, r0 /* r0 = saved original SR */ movi 1, r1 shlli r1, 28, r1 or r0, r1, r1 /* r0 with block bit set */ putcon r1, sr /* now in critical section */ movi 1, r36 shlli r36, 31, r36 andc r1, r36, r1 /* turn sr.mmu off in real mode section */ putcon r1, ssr movi .poke0-CONFIG_CACHED_MEMORY_OFFSET, r36 /* real mode target address */ movi 1f, r37 /* virtual mode return addr */ putcon r36, spc synco rte nop.poke0: /* come here in real mode, don't touch caches!! still in critical section (sr.bl==1) */ putcon r0, ssr putcon r37, spc /* Here's the actual poke. If the address is bad, all bets are now off * what will happen (handlers invoked in real-mode = bad news) */ st.q r2, 0, r3 synco rte /* Back to virtual mode */ nop1: ptabs LINK, tr0 blink tr0, r63/* * --- User Access Handling Section *//* * User Access support. It all moved to non inlined Assembler * functions in here. * * __kernel_size_t __copy_user(void *__to, const void *__from, * __kernel_size_t __n) * * Inputs: * (r2) target address * (r3) source address * (r4) size in bytes * * Ouputs: * (*r2) target data * (r2) non-copied bytes * * If a fault occurs on the user pointer, bail out early and return the * number of bytes not copied in r2. * Strategy : for large blocks, call a real memcpy function which can * move >1 byte at a time using unaligned ld/st instructions, and can * manipulate the cache using prefetch + alloco to improve the speed * further. If a fault occurs in that function, just revert to the * byte-by-byte approach used for small blocks; this is rare so the * performance hit for that case does not matter. * * For small blocks it's not worth the overhead of setting up and calling * the memcpy routine; do the copy a byte at a time. * */ .global __copy_user__copy_user: pta __copy_user_byte_by_byte, tr1 movi 16, r0 ! this value is a best guess, should tune it by benchmarking bge/u r0, r4, tr1 pta copy_user_memcpy, tr0 addi SP, -32, SP /* Save arguments in case we have to fix-up unhandled page fault */ st.q SP, 0, r2 st.q SP, 8, r3 st.q SP, 16, r4 st.q SP, 24, r35 ! r35 is callee-save /* Save LINK in a register to reduce RTS time later (otherwise ld SP,*,LINK;ptabs LINK;trn;blink trn,r63 becomes a critical path) */ ori LINK, 0, r35 blink tr0, LINK /* Copy completed normally if we get back here */ ptabs r35, tr0 ld.q SP, 24, r35 /* don't restore r2-r4, pointless */ /* set result=r2 to zero as the copy must have succeeded. */ or r63, r63, r2 addi SP, 32, SP blink tr0, r63 ! RTS .global __copy_user_fixup__copy_user_fixup: /* Restore stack frame */ ori r35, 0, LINK ld.q SP, 24, r35 ld.q SP, 16, r4 ld.q SP, 8, r3 ld.q SP, 0, r2 addi SP, 32, SP /* Fall through to original code, in the 'same' state we entered with *//* The slow byte-by-byte method is used if the fast copy traps due to a bad user address. In that rare case, the speed drop can be tolerated. */__copy_user_byte_by_byte: pta ___copy_user_exit, tr1 pta ___copy_user1, tr0 beq/u r4, r63, tr1 /* early exit for zero length copy */ sub r2, r3, r0 addi r0, -1, r0___copy_user1: ld.b r3, 0, r5 /* Fault address 1 */ /* Could rewrite this to use just 1 add, but the second comes 'free' due to load latency */ addi r3, 1, r3 addi r4, -1, r4 /* No real fixup required */___copy_user2: stx.b r3, r0, r5 /* Fault address 2 */ bne r4, ZERO, tr0___copy_user_exit: or r4, ZERO, r2 ptabs LINK, tr0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -