組込みOS自作入門【Windows11, WSL2】(2nd ステップ以降)

書籍『12ステップで作る 組込みOS自作入門』を読みながらWindows11のWSL2環境でOS自作を進めています。

先日、環境構築をしてHello Worldするまでの方法を記事にしました。

環境構築(1/2 - USBシリアル編):
組込みOS自作入門 環境構築 【Windows11, WSL2】(1/2 - USBシリアル編) - ちょっとした公開めも

環境構築(2/2 - ツールインストール、Hello World! 編):
組込みOS自作入門 環境構築 【Windows11, WSL2】(2/2 - ツールインストール、Hello World! 編) - ちょっとした公開めも


今回は、2ndステップ以降で環境による差異がありそうなところや少し詰まるかもしれないところだけをピックアップして書き残しておきたいと思います。
(2025/3/15追記)自分で見返すためにステップごとにコメントもつけました。



目次


環境


2nd ステップ

書籍の通りに進めて、特に問題なく完了できました。

コメント
1st ステップでは環境構築とHello Worldの出力までを行いました。
2nd ステップでは各種ライブラリ関数の追加と数値の出力を行いました。
この時点では自動変数の書き換えはできますが静的変数の書き換えができません。


3rd ステップ

書籍の通りに進めて、特に問題なく完了できました。

コメント
1st, 2nd ステップではプログラムをフラッシュROMに書き込み、そのままROM上で実行していたため静的変数の書き換えができませんでした。
3rd ステップではこれを改善するために、プログラム起動時にROM上の変数の初期値をRAM上にコピーし(②)、プログラムから変数へのアクセスはコピーしたRAM上のアドレスに対して行いました(①)。

実装では以下の対応をしています。
①リンカ・スクリプトに「VA ≠ PA」対応、つまり仮想アドレスをRAMに、物理アドレスをROMに割り当てる対応
 ・MEMORYコマンドで各メモリの領域(先頭アドレスとサイズ)を定義
 ・SECTIONSコマンドで各セクションをMEMORYコマンドで定義したどの領域に配置するか指定
   「> data AT > rom」:.dataセクションをRAM上のdata領域のアドレスをベースにリンク。物理アドレスをrom領域上に設定。(つまりROM上にロードするということ)

②main.cにデータ領域とBSS領域を初期化する処理を追加(これを行わないと初期値が未設定になる)
 ・データ領域はmemcpyで初期値をコピー
   コピー元:.rodataセクションの終端(ROM上の.dataセクションの先頭アドレス)
   コピー先:RAM上の.dataセクションの先頭アドレス
 ・BSS領域はmemsetでRAM上の.bssセクションの先頭アドレスから0で初期化

そもそもリンクとは...
main.cなどをmakeの実行によりコンパイルして生成したオブジェクトファイル(main.oなど)は、機械語の実行コードを持つが静的変数や関数のアドレスは決定されていない。オブジェクトファイルをリンクすることでそれらのアドレスを決定して最終的な実行形式ファイルが生成される。(p39参照)

ロードとは...
プログラム実行時にセグメント情報を参照してメモリ上に展開する処理のこと。



4th ステップ

ファイル転送アプリをインストール

最初は sx も lsx も入っていませんでした。

$ sx --version
コマンド 'sx' が見つかりません。次の方法でインストールできます:
sudo apt install lrzsz

lrzsz をインストールします。

$ sudo apt install lrzsz
$ sx --version
sx (lrzsz) 0.12.21rc
ファイル転送

lrzsz をインストールしても lsx はインストールされないため、sx を使用します。
書籍と同様、defines.h を転送します。

書籍に記載の通りに「~C」と入力しても子プロセスの起動に移ることはできません。

kzload> load
~C[Unrecognized.  Use ~~ to send ~]

(こうなると何を押しても反応しなくなると思います。H8のリセットボタンを押しましょう。)

参考記事に倣って、「~+」を入力します。
私の環境では、「~」を入力して1秒ほどで[PC名]が表示されます。間髪入れずに「+」を入力すると表示されないのですが...
表示されてもされなくても挙動は変わらないので気にしなくて良いです。

「load」をプロンプトに入力 & Enter すると約8秒に1回の頻度で文字化けしたお豆腐が表示されますが、これも気にしなくて良いです。(スクショを載せておきます)

$ sudo cu -s 9600 -l /dev/ttyUSB0
Connected.
kzload (kozos boot loader) started.
kzload> load
~[(PC名)]+sx defines.h
Sending defines.h, 1 blocks: Give your local XMODEM receive command now.
Bytes Sent:    256   BPS:37

Transfer complete

XMODEM receive succeeded.

dump は書籍の通りです。

