コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2020年10月1日 >>> 2020年10月1日
link もっと後

2020年10月1日

Zephyr OSで遊ぼう その15 - SMP対応の準備、コンテキストスイッチの実装、中編2、既存実装調査

目次: Zephyr

前回は、新しいコンテキストスイッチ関数に対応しているAArch64の実装のうち、共通部分からアーキテクチャ依存部分に至るまでを調べました。引き続きアーキテクチャ依存部分を調べます。

アーキ依存部分の処理(AArch64)

コンテキストスイッチのアーキテクチャ依存部分(AArch64向けarch_switch())の実装はほぼ全てアセンブラで実装されています。

コンテキストスイッチの本体はz_arm64_context_switchです。x0がnew_thread, x1がold_threadだと思って動きます。コンテキストスイッチの仕事はレジスタの値を切り替え前のスレッド構造体(old_thread)に退避し、切り替え後のスレッド構造体(new_thread)からレジスタの値を復旧させることです。

AArch64の新しい形式のコンテキストスイッチarch_switch() 実装

// 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;
};

コードを見て一発で理解するのは厳しいので、処理の概要を書いておきます。


Zephyr AArch64のコンテキストスイッチ概要

コンテキストスイッチの際にスタックが切り替わります。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が戻る先は切り替え後のスレッドのコードです。

編集者:すずき(2023/09/24 12:09)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2020年10月1日 >>> 2020年10月1日
link もっと後

管理用メニュー

link 記事を新規作成

<2020>
<<<10>>>
----123
45678910
11121314151617
18192021222324
25262728293031

最近のコメント5件

  • link 24年4月22日
    hdkさん (04/24 08:36)
    「うちのHHFZ4310は15年突破しまし...」
  • link 24年4月22日
    すずきさん (04/24 00:37)
    「ちゃんと数えてないですけど蛍光管が10年...」
  • link 24年4月22日
    hdkさん (04/23 20:52)
    「おお... うちのHHFZ4310より後...」
  • link 20年6月19日
    すずきさん (04/06 22:54)
    「ディレクトリを予め作成しておけば良いです...」
  • link 20年6月19日
    斎藤さん (04/06 16:25)
    「「Preferencesというメニューか...」

最近の記事3件

  • link 24年2月7日
    すずき (04/24 02:52)
    「[複数の音声ファイルのラウドネスを統一したい] PCやデジタル音楽プレーヤーで音楽を聞いていると、曲によって音量の大小が激しく...」
  • link 24年4月22日
    すずき (04/23 20:13)
    「[仕事部屋の照明が壊れた] いきなり仕事部屋のシーリングライトが消えました。蛍光管の寿命にしては去年(2022年10月19日の...」
  • link 24年4月17日
    すずき (04/18 22:44)
    「[VSCodeとMarkdownとPlantUMLのローカルサーバー] 目次: LinuxVSCodeのPlantUML Ex...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 04/24 08:36