179
144

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Mac で始める「ゼロからのOS自作入門」

Last updated at Posted at 2021-03-23

Mac で「ゼロからのOS自作入門」の「8.7 メモリ管理に挑戦」まで進められたので、ひとまずそこまでの手順をメモとして残しておきます。この環境構築方法で本の最後まで進められるかどうかはまだわかりません。

環境は macOS Sonoma(14.5), CPU は Intel でも Apple Silicon でも OK です。Homebrew はすでにインストールされているものとします。

PATH にいろいろ追加していきますが、適宜 .zshrc 等の PATH の設定にも追加してください。

EDK II の準備

後でインストールする binutils がすでにインストールされ PATH に追加されていると失敗するので注意してください。

$ cd $HOME
$ git clone https://github.com/tianocore/edk2.git
$ cd edk2
$ git checkout edk2-stable202208
$ git submodule update --init
$ cd BaseTools/Source/C
$ make

mikanos-build リポジトリの準備

$ cd $HOME
$ 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 ..

次の内容の mac.patch というファイルを作って適用します。

--- a/devenv/make_image.sh
+++ b/devenv/make_image.sh
@@ -23,11 +23,24 @@ qemu-img create -f raw $DISK_IMG 200M
 mkfs.fat -n 'MIKAN OS' -s 2 -f 2 -R 32 -F 32 $DISK_IMG
 
 $DEVENV_DIR/mount_image.sh $DISK_IMG $MOUNT_POINT
-sudo mkdir -p $MOUNT_POINT/EFI/BOOT
-sudo cp $EFI_FILE $MOUNT_POINT/EFI/BOOT/BOOTX64.EFI
+if [ `uname` = 'Darwin' ]; then
+    mkdir -p $MOUNT_POINT/EFI/BOOT
+    cp $EFI_FILE $MOUNT_POINT/EFI/BOOT/BOOTX64.EFI
+else
+    sudo mkdir -p $MOUNT_POINT/EFI/BOOT
+    sudo cp $EFI_FILE $MOUNT_POINT/EFI/BOOT/BOOTX64.EFI
+fi
 if [ "$ANOTHER_FILE" != "" ]
 then
-    sudo cp $ANOTHER_FILE $MOUNT_POINT/
+    if [ `uname` = 'Darwin' ]; then
+        cp $ANOTHER_FILE $MOUNT_POINT/
+    else
+        sudo cp $ANOTHER_FILE $MOUNT_POINT/
+    fi
 fi
 sleep 0.5
-sudo umount $MOUNT_POINT
+if [ `uname` = 'Darwin' ]; then
+    hdiutil detach $MOUNT_POINT
+else
+    sudo umount $MOUNT_POINT
+fi
diff --git a/devenv/mount_image.sh b/devenv/mount_image.sh
index ba8233e..aea4d7d 100755
--- a/devenv/mount_image.sh
+++ b/devenv/mount_image.sh
@@ -16,5 +16,9 @@ then
     exit 1
 fi
 
-mkdir -p $MOUNT_POINT
-sudo mount -o loop $DISK_IMG $MOUNT_POINT
+if [ `uname` = 'Darwin' ]; then
+    hdiutil attach -mountpoint $MOUNT_POINT $DISK_IMG
+else
+    mkdir -p $MOUNT_POINT
+    sudo mount -o loop $DISK_IMG $MOUNT_POINT
+fi
$ patch -p1 < mac.patch

QEMU のインストール

Homebrew でインストールします。

$ brew install qemu

LLVM のインストール

本では LLVM7 を使っていますが、現在(2024 年 7 月時点) mikanos リポジトリでは LLVM14 を使うようになっていることに合わせて LLVM14 を使います。

$ brew install llvm@14

# Intel Mac の場合
$ export PATH=/usr/local/opt/llvm@14/bin:$PATH

# Apple Silicon Mac の場合
$ export PATH=/opt/homebrew/opt/llvm@14/bin:$PATH

その他のビルドに必要なパッケージのインストール

$ brew install nasm dosfstools binutils

# Intel Mac の場合
$ export PATH=/usr/local/opt/binutils/bin:$PATH

# Apple Silicon Mac の場合
$ export PATH=/opt/homebrew/sbin:/opt/homebrew/opt/binutils/bin:$PATH

「2.2 EDK II でハローワールド」をビルドする

$ cd $HOME
$ mkdir workspace
$ cd workspace
$ git clone https://github.com/uchan-nos/mikanos.git
$ cd mikanos
$ git checkout osbook_day02a
$ cd $HOME/edk2
$ ln -s $HOME/workspace/mikanos/MikanLoaderPkg .
$ source edksetup.sh

