1 of 19

並列処理の第一歩

by だいみょーじん

2 of 19

目次

  1. 自己紹介
  2. 並行処理と並列処理
  3. x64におけるマルチプロセッサの構成
  4. BSPとAP
  5. HeliOSにおけるAP起動の全体的な流れ
  6. BSPがプロセッサを列挙
  7. BSPが自分のLocal APIC IDを確認
  8. BSPがAPを起動
  9. BSPのINIT-SIPI-SIPI送信における待ち時間の測定
  10. APの起動
  11. APが16ビットモードから32ビットモードへ移行
  12. APが32ビットモードから64ビットモードへ移行
  13. ELFへの移行
  14. プロセッサ間通信
  15. APからBSPへのハローワールド
  16. 今後の課題
  17. 参考文献

2

3 of 19

自己紹介

  • だいみょーじん
  • 自動車業界のエンジニア
  • HeliOSというOSを開発中
  • 好きな言語:Rust,Haskell

3

4 of 19

並行処理と並列処理

  • 「30日でできるOS自作入門」や「ゼロからのOS自作入門」のマルチタスクは,並行処理だが並列処理でない.
  • 今回は並列処理実現に必要な以下の機能をHeliOSに実装したので,それを紹介します.
    • 複数のプロセッサの起動方法
    • プロセッサ間通信

4

5 of 19

x64におけるマルチプロセッサの構成

  • 周辺機器からの割り込み信号はシステム全体の割り込みコントローラであるI/O APICに集約される.
  • 割り込み信号はその後各プロセッサの個別の割り込みコントローラであるLocal APICに分配される.
  • Local APICがプロセッサの窓口になっている.
  • Local APICにはLocal APIC IDが付与され,プロセッサ自体もLocal APIC IDで識別する.

5

6 of 19

BSPとAP

  • x64のマルチプロセッサにおける2種類のプロセッサ
    • BSP (Bootstrap Processor):電源ボタンを押して最初に起動するプロセッサ
      • 必ず1つ
      • /EFI/BOOT/BOOTX64.EFIを実行
    • AP (Application Processor):それ以外のプロセッサ
      • 0個以上
      • BSPから起動指示を出さなければ,停止したまま

6

7 of 19

HeliOSにおけるAP起動の全体的な流れ

7

8 of 19

BSPがプロセッサを列挙

  • GPD Micro PCの場合,Local APIC ID 0,2,4,6が列挙された.

8

9 of 19

BSPが自分のLocal APIC IDを確認

  • RDMSR命令でIA32_APIC_BASEを取得
  • オフセット0x20のLocal APIC ID Registerを取得
  • ビット24:31のAPIC IDを取得

GPD Micro PCのBSPのLocal APIC IDは0だったので,

  • BSP:0
  • AP:2,4,6

9

10 of 19

BSPがAPを起動

  • Local APIC Registerのオフセット0x300にあるICR(Interrupt Command Register)から,他のプロセッサに信号を送れる.
  • BSPからAPにINIT-SIPI-SIPIという順番で信号を送る.
    • INITは,プロセッサを初期化する信号
      • Delivery ModeにINITを指定
      • Destination FieldにLocal APIC IDを指定
    • SIPIは,プロセッサに実行を開始させる信号
      • Delivery ModeにStart Upを指定
      • Destination FieldにLocal APIC IDを指定
      • Vectorに「開始アドレス/0x1000」を指定

手順

  • INIT信号を開始する.(Level=Assert)
  • 100マイクロ秒待つ.
  • INIT信号を停止する.(Level=De-assert)
  • 10ミリ秒待つ.
  • 1回目のSIPI信号を送る.
  • 200マイクロ秒待つ.
  • 2回目のSIPI信号を送る.

10

11 of 19

BSPのINIT-SIPI-SIPI送信における待ち時間の測定

時間を測定する方法はいろいろあるがHeliOSではHPET(High Precision Event Timer)を使用する.

11

12 of 19

APの起動

  • 物理アドレス0x1000から0x10000をAPの起動に利用することに
    • 最初の1MiBの範囲のうち,QEMU,VirtualBox,VMware,GPD MicroPCで共通して使える領域だったから
  • BSPはAPを起動する前に/HeliOS/processor/boot_loader.binを,物理アドレス0x1000に配置
    • ソースはアセンブラで記述
  • APの実行開始アドレスは物理アドレス0x1000
  • APのスタックの底は物理アドレス0x10000
    • 全APが同じ場所をスタックとして使用するので,複数のAPが同時にboot_loader.binを実行してはいけない.

12

実際のログ

13 of 19

APが16ビットモードから32ビットモードへ移行

  • 仮のGDTを設定する.
  • 一時的にページングを無効化する.
  • 32ビットプロテクトモード有効化する.
  • 32ビットコードセグメントにジャンプする.

13

14 of 19

APが32ビットモードから64ビットモードへ移行

  • BSPが用意したAP用のPML4 tableを自身のCR3に設定する.
  • CR4のPAEフラグを立てる.
    • PAEフラグは32ビットを超える物理アドレスを使えるようにする.
  • IA32_EFERのLMEフラグとNXEフラグを立てる.
    • LMEフラグは64ビットモードを有効化する.
    • NXEフラグは実行不可フラグNXを有効化する.
  • CR0のPGフラグを立てる.
    • PGフラグはページングを有効化する.
  • 64ビットコードセグメントにジャンプする.

14

15 of 19

ELFへの移行

  • メモリの全体像

  • BSP側であらかじめ自身のPML4 tableから各AP用のPML4 tableを複製,編集し,図の仮想メモリ空間を準備しておく.
  • APはBSPが指定したPML4 tableのアドレスをCR3に設定し,RSPを0にし,ELFのエントリにジャンプするだけ.

15

16 of 19

プロセッサ間通信

  • APを起動するINIT-SIPI-SIPIと同様に,Local APIC RegisterのICR(Interrupt Command Register)を使用する.
    • 送信側プロセッサがICRに書き込みを行うと,受信側プロセッサで割り込みが発生する.
      • Delivery ModeにFixedを指定
      • Destination Fieldに受信側プロセッサの�Local APIC IDを指定
      • Vectorに割り込み番号を指定

  • メッセージ列挙体

16

←APのブート完了を通知

←文字送信

←APがHLTループに入ることを通知

17 of 19

APからBSPへのハローワールド

  • Charメッセージを使って,APからBSPへ文字列を送るbsp_println!マクロを作成

17

メッセージ列挙体

AP側のkernel.elf

BSPは全てのAPからKernelCompletedを受け取ったら,

APから受信した文字列を表示

←APのブート完了を通知

←文字送信

←APがHLTループに入ることを通知

18 of 19

今後の課題

  • 現状はAPからBSPへの一方通行のメッセージのみ.
  • 双方向通信など,より高度なことをするためには�atomicやmutexなどを勉強する必要あり.

18

19 of 19

参考文献

ご清聴ありがとうございました!

19