コグノスケ


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

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

2020年10月16日

Zephyr OSで遊ぼう その25 - SMP対応CPUコア数4、IPIの実装

目次: Zephyr

前回はマルチコアのブート処理を実装しました。今回はIPI (Inter-Processor Interrupt、プロセッサ間割り込み) を実装します。長きに渡ったSMP対応もようやく終盤です。

IPIとは

IPIとはInter-Processor Interrupt、プロセッサ間割り込みのことで、SMPの核となる機能です。プロセッサ間で何かイベントを伝えたい(今回の場合はスレッドスケジューラを動かしてほしい)ときにIPIを発生させます。

RISC-V Privilegeの場合、IPIを発生させるにはCLINTを使います。CLINTのmsipレジスタの最下位ビットは、それぞれのHARTのmipレジスタのMSIPビットに繋がっています。平たく言えばmsipレジスタに1を書き込むと他のHARTにソフトウェア割り込みが発生する仕組みです。

CLINTはタイマードライバの実装のときに出てきました(2020年10月14日の日記参照)。IPIの実装は、他アーキテクチャだとzephyr/arch/*/coreの下に実装していることが多いですが、RISC-Vの場合はタイマードライバzephyr/drivers/timer/riscv_machine_timer.cに実装すると早いです。このやり方で合っているのかはちょっとわかりません。割り込みコントローラとして新たに実装した方が筋が良さそうではあります。

IPI発生側の実装

IPIの実装を発生させる側と受け取る側に分けて説明します。

IPI発生側の実装 (arch_sched_ipi)

// zephyr/drivers/timer/riscv_machine_timer.c

#define RISCV_MSIP_OTHER(id) (RISCV_MSIP_BASE + (uintptr_t)(id) * 4)
#define RISCV_MSIP     RISCV_MSIP_OTHER(z_riscv_hart_id())

...

#ifdef CONFIG_SMP
void arch_sched_ipi(void)
{
	uint32_t id = z_riscv_hart_id();

	for (int i = 0; i < CONFIG_MP_NUM_CPUS; i++) {
		volatile uint32_t *r = (uint32_t *)RISCV_MSIP_OTHER(i);

		if (i == id)
			continue;    //★自分自身には割り込みを発生させない★

		*r = 1;
	}
}

...

発生させる側の実装はarch_sched_ipi() 関数を定義して、自分以外のHARTに割り込みを発生させます。シンプルで良いですね。

IPIを発生させる処理も確認します。何箇所かありますが、短めのものを例として挙げます。

IPI発生側の実装 (スケジューラ)

// zephyr/kernel/sched.c

static void ready_thread(struct k_thread *thread)
{
	if (z_is_thread_ready(thread)) {
		sys_trace_thread_ready(thread);
		_priq_run_add(&_kernel.ready_q.runq, thread);
		z_mark_thread_as_queued(thread);
		update_cache(0);
#if defined(CONFIG_SMP) &&  defined(CONFIG_SCHED_IPI_SUPPORTED)
		arch_sched_ipi();    //★ここで呼ばれている★
#endif
	}
}

コンフィグCONFIG_SMPは既に有効にしていますが、それ以外にもCONFIG_SCHED_IPI_SUPPORTEDを有効にする必要があるようです。

IPIのサポートを追加する

// zephyr/drivers/timer/Kconfig

config RISCV_MACHINE_TIMER
	bool "RISCV Machine Timer"
	depends on SOC_FAMILY_RISCV_PRIVILEGE
	select TICKLESS_CAPABLE
	select SCHED_IPI_SUPPORTED    #★この行を足す★
	help
	  This module implements a kernel device driver for the generic RISCV machine
	  timer driver. It provides the standard "system clock driver" interfaces.

今回IPIの機構を実装したのはタイマードライバですので、タイマーのKconfigに追加しています。

IPI受信側の実装

IPIを受け取る側の実装です。マスターコアとスレーブコアで呼ばれる関数が違う点は少しややこしいですが、基本的にやることは一緒です。前回(2020年10月10日の日記参照)、空関数で実装したsmp_timer_init() を真面目に実装するときが来ました。

IPI受信側の実装(割り込みハンドラ)
 
#ifdef CONFIG_SMP
void z_riscv_sched_ipi(void);

static void soft_isr(const void *arg)
{
	volatile uint32_t *r = (uint32_t *)RISCV_MSIP;

	ARG_UNUSED(arg);

	*r = 0;                 //★ソフトウェア割り込みをクリア★
	z_riscv_sched_ipi();    //★IPIテスト用の関数(後日に説明予定)今はリンクエラーになるはずなので、コメントアウトしてOK★
}
#endif

//★マスターコア用のタイマー初期化関数★
int z_clock_driver_init(const struct device *device)
{
	ARG_UNUSED(device);

	IRQ_CONNECT(RISCV_MACHINE_TIMER_IRQ, 0, timer_isr, NULL, 0);
	last_count = mtime();
	set_mtimecmp(last_count + CYC_PER_TICK);
	irq_enable(RISCV_MACHINE_TIMER_IRQ);

#ifdef CONFIG_SMP
	IRQ_CONNECT(RISCV_MACHINE_SOFT_IRQ, 0, soft_isr, NULL, 0);    //★ソフトウェア割り込みの割り込みハンドラを設定する★
	irq_enable(RISCV_MACHINE_SOFT_IRQ);    //★ソフトウェア割り込み有効★
#endif

	return 0;
}

...

//★スレーブコア用のタイマー初期化関数★
//★マスターコアが割り込みハンドラの設定をするので、割り込みを有効にするだけに留める★
void smp_timer_init(void)
{
	last_count = mtime();
	set_mtimecmp(last_count + CYC_PER_TICK);
	irq_enable(RISCV_MACHINE_TIMER_IRQ);
	irq_enable(RISCV_MACHINE_SOFT_IRQ);
}
#endif /* CONFIG_SMP */