https://github.com/uchan-nos/mikanos/commit/b5f7740c04002e67a95af16a5c6e073b664bf3f5 で行われいるのと同じ変更を MikanLoaderPkg/MikanLoaderPkg.dsc に行います。(この変更は mikanos リポジトリの master ブランチには入っているが先ほどチェックアウトした osbook_day02a タグには入っていないので手動で変更する必要があります。)

Conf/target.txt を開き次のように変更します。TOOL_CHAIN_TAG が本とは異なるので注意してください。CLANG38 ツールチェインは Linux でしか使えないため代わりに CLANGPDB ツールチェインを使用します。

設定項目 設定値
ACTIVE_PLATFORM MikanLoaderPkg/MikanLoaderPkg.dsc
TARGET DEBUG
TARGET_ARCH X64
TOOL_CHAIN_TAG CLANGPDB

変更を保存したらビルドします。

$ build

$HOME/edk2/Build/MikanLoaderX64/DEBUG_CLANGPDB/X64/Loader.efi というファイルが作られれば成功です。

QEMU で実行

次のようにして QEMU を実行します。

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

うまくいくと QEMU が起動し、さっきビルドしたプログラムが実行されるはずです。

スクリーンショット 2021-03-23 23.45.51.png

「3.3 初めてのカーネル」の補足

本とは異なり「LLVMのインストール」で LLVM14 を使うようにしました。LLVM 10 以降では -z separate-code というオプションをつけてリンクしないと本書のブートローダでロードすることができません。(「ゼロからのOS自作入門」 03日目 を参考にさせていただきました。ありがとうございます。)

本の

$ ld.lld $LDFLAGS --entry KernelMain -z norelro --image-base 0x100000 --static -o kernel.elf main.o

の代わりに

$ ld.lld $LDFLAGS --entry=KernelMain -z norelro --image-base 0x100000 --static -o kernel.elf -z separate-code main.o

とします。

「3.4 ブートローダからピクセルを描く」の補足

Linux では標準のシェルとして bash が使われているのに対し、Mac では zsh が使われています。変数に含まれるスペースの扱いが zsh と bash では異なるため、bash を前提としている本の

$ clang++ $CPPFLAGS -O2 --target=x86_64-elf -fno-exceptions -ffreestanding -c main.cpp

ではコンパイルできません。代わりに

$ clang++ ${=CPPFLAGS} -O2 --target=x86_64-elf -fno-exceptions -ffreestanding -c main.cpp

としてください。

「3.5 カーネルからピクセルを描く」の補足

『「2.2 EDK II でハローワールド」をビルドする』で TOOL_CHAIN_TAG に本で指定している CLANG38 ではなく、CLANGPDB を指定しました。CLANG38 ツールチェインは System V AMD64 ABI を使用しますが、CLANGPDB ツールチェインは Microsoft x64 ABI を使用します。(ABI については本の「コラム 4.1 ABI」を参照してださい。)このため System V AMD64 ABI で引数が渡ってくることを想定しているカーネルの KernelMain に引数を渡せません。そこで本のリスト 3.8 の

typedef void EntryPointType(UINT64, UINT64);

typedef void __attribute__((sysv_abi)) EntryPointType(UINT64, UINT64);

にすると、強制的に System V AMD64 ABI でカーネルを呼び出すことができ、引数を渡せます。

「4.1 make 入門」の補足

Makefile の LDFLAGS の行を変更し、-z separate-code をつけてリンクするようにします。

LDFLAGS += --entry KernelMain -z norelro --image-base 0x100000 --static -z separate-code

「5.2 分割コンパイル」の補足

Makefile で sed を使うようになりますが、Linux の sed と Mac の sed はコマンドラインオプションが異なります。sed を使う行は

	sed -I '' -e 's|$(notdir $(OBJ))|$(OBJ)|' $@

にする必要があります。

また本とは使用するツールチェインが異なるためだと思いますが、 make を実行すると

ld.lld: error: undefined symbol: __cxa_pure_virtual
>>> referenced by graphics.cpp
>>>               graphics.o:(vtable for PixelWriter)
make: *** [kernel.elf] Error 1

というエラーが出るようになります。完全仮想関数を呼び出そうとしてしまった場合に呼ばれるエラーハンドラの実装を提供する必要があるそうです。(OS 自作に便利な C++ の機能 10 選(前編))

main.cpp に次のような実装を書いておくとビルドできるようになります。

extern "C" void __cxa_pure_virtual() {
  while (1) __asm__("hlt");
}
179
144
17

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
179
144

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?