NetBSDカーネル改造記 : 起動時に任意のメッセージを表示させる

## 今回の目的
NetBSDカーネルのソースコードを変更し、起動時に「Hello from kernel」のような任意のメッセージを表示させることを目指します。

## 学習の動機
最近、低レイヤー、特にOSの仕組みに関心を持つようになり、Linux以外のオープンソースOSにも触れてみたいという好奇心から実際に試してみることにしました。
また、普段使っているOSがどのようにプログラムされ、どのように動作しているのかを、自分の目で確かめたいという気持ちもあります。

中でもNetBSDを選んだ理由は、移植性に優れており、設計がシンプルで整っていると知ったためで、初心者でも比較的扱いやすいのではないかと考えたからです。

### 環境
#### VirtualBox

<dl>
  <dt>・インストール時のバージョン</dt>
  <dd>VirtualBox-7.1.6(2025/01/28)</dd>
  <dt>・ファイル名(インストーラ)</dt>
  <dd>VirtualBox-7.1.6-167084-Win.exe</dd>
</dl>

#### NetBSD
<dl>
  <dt>・インストール時のバージョン</dt>
  <dd>NetBSD-10.1(2025/04/25)</dd>
</dl>

:::note warn
 注意書き
今回、ユーザーを追加する手間を省くため、すべて管理者権限でコマンドを実行しました。
しかし、この方法は推奨されませんので、通常は適切なユーザー権限で作業を行ってください。
:::


## 作業手順
作業手順は以下の7つのステップで進めます。

1. NetBSDのインストール
2. 次の作業に入る前に (ネットワーク編)
3. カーネルソースコードの取得
4. 次の作業に入る前に (カーネルビルド編)
5. カーネルソースコードの編集
6. カーネルのビルドとインストール
7. カスタムカーネルでの起動



## 1. NetBSDのインストール
まず、下のリンクからNetBSDのisoイメージをダウンロードしました。

https://wiki.netbsd.org/ports/amd64/

VirtualBoxへのインストール手順は、次の記事を参考にしました。
(http通信なので、自己責任でお願いします)

http://bootcamp119.blog.fc2.com/blog-entry-10.html

## 2. 次の作業に入る前に (ネットワーク編)

ネットワークに接続しておきましょう。

NetBSD起動後、ルートディレクトリに移動しましょう。
pwdコマンドを打ち、カレントディレクトリを確認します。
```
pwd
```

カレントディレクトリがルートディレクトリでない場合、移動します。
```
cd /
```
移動後、ipconfigコマンドで、TCP/IP構成を表示させます。
```
ipconfig -a
```
TCP/IPの構成名が分かったら、dhcpcdコマンドでIPアドレスを自動取得します。
(私の環境では、wm0でした)
```
dhcpcd wm0
```
これでIPアドレスが取得でき、ネットワークに接続されているはずです。

pingコマンドを使用して、ネットワークが接続できたか確認します。
```
ping google.com
```
下の画像のように応答が返っていれば、ネットワーク接続は正常です。
![pingコマンドでネットワーク確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/2e49bda9-6e09-4584-8000-6b13609648a3.png)

:::note info
何もしないとずっと応答速度を表示するため、ある程度確認出来たら
ctrl+cで強制終了させましょう
:::
## 3. カーネルソースコードの取得
作業に入る前に、カーネルについて簡単に解説します。
#### カーネルとは
オペレーティングシステムの内部部分をカーネルと呼び、コンピュータの稼働に必要な基本的機能を提供するソフトウェアです。
このソフトウェアの挙動を記述しているソースコードが、今回取得するカーネルソースコードです。

カーネルソースコードは、ftpコマンドを使用して公式CDNから取得しました。
以下のリンクから必要なファイルをすべて取得します。

https://cdn.netbsd.org/pub/NetBSD/NetBSD-10.1/source/sets/

これを、NetBSDで展開します。
具体的には、ルートディレクトリにカーネルソースコードを取得し、その後ファイルを展開します。


ftpコマンドで先ほどのリンク先のファイルをすべて取得します。
```
ftp https://cdn.NetBSD.org/pub/NetBSD/NetBSD-10.1/source/sets/MD5
ftp https://cdn.NetBSD.org/pub/NetBSD/NetBSD-10.1/source/sets/SHA512
ftp https://cdn.NetBSD.org/pub/NetBSD/NetBSD-10.1/source/sets/gnusrc.tgz
ftp https://cdn.NetBSD.org/pub/NetBSD/NetBSD-10.1/source/sets/sharesrc.tgz
ftp https://cdn.NetBSD.org/pub/NetBSD/NetBSD-10.1/source/sets/src.tgz
ftp https://cdn.NetBSD.org/pub/NetBSD/NetBSD-10.1/source/sets/syssrc.tgz
ftp https://cdn.NetBSD.org/pub/NetBSD/NetBSD-10.1/source/sets/xsrc.tgz
```

取得したファイルを展開します。
```
tar -xzvf gnusrc.tgz
tar -xzvf sharesrc.tgz
tar -xzvf src.tgz
tar -xzvf syssrc.tgz
tar -xzvf xsrc.tgz
```

ファイルを正常に展開出来ているか確認しましょう。
ルートディレクトリから展開したので、先ほどのファイルが/usrに保存されています。

![展開後写真.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/7f379731-48db-4c73-8a27-11a5fe7a7cc7.png)

画像のような状態になれば準備完了です。

## 4. 次の作業に入る前に (カーネルビルド編)
本章は「第6章で行うカーネルビルド手順の全体像」を説明するための章です。
実際に起動時メッセージを追加する作業は第5章以降で行いますので、概要を把握した後は、第5章へ進んで構いません。

また、この章以降、エラーが連発し、なかなか進めなかったのですが、以下の記事を参考にしたら実行できたため、こちらの記事をベースに解説を進めていきます。

https://qiita.com/furandon_pig/items/d9b2782372edc1b93263

作業に入る前に、ビルドについて簡単に解説します。
#### ビルドとは
カーネルは、ソースコード形式で開発・配布が行われています。
しかし、ソースコードのままではコンピュータは実行できないため、コンピュータが解釈・実行できる形式に変換し、実行可能なファイルを作成します。
このプロセスのことを「ビルド」と呼びます。

まず、GENERICというカーネルファイルをコピーします。
```
# cd /usr/src/sys/arch/amd64/conf
#cp GENERIC VMP
```
ちなみに私の環境だと、
/usr/src/sys/arch/amd64/conf内は以下のようになっています。

![confの中身.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/47a5c33c-746f-4932-9fdf-6e46c1bd7f48.png)

次に、カーネルのビルドを実行します。
```
# config VMP
Build directory is ../compile/VMP
Don't forget to run "make depend"
# cd ../
# cd compile/VMP
# make depend
# make 2>&1 | tee _make.20141205.0.log
# make
```
:::note info
ここで実行するmakeコマンドは時間がかかるので気長に待ちましょう
:::

ビルドが完了したら、生成したnetbsdファイルを確認します。
```
# find . -name netbsd
# file netbsd
# ls -lh netbsd
```
上記コマンドの実行結果は、以下の画像の通りです。
![makeコマンド後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/a2b3c508-29a2-4d2c-9d98-33340ae9f688.png)

生成したカーネルファイルを/netbsd.VMPとしてコピーします。
```
# cp -pi netbsd /netbsd.VMP
```

## 5. カーネルソースコードの編集
カーネルの起動時に任意のメッセージを表示するために、init_main.cを編集します。
```
# cd /usr/src/sys/kern
# vi init_main.c
```
init_main.cには、banner関数があります。
この関数は、NetBSD起動時に著作権情報やバージョン情報、メモリサイズ等を表示させる関数です。