割り込みを有効にして、ソフトウェア割り込みハンドラでCLINTのmsipレジスタをクリアします。msipのクリアを忘れると割り込みハンドラが終わった直後、またすぐソフトウェア割り込みが入って、ハンドラが呼ばれて、割り込みが入って、ハンドラが呼ばれて、、、を繰り返してしまい処理が先に進まなくなって、ハングします。

動作確認

前回作成した環境を流用して動作確認します。

IPI受信側の実装(割り込みハンドラ)
$ ninja run 

[0/1] To exit from QEMU enter: 'CTRL+a, x'[QEMU] CPU: riscv32
*** Booting Zephyr OS build zephyr-v2.4.0-546-g720718653f92  ***
1: thread_a: Hello World from QEMU RV32 virt board!
2: thread_b: Hello World from QEMU RV32 virt board!
0: thread_a: Hello World from QEMU RV32 virt board!
2: thread_b: Hello World from QEMU RV32 virt board!
1: thread_a: Hello World from QEMU RV32 virt board!
3: thread_b: Hello World from QEMU RV32 virt board!
1: thread_a: Hello World from QEMU RV32 virt board!

...

やった!動きました。スレッドがHART 0だけでなく、別のHARTでも実行されている様子がわかります。

リグレッションテストについては、また次回。

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

コメント一覧

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



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

管理用メニュー

link 記事を新規作成

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

最近のコメント20件

  • link 21年3月13日
    すずきさん (03/05 15:13)
    「あー、このプログラムがまずいんですね。ご...」
  • link 21年3月13日
    emkさん (03/05 12:44)
    「キャストでvolatileを外してアクセ...」
  • link 24年1月24日
    すずきさん (02/19 18:37)
    「簡単にできる方法はPowerShellの...」
  • link 24年1月24日
    KKKさん (02/19 02:30)
    「追伸です。\nネットで調べたらマイクロソ...」
  • link 24年1月24日
    KKKさん (02/19 02:25)
    「私もエラーで困ってます\n手動での回復パ...」
  • link 24年1月24日
    すずきさん (02/13 11:48)
    「ありがとうございます。\n私のPCはもう...」
  • link 24年1月24日
    えはらさん (02/12 15:00)
    「Powershellのスクリプトは以下の...」
  • link 24年2月2日
    すずきさん (02/02 18:17)
    「サーバー側の設定はとても簡単でした。ちょ...」
  • link 24年2月2日
    hdkさん (02/02 08:54)
    「さくらのレンタルサーバの設定でLet's...」
  • link 24年1月24日
    すずきさん (01/28 11:35)
    「ご指摘ありがとうございます。確かに間違っ...」
  • link 24年1月24日
    通りすがりさん (01/27 14:05)
    「Powershellで解決しなかったのは...」
  • link 23年11月29日
    すずきさん (12/04 00:38)
    「あ、そうか。1nsですね。ありがとうござ...」
  • link 23年11月29日
    hdkさん (12/03 18:49)
    「>(本来1usなのに1msになって...」
  • link 23年11月29日
    すずきさん (12/03 00:35)
    「大山先生、お久しぶりです。コメントありが...」
  • link 23年11月29日
    大山恵弘さん (12/02 18:53)
    「すずきさんのX(旧Twitter)へのポ...」
  • link 20年7月12日
    すずきさん (10/19 11:17)
    「ご指摘ありがとうございます。9月の編集は...」
  • link 20年7月12日
    通り縋りさん (10/18 19:08)
    「上の記事2023年9月編集という事ですが...」
  • link 23年9月22日
    すずきさん (09/23 21:14)
    「そうなんですよ。賢いなーと思って自分でも...」
  • link 23年9月22日
    hdkさん (09/23 14:56)
    「+1だから、繰り上がる時は必ず下のほうに...」
  • link 23年9月2日
    すずきさん (09/06 18:21)
    「dアカウント自体はMNPと関係なく存在す...」

最近の記事3件

  • link 24年3月25日
    すずき (03/26 03:20)
    「[Might and Magic Book One TASのその後] 目次: Might and Magicファミコン版以前(...」
  • link 21年10月4日
    すずき (03/26 03:14)
    「[Might and Magicファミコン版 - まとめリンク] 目次: Might and Magicファミコン版TASに挑...」
  • link 24年3月19日
    すずき (03/20 02:52)
    「[モジュラージャックの規格] 古くは電話線で、今だとEthernetで良く見かけるモジュラージャックというコネクタとレセプタク...」
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

最終更新: 03/26 03:20