📄 entry.s
字号:
/* $Id: entry.S,v 1.71 2000/03/22 13:29:33 gniibe Exp $ * * linux/arch/sh/entry.S * * Copyright (C) 1999, 2000 Niibe Yutaka * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * */#include <linux/sys.h>#include <linux/linkage.h>#include <linux/config.h>/* * Define this to turn on compatibility with the previous * system call ABI. This feature is not properly maintained. */#undef COMPAT_OLD_SYSCALL_ABI! NOTE:! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address! to be jumped is too far, but it causes illegal slot exception./* * entry.S contains the system-call and fault low-level handling routines. * This also contains the timer-interrupt handler, as well as all interrupts * and faults that can result in a task-switch. * * NOTE: This code handles signal-recognition, which happens every time * after a timer-interrupt and after each system call. * * NOTE: This code uses a convention that instructions in the delay slot * of a transfer-control instruction are indented by an extra space, thus: * * jmp @$k0 ! control-transfer instruction * ldc $k1, $ssr ! delay slot * * Stack layout in 'ret_from_syscall': * ptrace needs to have all regs on the stack. * if the order here is changed, it needs to be * updated in ptrace.c and ptrace.h * * $r0 * ... * $r15 = stack pointer * $spc * $pr * $ssr * $gbr * $mach * $macl * syscall # * *//* * These are offsets into the task-struct. */flags = 4sigpending = 8need_resched = 20tsk_ptrace = 24PT_TRACESYS = 0x00000002PF_USEDFPU = 0x00100000ENOSYS = 38EINVAL = 22#if defined(__sh3__)TRA = 0xffffffd0EXPEVT = 0xffffffd4#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)INTEVT = 0xa4000000 ! INTEVTE2(0xa4000000)#elseINTEVT = 0xffffffd8#endifMMU_TEA = 0xfffffffc ! TLB Exception Address Register#elif defined(__SH4__)TRA = 0xff000020EXPEVT = 0xff000024INTEVT = 0xff000028MMU_TEA = 0xff00000c ! TLB Exception Address Register#endif/* Offsets to the stack */R0 = 0 /* Return value. New ABI also arg4 */R1 = 4 /* New ABI: arg5 */R2 = 8 /* New ABI: arg6 */R3 = 12 /* New ABI: syscall_nr */R4 = 16 /* New ABI: arg0 */R5 = 20 /* New ABI: arg1 */R6 = 24 /* New ABI: arg2 */R7 = 28 /* New ABI: arg3 */SP = (15*4)SR = (16*4+8)SYSCALL_NR = (16*4+6*4)#define k0 r0#define k1 r1#define k2 r2#define k3 r3#define k4 r4#define current r7 /* r7_bank1 */#define g_imask r6 /* r6_bank1 */#define k_current r7_bank /* r7_bank1 */#define k_g_imask r6_bank /* r6_bank1 */#define k_ex_code r2_bank /* r2_bank1 *//* * Kernel mode register usage: * k0 scratch * k1 scratch * k2 scratch (Exception code) * k3 scratch (Return address) * k4 scratch * k5 reserved * k6 Global Interrupt Mask (0--15 << 4) * k7 CURRENT (pointer to current task) */!! TLB Miss / Initial Page write exception handling! _and_! TLB hits, but the access violate the protection.! It can be valid access, such as stack grow and/or C-O-W.!!! Find the pmd/pte entry and loadtlb! If it's not found, cause address error (SEGV)!! Although this could be written in assembly language (and it'd be faster),! this first version depends *much* on C implementation.!#define STI() \ mov.l __INV_IMASK, $r11; \ stc $sr, $r10; \ and $r11, $r10; \ stc $k_g_imask, $r11; \ or $r11, $r10; \ ldc $r10, $sr .align 2tlb_miss_load: bra call_dpf mov #0, $r5 .align 2tlb_miss_store: bra call_dpf mov #1, $r5 .align 2initial_page_write: bra call_dpf mov #1, $r5 .align 2tlb_protection_violation_load: bra call_dpf mov #0, $r5 .align 2tlb_protection_violation_store: bra call_dpf mov #1, $r5call_dpf: mov.l 1f, $r0 mov $r5, $r8 mov.l @$r0, $r6 mov $r6, $r9 mov.l 2f, $r0 sts $pr, $r10 jsr @$r0 mov $r15, $r4 ! tst #0xff, $r0 bf/s 0f lds $r10, $pr rts nop0: STI() mov.l 3f, $r0 mov $r9, $r6 mov $r8, $r5 jmp @$r0 mov $r15, $r4 .align 21: .long MMU_TEA2: .long SYMBOL_NAME(__do_page_fault)3: .long SYMBOL_NAME(do_page_fault)#if defined(CONFIG_DEBUG_KERNEL_WITH_GDB_STUB) || defined(CONFIG_SH_STANDARD_BIOS) .align 2 /* Unwind the stack and jmp to the debug entry */debug_kernel: mov.l @$r15+, $r0 mov.l @$r15+, $r1 mov.l @$r15+, $r2 mov.l @$r15+, $r3 mov.l @$r15+, $r4 mov.l @$r15+, $r5 mov.l @$r15+, $r6 mov.l @$r15+, $r7 stc $sr, $r8 mov.l 1f, $r9 ! BL =1, RB=1, IMASK=0x0F or $r9, $r8 ldc $r8, $sr ! here, change the register bank mov.l @$r15+, $r8 mov.l @$r15+, $r9 mov.l @$r15+, $r10 mov.l @$r15+, $r11 mov.l @$r15+, $r12 mov.l @$r15+, $r13 mov.l @$r15+, $r14 mov.l @$r15+, $k0 ldc.l @$r15+, $spc lds.l @$r15+, $pr mov.l @$r15+, $k1 ldc.l @$r15+, $gbr lds.l @$r15+, $mach lds.l @$r15+, $macl mov $k0, $r15 ! mov.l 2f, $k0 jmp @$k0 ldc $k1, $ssr .align 21: .long 0x300000f02: .long CONFIG_GDB_STUB_VBR + 0x100#endif .align 2debug_trap: #if defined(CONFIG_DEBUG_KERNEL_WITH_GDB_STUB) || defined(CONFIG_SH_STANDARD_BIOS) mov #SR, $r0 mov.l @($r0,$r15), $r0 ! get status register shll $r0 shll $r0 ! kernel space? bt/s debug_kernel#endif mov.l @$r15, $r0 mov.l 1f, $r8 jmp @$r8 nop .align 21: .long SYMBOL_NAME(break_point_trap_software) .align 2error: ! STI() mov.l 1f, $r0 jmp @$r0 nop .align 21: .long SYMBOL_NAME(do_exception_error)!!!ENTRY(ret_from_fork) bra SYMBOL_NAME(ret_from_syscall) add #4, $r15 ! pop down bogus r0 (see switch_to MACRO)/* * Old syscall interface: * * Syscall #: R0 * Arguments #0 to #3: R4--R7 * more arguments: On the stack * TRA: (number of arguments on the stack) x 4 * * New syscall interface: * * Syscall #: R3 * Arguments #0 to #3: R4--R7 * Arguments #4 to #6: R0, R1, R2 * TRA: (number of arguments + 0x10) x 4 * * This code also handles delegating other traps to the BIOS/gdb stub * according to: * * Trap number * (TRA>>2) Purpose * -------- ------- * 0x0-0xf old syscall ABI * 0x10-0x1f new syscall ABI * 0x20-0xff delegated through debug_trap to BIOS/gdb stub. * * Note: When we're first called, the TRA value must be shifted * right 2 bits in order to get the value that was used as the "trapa" * argument. */system_call: mov.l __TRA, $r9 mov.l @$r9, $r8 ! ! Is the trap argument >= 0x20? (TRA will be >= 0x80) mov #0x20, $r9 extu.b $r9, $r9 shll2 $r9 cmp/hs $r9, $r8 bt debug_trap ! mov #SYSCALL_NR, $r14 add $r15, $r14 !#ifdef COMPAT_OLD_SYSCALL_ABI mov #0x40, $r9 cmp/hs $r9, $r8 bf/s old_abi_system_call nop#endif ! New Syscall ABI add #-0x40, $r8 shlr2 $r8 shll8 $r8 shll8 $r8 ! $r8 = num_args<<16 mov $r3, $r10 or $r8, $r10 ! Encode syscall # and # of arguments mov.l $r10, @$r14 ! set syscall_nr STI() ! stc $k_current, $r11 mov.l @(tsk_ptrace,$r11), $r10 ! Is current PTRACE_SYSCALL'd? mov #PT_TRACESYS, $r11 tst $r11, $r10 bt 5f ! Yes it is traced. mov.l __syscall_trace, $r11 ! Call syscall_trace() which notifies jsr @$r11 ! superior (will chomp $R[0-7]) nop ! Reload $R0-$R4 from kernel stack, where the ! parent may have modified them using ! ptrace(POKEUSR). (Note that $R0-$R2 are ! used by the system call handler directly ! from the kernel stack anyway, so don't need ! to be reloaded here.) This allows the parent ! to rewrite system calls and args on the fly. mov.l @(R4,$r15), $r4 ! arg0 mov.l @(R5,$r15), $r5 mov.l @(R6,$r15), $r6 mov.l @(R7,$r15), $r7 ! arg3 mov.l @(R3,$r15), $r3 ! syscall_nr ! Arrange for syscall_trace() to be called ! again as the system call returns. mov.l __syscall_ret_trace, $r10 bra 6f lds $r10, $pr ! No it isn't traced. ! Arrange for normal system call return.5: mov.l __syscall_ret, $r10 lds $r10, $pr ! Call the system call handler through the table. ! (both normal and ptrace'd) ! First check for bad syscall number6: mov $r3, $r9 mov.l __n_sys, $r10 cmp/hs $r10, $r9 bf 2f ! Bad syscall number rts ! go to syscall_ret or syscall_ret_trace mov #-ENOSYS, $r0 ! Good syscall number2: shll2 $r9 ! x4 mov.l __sct, $r11 add $r11, $r9 mov.l @$r9, $r11 jmp @$r11 ! jump to specific syscall handler nop ! In case of tracesyscall_ret_trace: mov.l $r0, @(R0,$r15) ! save the return value mov.l __syscall_trace, $r1 mova SYMBOL_NAME(ret_from_syscall), $r0 jmp @$r1 ! Call syscall_trace() which notifies superior lds $r0, $pr ! Then return to ret_from_syscall()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -