去年買った「ゼロからのOS自作入門」という本(通称「みかん本」)、ある程度進めてからしばらく放置してしまっていたのですが、最近OSの卒業研究でのxv6やLinuxカーネルのコードリーディングを通して、さらに理解を深めるために再びみかん本の写経をやりたいという欲が出てきました。
せっかくなので、現在のメイン機であるM1 Macでできるところまでやってみます。手元のUbuntu機にも同様の環境を導入していますが、Ubuntuへの導入方法については本に記載されている通りのためここでは省きます。
完走できるかどうか分かりませんが、忘備録も兼ねて、今日から開発日記ならぬ写経日記的なものを不定期に書いていきたいと思います。ところどころで独自の実装や改造などもしていきたいなぁと思ってます。

なお、あまり本の内容に深入りしてしまうとネタバレ(?)になってしまうので、あくまでも進捗報告や自分なりに工夫した点、感想などを書いていくだけに留まらせていただきます。気になる方は本をご購入ください。

はじめに

みかん本ではUbuntuまたはWSLで進めることが推奨されています。必ずしもM1 Macで本の通りに動くとは限らないので要注意。また、ライブラリ等のバージョンにより動作が大きく異なる場合があります。実験環境を示しておきますのでご参照ください。
また、1章の部分は以前進めたので飛ばし、いきなり2章から始めさせていただきます。

実験環境

  • MacBook Air 2020
    • macOS Monterey 12.4
    • Chip: Apple M1 (arm64)
    • RAM: 8GB
  • 導入環境

    • Cコンパイラ(LLVM): Homebrew clang version 14.0.6 (CLANGPDB)
    • QEMU: qemu-system-x86_64 version 7.0.0
    • NASM: version 2.15.05
    • dosfstools: stable 4.2
    • binutils: stable 2.38
  • その他

    • EDK II: 38c8be123aced4cc8ad5c7e0da9121a181b94251
    • mikanos-build: 8d4882122ec548ef680b6b5a2ae841a0fd4d07a1
    • MikanOS: osbook_day02a

参考文献

基本的にはこの記事通りに進めております。ただし、最新のClangコンパイラの問題?として、edk2のBaseToolsがビルドできない問題があり、一部のビルドエラーを無視させなければ完遂できませんでした。その手順も追って説明します。

手順

1. EDK IIの導入

edk2を任意の場所にgit cloneし、submoduleも導入します。
このとき、現状のmikanosでは最新版のEDK2ではビルドエラーが発生してしまうため、少し古めのバージョンにcheckoutしています(参照:MikanOSのビルド中にエラー - Issue #19)。

cd ~
git clone https://github.com/tianocore/edk2
cd edk2
git checkout 38c8be123aced4cc8ad5c7e0da9121a181b94251
git submodule init
git submodule update

次にEDK IIをビルドするための場所へ移動。

cd BaseTools/Source/C

いざビルド、といきたいところですが、ここで個人的に追加したポイント。このままビルドすると、以下の2つのビルドエラーが発生します。

EfiUtilityMsgs.c: In function 'PrintMessage':
EfiUtilityMsgs.c:478:9: error: '__builtin___strncat_chk' output may be truncated copying between 0 and 511 bytes from a string of length 511 [-Werror=stringop-truncation]
  478 |         strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1);
      |         ^~~~~~~
EfiUtilityMsgs.c:463:9: error: '__builtin___strncat_chk' output may be truncated copying between 0 and 511 bytes from a string of length 511 [-Werror=stringop-truncation]
  463 |         strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1);
      |         ^~~~~~~
EfiUtilityMsgs.c:505:5: error: '__builtin___strncat_chk' output may be truncated copying between 0 and 511 bytes from a string of length 511 [-Werror=stringop-truncation]
  505 |     strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1);
      |     ^~~~~~~
brotli/c/dec/decode.c:2033:41: error: argument 2 of type 'const uint8_t *' {aka 'const unsigned char *'} declared as a pointer [-Werror=vla-parameter]
 2033 |     size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size,
      |                          ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
In file included from brotli/c/dec/decode.c:7:
./brotli/c/include/brotli/decode.h:204:19: note: previously declared as a variable length array 'const uint8_t[*decoded_size]' {aka 'const unsigned char[*decoded_size]'}
  204 |     const uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(encoded_size)],
      |     ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