kzload> dump
size: 100
23 69 66 6e 64 65 66 20  5f 44 45 46 49 4e 45 53
5f 48 5f 49 4e 43 4c 55  44 45 44 5f 0a 23 64 65
66 69 6e 65 20 5f 44 45  46 49 4e 45 53 5f 48 5f
49 4e 43 4c 55 44 45 44  5f 0a 0a 23 64 65 66 69
6e 65 20 4e 55 4c 4c 20  28 28 76 6f 69 64 20 2a
29 30 29 0a 23 64 65 66  69 6e 65 20 53 45 52 49
41 4c 5f 44 45 46 41 55  4c 54 5f 44 45 56 49 43
45 20 31 0a 0a 74 79 70  65 64 65 66 20 75 6e 73
69 67 6e 65 64 20 63 68  61 72 20 20 75 69 6e 74
38 3b 0a 74 79 70 65 64  65 66 20 75 6e 73 69 67
6e 65 64 20 73 68 6f 72  74 20 75 69 6e 74 31 36
3b 0a 74 79 70 65 64 65  66 20 75 6e 73 69 67 6e
65 64 20 6c 6f 6e 67 20  20 75 69 6e 74 33 32 3b
0a 0a 23 65 6e 64 69 66  0a 1a 1a 1a 1a 1a 1a 1a
1a 1a 1a 1a 1a 1a 1a 1a  1a 1a 1a 1a 1a 1a 1a 1a
1a 1a 1a 1a 1a 1a 1a 1a  1a 1a 1a 1a 1a 1a 1a 1a

kzload> ~[(PC名)].
Disconnected.

参考記事:
「12 ステップで作る 組込み OS 自作入門」の開発環境を揃えてみる

5th ステップ以降も順次更新していく予定です。(2024/7/20)

コメント
3rd ステップまではプログラムを修正する度にフラッシュROMに書き込んで動作させていましたが、ROMに上書きできる回数は有限のため、今後はPCでコンパイルした実行ファイル(OS)をH8のRAM上にシリアル転送する方針で準備を進めていきます。

ブート・ローダー:「OSの実行形式ファイルをシリアル経由でダウンロードし、それをRAM上に展開して起動するプログラムをフラッシュROMに書き込む」ようなプログラム。
ブート・ストラップ:電源ONでブート・ローダーを起動し、ブート・ローダーでOSをダウンロードして起動するようなOSの起動手順。

4~6th ステップでブート・ローダーを作成していきますが、4th ステップではファイルをシリアル経由でダウンロードして、その内容を16進ダンプできるようにするところまで実装しました。
ロードする際はリンカ・スクリプトを変更してRAM上に確保した.bufferセクションにロードするようにしています。


5th ステップ

書籍の通り、問題なくできました。

ただ、4th ステップの kzload.elf をそのまま5th ステップにコピーすると5th ステップの kzload.elf とファイル名が一致してしまうため、kzload04.elf にファイル名を変更する変更だけしました。

$ sudo cu -s 9600 -l /dev/ttyUSB0
Connected.
kzload (kozos boot loader) started.
kzload> load
~+sx kzload04.elf
Sending kzload04.elf, 38 blocks: Give your local XMODEM receive command now.
Bytes Sent:   4992   BPS:354

Transfer complete

XMODEM receive succeeded.
kzload> dump
size: 1380
7f 45 4c 46 01 02 01 00  00 00 00 00 00 00 00 00
00 02 00 2e 00 00 00 01  00 00 01 00 00 00 00 34
00 00 08 d0 00 81 00 00  00 34 00 20 00 03 00 28
(略)
69 61 6c 5f 73 65 6e 64  5f 62 79 74 65 00 5f 73
74 61 63 6b 00 5f 6d 61  69 6e 00 5f 65 72 6f 64
61 74 61 00 1a 1a 1a 1a  1a 1a 1a 1a 1a 1a 1a 1a

kzload> run
000094 00000000 00000000 00100 00100 06 01
000194 00000100 00000100 006ec 006ec 05 01
000880 00fffc20 000007ec 00010 00024 06 01
kzload> ~.
Disconnected.

(2024/7/22)

コメント
4th ステップに続いてブート・ローダーの作成中です。5th ステップではダウンロードしたELFファイルを解析してセグメント情報を表示する処理を追加しました。



6th ステップ

書籍の通り、問題なくできました。

kozos.elf ファイルの中身を観察
$ cd ~/12step_emb_os/osbook_03/06/os
$ make
$ readelf -a kozos.elf > kozos_elf.txt
bootload ファイル書き込み
$ cd ../bootload/
$ make
$ make image
$ sudo make write
load, run, echo
$ cd ../os
$ sudo cu -s 9600 -l /dev/ttyUSB0
Connected.
kzload (kozos boot loader) started.
kzload> load
~+sx kozos
Sending kozos, 11 blocks: Give your local XMODEM receive command now.
Bytes Sent:   1536   BPS:334

Transfer complete

XMODEM receive succeeded.
kzload> run
starting from entry point: ffc020
Hello World!
> echo 1234567890
 1234567890
> echo123
123
> exit
~.
Disconnected.

(2024/7/24)

コメント
6th ステップでブート・ローダーを完成させました。
解析したセグメント情報を参照して、セグメントをメモリに展開(コピー)する処理とエントリ・ポイントを取得する処理を加えました。