```
void
banner(void)
{
	static char notice[] = " Notice: this software is "
	    "protected by copyright";
	char pbuf[81];
	void (*pr)(const char *, ...) __printflike(1, 2);
	int i;

	if ((boothowto & AB_SILENT) != 0) {
		snprintf(pbuf, sizeof(pbuf), "%s %s (%s)",
		    ostype, osrelease, kernel_ident);
		printf_nolog("%s", pbuf);
		for (i = 80 - strlen(pbuf) - sizeof(notice); i > 0; i--)
			printf(" ");
		printf_nolog("%s\n", notice);
		pr = aprint_normal;
	} else {
		pr = printf;
	}

	memset(pbuf, 0, sizeof(pbuf));
	(*pr)("%s%s", copyright, version);
	format_bytes(pbuf, MEM_PBUFSIZE, ctob((uint64_t)physmem));
	(*pr)("total memory = %s\n", pbuf);
	format_bytes(pbuf, MEM_PBUFSIZE, ctob((uint64_t)uvm_availmem(false)));
	(*pr)("avail memory = %s\n", pbuf);
}
```
(https://github.com/NetBSD/src/blob/trunk/sys/kern/init_main.c#L1170)

banner関数の最下部を以下のように編集します。
```
	memset(pbuf, 0, sizeof(pbuf));
	(*pr)("%s%s", copyright, version);
	format_bytes(pbuf, MEM_PBUFSIZE, ctob((uint64_t)physmem));
	(*pr)("total memory = %s\n", pbuf);
	format_bytes(pbuf, MEM_PBUFSIZE, ctob((uint64_t)uvm_availmem(false)));
	(*pr)("avail memory = %s\n", pbuf);
    (*pr)("=== Welcome to Mika's kernel ===\n"); 
```
:::note info
上記画像の(*pr)("=== Welcome to Mika's kernel ===\n"); が
新しく追加した部分です。
:::
新しく追加した(*pr)("=== Welcome to Mika's kernel ===\n"); 内で、
「=== Welcome to Mika's kernel ===」の部分が、好きなメッセージを設定できるところです。

## 6. カーネルのビルドとインストール
変更を加えた後、「4. 次の作業に入る前に (カーネルビルド編)」で行った手順と同じようにビルドします。
```
# cd /usr/src/sys/arch/amd64/conf/
# config VMP
Build directory is ../compile/VMP
Don't forget to run "make depend"
# cd ../
# cd compile/VMP
# make depend
# make 2>&1 | tee _make.20141205.0.log
```
中身の確認をしておきます。
```
# strings ./netbsd | grep 'Welcome'
# file netbsd
# ls -lh netbsd
```
実行結果は、以下の画像の通りです。
![makeコマンド後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/644ec0f5-4634-4ad8-aeeb-38a5e234fb71.png)


生成したカーネルファイルをコピーします。
```
# cp -pi ./netbsd /netbsd.VMP
```

これで準備は完了です。

## 7. カスタムカーネルでの起動
では、さっそく起動時に先ほど加えたメッセージが表示されるか確認します。

仮想マシンを再起動すると、ブート直後に以下の画面が表示されます。
ここで、「in 1 seconds」と表示されるのですが、ここが0となるまでにスペースキーを押すことで、起動時のオプションを選択することができます。

オプション内の「Drop to boot prompt」を選択します。
(私の場合は、3が該当していたため、3を入力しています)
![bootオプション選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/84967427-3ec0-431d-8505-f0b1de538ca9.png)

「Drop to boot prompt」を選択後、helpコマンドを入力し、利用可能なコマンド一覧を確認しましょう。
"boot"というコマンドにカーネルファイル名を指定することで、任意のカーネルで起動できることがわかります。
![helpコマンド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/b74f60b0-9294-4421-aa45-5ebe1e1e1d76.png)

実際に、bootコマンドで任意のカーネルを起動します。
```
 boot netbsd.VMP
```
このとき、画面に先ほど追加したメッセージが表示されます。

私の場合、起動時の表示速度が速くて、スクリーンショットが取れなかったため、別の方法で確認します。

unameコマンドでシステム情報を確認しましょう。
```
uname -a
```
以下の画像が出力結果です。
VMPコンフィグによるカーネルであることが分かります。
![uname確認.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/27e91bcd-ebc9-4ee3-9fd3-4b35f7e07547.png)

起動時の画面を確認します。
ここでは、dmesgコマンドを使用し、起動画面の先頭13行を表示させます。
```
dmesg | head -n13
```
![VirtualBox_NetBSD_18_05_2025_05_07_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471729/11d64b87-270a-4515-8676-23dfdfef4d4e.png)


画像の最後の行に、新たに加えたメッセージである「=== Welcome to Mika's kernel ===」が出力されていることが確認できました！

## まとめ
カーネルソースコードに任意のメッセージを加えるという基本的な作業でしたが、実際に手を動かすことでカーネルの起動処理やビルド手順、ログ出力の流れなどを大まかに理解できました。

記事中では省略しましたが、エラー対応を通じて学んだことも多くあります。
例えば、CUI環境のNetBSDではネットワーク設定をコマンド（dhcpcd など）で行う必要があるなどを学びました。


## 参考文献
記事内で触れた参考資料をこちらにもまとめておきます

http://bootcamp119.blog.fc2.com/blog-entry-10.html

上の記事は、http通信なので、自己責任でお願いします

https://qiita.com/furandon_pig/items/d9b2782372edc1b93263