*参照元 [#b0b06074] #backlinks *説明 [#e7c6ad9c] -パス: [[linux-2.6.33/arch/arm/kernel/entry-common.S]] -FIXME: これは何? --説明 **引数 [#f567764a] - -- **返り値 [#ncf12b1d] - -- **参考 [#c8b425c4] *実装 [#q2c6cca8] -大きく分けると、以下 2つの部分があります。 --レジスタをスタックに保存する部分 --システムコール番号を取得する部分 **レジスタをスタックに保存する部分 [#nbb1c8b7] .align 5 -2^5 = 32バイト境界に配置する ENTRY(vector_swi) - --[[linux-2.6.33/ENTRY()]] sub sp, sp, #S_FRAME_SIZE stmia sp, {r0 - r12} @ Calling r0 - r12 -sub: スタックの領域を sizeof(struct pt_regs) 分だけ確保する。 --[[linux-2.6.33/S_FRAME_SIZE]] -stmia: ユーザモード、スーババイザモード共通のレジスタを、 スタックに push する。 --stm は若いアドレスに若い番号のアドレスをストアする。 --IA(increment after) なので、スタックに積んだあとに sp が増加する。 しかし sp! になっていない(ライトバックしない)ので sp は変化しない。 -命令実行後のスタックイメージ (0x00000000 側) +---------+ <-- push 前、push 後に sp が指すアドレス | r0 | | r1 | | ... | | r11 | | r12 | +---------+ <-- まだ書いていない領域 | xxxx | | xxxx | | xxxx | | xxxx | | xxxx | +---------+ | ....... | <-- 別のスタックフレーム (0xffffffff 側) -なお ARM() は ARM モードの時のみ命令を生成するマクロ。 --[[linux-2.6.33/ARM()]] ARM( add r8, sp, #S_PC ) ARM( stmdb r8, {sp, lr}^ ) @ Calling sp, lr -add: r15 までのオフセット(= S_PC)だけスタックポインタを進める --[[linux-2.6.33/S_PC]] -stmdb: r15 までのオフセットだけスタックポインタを進める --DB(decrement before)なので、スタックに積む前に sp が減少する。 しかし r8! になっていない(ライトバックしない)ので sp は変化しない。 -命令実行後のスタックイメージ (0x00000000 側) +---------+ <-- sp | r0 | | ... | | r12 | +---------+ <-- r8 - 8 = stmdb のストア先アドレス | sp(usr) | | lr(usr) | +---------+ <-- r8 | xxxxxxx | | xxxxxxx | +---------+ | xxxx | +---------+ | ....... | <-- 別のスタックフレーム (0xffffffff 側) THUMB( mov r8, sp ) THUMB( store_user_sp_lr r8, r10, S_SP ) @ calling sp, lr - --[[linux-2.6.33/store_user_sp_lr()]] - --[[linux-2.6.33/THUMB()]] mrs r8, spsr @ called from non-FIQ mode, so ok. str lr, [sp, #S_PC] @ Save calling PC str r8, [sp, #S_PSR] @ Save CPSR str r0, [sp, #S_OLD_R0] @ Save OLD_R0 zero_fp -mrs: cpsr レジスタを読みだす。 -str lr: lr をユーザモードにとっての pc として積む。 --swi 命令によるソフトウェア例外の場合、 スーパバイザモードの lr には swi 命令の次のアドレスが格納されている。 --[[linux-2.6.33/S_PC]] -str r8: cpsr を積む --[[linux-2.6.33/S_PSR]] -str r0: r0 を orig_r0 として積む。 --システムコールの入口の r0 != システムコールの出口での r0 のためだと思われる。 --r0 はシステムコールの返り値として使われるため。 --[[linux-2.6.33/S_OLD_R0]] -zero_fp: フレームポインタを使うコンフィグが有効なら fp を 0 クリアする。 --[[linux-2.6.33/zero_fp()]] -命令実行後のスタックイメージ (0x00000000 側) +---------+ <-- sp | r0 | | ... | | r12 | | sp(usr) | | lr(usr) | +---------+ <-- ここ以下が新たに書かれる | pc(usr) | | cpsr | | orig_r0 | +---------+ | ....... | <-- 別のスタックフレーム (0xffffffff 側) **システムコール番号を取得する部分 [#z2169fad] /* * Get the system call number. */ #if defined(CONFIG_OABI_COMPAT) - --[[linux-2.6.33/CONFIG_OABI_COMPAT]] /* * If we have CONFIG_OABI_COMPAT then we need to look at the swi * value to determine if it is an EABI or an old ABI call. */ #ifdef CONFIG_ARM_THUMB - --[[linux-2.6.33/CONFIG_ARM_THUMB]] tst r8, #PSR_T_BIT movne r10, #0 @ no thumb OABI emulation ldreq r10, [lr, #-4] @ get SWI instruction #else ldr r10, [lr, #-4] @ get SWI instruction A710( and ip, r10, #0x0f000000 @ check for SWI ) A710( teq ip, #0x0f000000 ) A710( bne .Larm710bug ) - --[[linux-2.6.33/A710()]] - --[[linux-2.6.33/.Larm710bug()]] #endif #ifdef CONFIG_CPU_ENDIAN_BE8 - --[[linux-2.6.33/CONFIG_CPU_ENDIAN_BE8]] rev r10, r10 @ little endian instruction #endif #elif defined(CONFIG_AEABI) - --[[linux-2.6.33/CONFIG_AEABI]] /* * Pure EABI user space always put syscall number into scno (r7). */ A710( ldr ip, [lr, #-4] @ get SWI instruction ) A710( and ip, ip, #0x0f000000 @ check for SWI ) A710( teq ip, #0x0f000000 ) A710( bne .Larm710bug ) #elif defined(CONFIG_ARM_THUMB) /* Legacy ABI only, possibly thumb mode. */ tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in ldreq scno, [lr, #-4] #else /* Legacy ABI only. */ ldr scno, [lr, #-4] @ get SWI instruction A710( and ip, scno, #0x0f000000 @ check for SWI ) A710( teq ip, #0x0f000000 ) A710( bne .Larm710bug ) #endif #ifdef CONFIG_ALIGNMENT_TRAP - --[[linux-2.6.33/CONFIG_ALIGNMENT_TRAP]] ldr ip, __cr_alignment ldr ip, [ip] mcr p15, 0, ip, c1, c0 @ update control register - --[[linux-2.6.33/__cr_alignment]] #endif enable_irq - --[[linux-2.6.33/enable_irq()]] get_thread_info tsk - --[[linux-2.6.33/get_thread_info()]] adr tbl, sys_call_table @ load syscall table pointer ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing - --[[linux-2.6.33/sys_call_table(global)]] - --[[linux-2.6.33/TI_FLAGS]] #if defined(CONFIG_OABI_COMPAT) /* * If the swi argument is zero, this is an EABI call and we do nothing. * * If this is an old ABI call, get the syscall number into scno and * get the old ABI syscall table address. */ bics r10, r10, #0xff000000 eorne scno, r10, #__NR_OABI_SYSCALL_BASE ldrne tbl, =sys_oabi_call_table - --[[linux-2.6.33/__NR_OABI_SYSCALL_BASE()]] - --[[linux-2.6.33/sys_oabi_call_table(global)]] #elif !defined(CONFIG_AEABI) bic scno, scno, #0xff000000 @ mask off SWI op-code eor scno, scno, #__NR_SYSCALL_BASE @ check OS number #endif stmdb sp!, {r4, r5} @ push fifth and sixth args tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? bne __sys_trace - --[[linux-2.6.33/_TIF_SYSCALL_TRACE]] - --[[linux-2.6.33/__sys_trace()]] cmp scno, #NR_syscalls @ check upper syscall limit adr lr, BSYM(ret_fast_syscall) @ return address ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine - --[[linux-2.6.33/BSYM()]] - --[[linux-2.6.33/ret_fast_syscall()]] add r1, sp, #S_OFF - --[[linux-2.6.33/S_OFF]] 2: mov why, #0 @ no longer a real syscall cmp scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE) eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back - --[[linux-2.6.33/__ARM_NR_BASE]] - --[[linux-2.6.33/__NR_SYSCALL_BASE]] bcs arm_syscall - --[[linux-2.6.33/arm_syscall()]] b sys_ni_syscall @ not private func - --[[linux-2.6.33/sys_ni_syscall()]] ENDPROC(vector_swi) - --[[linux-2.6.33/ENDPROC()]] *コメント [#rd0ea46c]