目次: Zephyr
前回は、新しいコンテキストスイッチ関数に対応しているAArch64の実装のうち、共通部分からアーキテクチャ依存部分に至るまでを調べました。引き続きアーキテクチャ依存部分を調べます。
コンテキストスイッチのアーキテクチャ依存部分(AArch64向けarch_switch())の実装はほぼ全てアセンブラで実装されています。
コンテキストスイッチの本体はz_arm64_context_switchです。x0がnew_thread, x1がold_threadだと思って動きます。コンテキストスイッチの仕事はレジスタの値を切り替え前のスレッド構造体(old_thread)に退避し、切り替え後のスレッド構造体(new_thread)からレジスタの値を復旧させることです。
// zephyr/arch/arm/core/aarch64/switch.S
GTEXT(z_arm64_svc)
SECTION_FUNC(TEXT, z_arm64_svc)
z_arm64_enter_exc x2, x3, x4 /* ★レジスタをスタックに退避(切り替え前のスレッド)★ */
switch_el x1, 3f, 2f, 1f
3:
mrs x0, esr_el3
b 0f
2:
mrs x0, esr_el2
b 0f
1:
mrs x0, esr_el1
0:
lsr x1, x0, #26
cmp x1, #0x15 /* 0x15 = SVC */
bne inv
/* Demux the SVC call */
and x1, x0, #0xff
cmp x1, #_SVC_CALL_CONTEXT_SWITCH
beq context_switch /* ★以下参照★ */
...
context_switch:
/*
* Retrieve x0 and x1 from the stack:
* - x0 = new_thread->switch_handle = switch_to thread
* - x1 = x1 = &old_thread->switch_handle = current thread
*/
ldp x0, x1, [sp, #(16 * 10)] /* ★x1 = 切り替え前、x0 = 切り替え後のスレッド★ */
/* Get old thread from x1 */
sub x1, x1, ___thread_t_switch_handle_OFFSET
/* Switch thread */
bl z_arm64_context_switch /* ★コンテキストスイッチ本体(スタックが切り替わる)★ */
exit:
z_arm64_exit_exc x0, x1, x2 /* ★レジスタをスタックから復旧(切り替え後のスレッド)★ */
...
/**
* @brief Routine to handle context switches
*
* This function is directly called either by _isr_wrapper() in case of
* preemption, or z_arm64_svc() in case of cooperative switching.
*/
GTEXT(z_arm64_context_switch)
SECTION_FUNC(TEXT, z_arm64_context_switch)
/* addr of callee-saved regs in thread in x2 */
ldr x2, =_thread_offset_to_callee_saved
add x2, x2, x1
/* Store rest of process context including x30 */
stp x19, x20, [x2], #16
stp x21, x22, [x2], #16
stp x23, x24, [x2], #16
stp x25, x26, [x2], #16
stp x27, x28, [x2], #16
stp x29, x30, [x2], #16
/* Save the current SP */
mov x1, sp
str x1, [x2]
/* addr of callee-saved regs in thread in x2 */
ldr x2, =_thread_offset_to_callee_saved
add x2, x2, x0
/* Restore x19-x29 plus x30 */
ldp x19, x20, [x2], #16
ldp x21, x22, [x2], #16
ldp x23, x24, [x2], #16
ldp x25, x26, [x2], #16
ldp x27, x28, [x2], #16
ldp x29, x30, [x2], #16
ldr x1, [x2]
mov sp, x1 /* ★ここで切り替え後のスレッドのスタックに変わる★ */
#ifdef CONFIG_TRACING
stp xzr, x30, [sp, #-16]!
bl sys_trace_thread_switched_in
ldp xzr, x30, [sp], #16
#endif
/* We restored x30 from the process stack. There are three possible
* cases:
*
* - We return to z_arm64_svc() when swapping in a thread that was
* swapped out by z_arm64_svc() before jumping into
* z_arm64_exit_exc()
* - We return to _isr_wrapper() when swapping in a thread that was
* swapped out by _isr_wrapper() before jumping into
* z_arm64_exit_exc()
* - We return (jump) into z_thread_entry_wrapper() for new threads
* (see thread.c)
*/
ret
// zephyr/include/arm/aarch64/thread.h
struct _callee_saved {
uint64_t x19;
uint64_t x20;
uint64_t x21;
uint64_t x22;
uint64_t x23;
uint64_t x24;
uint64_t x25;
uint64_t x26;
uint64_t x27;
uint64_t x28;
uint64_t x29; /* FP */
uint64_t x30; /* LR */
uint64_t sp;
};
コードを見て一発で理解するのは厳しいので、処理の概要を書いておきます。
コンテキストスイッチの際にスタックが切り替わります。z_arm64_exit_exc x0, x1, x2はシステムコールを呼んだスレッド(=切り替え前のスレッド)ではなく、コンテキストスイッチ後のスレッドのスタックからレジスタを復旧します。
これも文章だと何だかわからないので、紙芝居を書いておきます。
Zephyr AArch64のコンテキストスイッチ: 例外ハンドラ先頭
Zephyr AArch64のコンテキストスイッチ: 例外ハンドラ入り口、スタックへレジスタ退避
Zephyr AArch64のコンテキストスイッチ: コンテキストスイッチ前半、切り替え前スレッド構造体へレジスタ退避
Zephyr AArch64のコンテキストスイッチ: コンテキストスイッチ前半、切り替え前スレッド構造体へスタックポインタ退避
Zephyr AArch64のコンテキストスイッチ: コンテキストスイッチ後半、切り替え後スレッド構造体からレジスタ復旧
Zephyr AArch64のコンテキストスイッチ: コンテキストスイッチ後半、切り替え後スレッド構造体からスタックポインタ復旧(=スタック切り替え)
Zephyr AArch64のコンテキストスイッチ: 例外ハンドラ入り口、切り替え後のスタックからレジスタ復旧
図には書きませんでしたが、例外からリターンする命令(eret命令)が参照するレジスタ(SPSR, ELRレジスタ)もスタックに退避、復旧しています。従ってeretが戻る先は切り替え後のスレッドのコードです。
< | 2020 | > | ||||
<< | < | 10 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.2.15.
using GD bundled (2.1.0 compatible)(png support.)