*参照元 [#b0b06074] #backlinks *説明 [#e7c6ad9c] -パス: [[linux-2.6.33/arch/arm/kernel/entry-common.S]] -FIXME: これは何? --説明 **引数 [#f567764a] - -- **返り値 [#ncf12b1d] - -- **参考 [#c8b425c4] *実装 [#q2c6cca8] -下記のように大きく分かれます。 --レジスタをスタックに保存する部分 --システムコール番号を取得する部分 --システムコールのコードにジャンプする部分 **レジスタをスタックに保存する部分 [#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 までのオフセットだけスタックポインタを進める -stmdb: ユーザモードの sp, lr をスタックに積む --DB(decrement before)なので、スタックに積む前に sp が減少する。 しかし r8! になっていない(ライトバックしない)ので sp は変化しない。 --レジスタ指定に「^」を付けると特殊な stm 命令になり、 ユーザモードのレジスタが読み出せる。 {sp, lr}^ ~~ コレのことですよ --この stm 命令はユーザモードとシステムモード以外のモード (スーパバイザモードなど)でしか使えない。 -命令実行後のスタックイメージ (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: spsr(ユーザ側の 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) -古い ABI をサポートする場合。 呼び出すべきシステムコールは swi の引数で指定される。 --FIXME: 命令形式の制限から Thumb からシステムコールを呼ぶことはできない? --[[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 -ユーザコードで 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 -tst: ユーザモードが Thumb モードで実行されているか検査する。 --r8 は spsr のコピーが入っている。 --spsr は ユーザ側の CPSR の値がコピーされているレジスタ。 -movne: ARM モードなら r10 を 0 クリアする。 --ne は Not Equal つまり、Thumb モードではない、ということ。 -ldrne: ARM モードなら r10 に、 ユーザが実行した swi 命令コードをロードする。 --swi 命令発行時、lr に swi 命令の「次」の命令のアドレスが入る。 そのため swi 命令の位置は lr - 4 になる。 #else -ユーザコードで Thumb モードを使わない場合。 ldr r10, [lr, #-4] @ get SWI instruction A710( and ip, r10, #0x0f000000 @ check for SWI ) A710( teq ip, #0x0f000000 ) A710( bne .Larm710bug ) -ldr: r10 に、ユーザが実行した swi 命令コードをロードする。 --swi 命令発行時、lr に swi 命令の「次」の命令のアドレスが入る。 そのため swi 命令の位置は lr - 4 になる。 -and: 0x0f000000 でマスクする。 --swi 命令の構造 ビット位置 | 31 28 | 27 | 26 | 25 | 24 | 23 0 | -------------------------------------------------------- 意味 | cond | 1 | 1 | 1 | 1 | immed_24 | ~~~~~~~~~~~~~~~~~~~~~ ↑swi 命令であることを表す部分 --ARM710 のみで必要。 -teq: マスクした値が 0x0f000000 かどうか? --ARM710 のみで必要。 -bne: swi 命令でなければ、.Larm710bug にジャンプする。 --ne は Not Equal つまり、swi 命令ではない、ということ。 --名前からしてバグ対応のようだが…内容がよくわからない。 --ARM710 のみで必要。 --[[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 -rev: メモリからロードした swi 命令の並びを逆にする。 --常に 0 ビット側に swi 命令の即値が来るようにしている。 #endif #elif defined(CONFIG_AEABI) -新 ABI を使う場合。 呼び出すべきシステムコールは r7 で指定される。 --Thumb からもシステムコールを呼ぶことができる。 --[[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()]] **システムコールのコードにジャンプする部分 [#z990c2be] 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 -tbl は r8 の別名 -tsk は r9 の別名 --[[linux-2.6.33/tbl(global)]] --[[linux-2.6.33/tsk(global)]] - --[[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]