brotli/c/dec/decode.c:2034:14: error: argument 4 of type 'uint8_t *' {aka 'unsigned char *'} declared as a pointer [-Werror=vla-parameter]
 2034 |     uint8_t* decoded_buffer) {
      |     ~~~~~~~~~^~~~~~~~~~~~~~

1つ目のエラーは文字列の切り捨てに関するエラー、2つ目のエラーは引数のポインタに関するエラーですが…元記事ではこれらのエラーには触れられておらず、無視しても動作自体はするので、さほど影響はないかなと思います(なにか問題が起きたら追記します)。
これらのビルドエラーを回避するため、今回はコンパイルオプションを追加しエラーを無視させました。BaseTools/Source/C/Makefiles配下のheader.makefileを開き、
(変更前)

ifeq ($(DARWIN),Darwin)
# assume clang or clang compatible flags on OS X
BUILD_CFLAGS = -MD -fshort-wchar -fno-strict-aliasing -Wall -Werror \
-Wno-deprecated-declarations -Wno-self-assign -Wno-unused-result -nostdlib -g

ここに-Wno-stringop-truncation-Wno-vla-parameterを追加します。
(変更後)

ifeq ($(DARWIN),Darwin)
# assume clang or clang compatible flags on OS X
BUILD_CFLAGS = -MD -fshort-wchar -fno-strict-aliasing -Wall -Werror \
-Wno-deprecated-declarations -Wno-self-assign -Wno-unused-result -Wno-stringop-truncation -Wno-vla-parameter -nostdlib -g

これでOK。ビルドしてみます。

make

最後にFinished building BaseTools C Tools with HOST_ARCH=AARCH64と表示されたらEDK IIのビルドは完了です。

2. mikanos-buildの準備

mikanosのリポジトリを用意します。ビルドと実行用のツールがここに含まれます。

cd ~
git clone https://github.com/uchan-nos/mikanos-build.git osbook
cd osbook/devenv
curl -L https://github.com/uchan-nos/mikanos-build/releases/download/v2.0/x86_64-elf.tar.gz | tar xz
cd ../

次にmikanos-buildの各ファイルをMac用に書き換える必要がありますが、ここでMac用のパッチファイルmac.patchを生成します。
パッチファイルを生成してくださった方がいらっしゃいますので、今回はこれを使わせていただきます。Qiitaに記載されているものをコピペして~/osbook/に生成します。
このとき、マウス操作でコピペするとpatchファイルの空白等がうまくコピペできず正常に動作しない場合があり、Qiitaのコピペボタンでコピペすることをオススメします。

mac.patchを生成したら、以下のコマンドによって各ファイルにパッチを適用することでMac用にmikanos-buildの各ファイルが書き換えられます。

patch -p1 < mac.patch

3. 環境の準備

qemu、llvm、nasmといった必要な環境をインストールしてパスを通す。

brew install qemu
brew install llvm
export PATH=/opt/homebrew/opt/llvm/bin:$PATH
brew install nasm dosfstools binutils
export PATH=/opt/homebrew/sbin:/opt/homebrew/opt/binutils/bin:$PATH

4. ワークスペースの準備

主にOSのファイルを置いておく場所を用意します。

cd ~
mkdir workspace
cd workspace
git clone https://github.com/uchan-nos/mikanos.git
cd mikanos

今回はosbook_day02aにcheckoutして使います。

git checkout osbook_day02a

5. シンボリックリンクの生成

edk2にmikanosのworkspaceにあるMikanLoaderPkgへのシンボリックリンクを生成しておきます。そして、edksetup.shをsourceで読み込みます。

cd ~/edk2
ln -s ~/workspace/mikanos/MikanLoaderPkg ./
source edksetup.sh

これによりConf/配下にtarget.txttools_def.txtが生成されます。

6. Conf/target.txtの設定

以下の箇所を書き換えます。(書き換え前 → 書き換え後)

  • ACTIVE_PLATFORM
    • EmulatorPkg/EmulatorPkg.dsc → MikanLoaderPkg/MikanLoaderPkg.dsc
  • TARGET_ARCH
    • IA32 → X64
  • TOOL_CHAIN_TAG
    • VS2015x86 → CLANGPDB
︙
ACTIVE_PLATFORM       = MikanLoaderPkg/MikanLoaderPkg.dsc
︙
TARGET                = DEBUG
︙
TARGET_ARCH           = X64
︙
TOOL_CHAIN_TAG        = CLANGPDB
︙

7. ビルド&実行!

ようやっと準備が整いました。edk2にてbuildを実行。

build

最後に

- Done -
Build end time: 04:01:25, Aug.12 2022
Build total time: 00:00:06

こんな感じのが出てきたらビルド成功です。~/edk2/Build/MikanLoaderX64/DEBUG_CLANGPDB/X64/Loader.efiというファイルが生成されているはずです。

最後にQEMUで実行します。

~/osbook/devenv/run_qemu.sh ~/edk2/Build/MikanLoaderX64/DEBUG_CLANGPDB/X64/Loader.efi

スクリーンショット 2022-08-12 8.53.06
できた!

今後の予定

基本的には本の通りに手を動かしていきます。ある程度進んだらまた更新します。