ゼロからのOS自作入門 〜環境構築からブートローダの作成まで〜
ゼロからのOS自作入門を購入しました!このブログでは、環境構築からブートローダの作成まで(本書の3章まで)を通して自分なりに分かったことを日記として投稿します。(調べながら書いたので、である調とですます調が混ざってますが、大目にみてください。)
読んだ理由
この本をTwitterのタイムラインで見かけて、元々〇〇自作にとても興味があり、面白そうだと思ったので購入しました。普段当たり前のようにお世話になっているOSですが、全く知らないのでこの本を通して学んでいきたいと思いました。
対象読者
本書によると、「簡単なプログラムを書いたことがある人」とのこと。
この本で学べること
- CやC++を使って"全部自分で"OSを自作する
私のスペック
- 普段はよくRubyを書いており、ソフトウェアエンジニアをしています。CやC++は今回初めてです。
- よく使っているOSはmacOSです。
- Vim、Git/Githubは調べながら使えます。
- 基本情報技術者に2年くらい前に
ギリギリで合格しました。 - 自作は全く初めてです。(mountコマンドの意味さえ知りませんでした。)
3章までやった感想としては、「とりあえず動かせるので楽しいけど、前提知識がなさすぎて解説が80%くらい理解できない」という感じです。
開発環境の構築
本書によると、2012年以降に発売されたパソコンを使うことが推奨されており、Ubuntu、Windowsで仮想環境を作ってLinuxが使えるようになるWSL (Windows Subsystem for Linux) 、QEMU(仮想環境)を使うやり方が紹介されています。
私は最初ベストな環境構築が分からなくて、1週間くらいハマりました。本当はMacで開発しようと思っていたのですが自分がよく分からないものは入れたくなかったので、フリマアプリで壊れてもいいパソコンを買って、本書で紹介されているLinux環境を作ることにしました。パソコンのスペックとUSBは以下です。
② USB
Windows10を完全に削除してUbuntuをインストールして開発を進めました。以下の記事が参考になりました。
yoshinorin.net
BIOSの設定は、「ThinkPadロゴが出たらF1を長押し」でいけました。私が購入した機種ではセキュアブートは設定されていなかった(設定できない?)ようで、BIOSのStartupのBootの設定から、起動時の設定でUSBの優先度をあげると、USBからでも無事起動できました☺️
試行錯誤した結果、最終的に開発環境と動作確認用端末が一緒になってしまったので、今はQEMUを使って開発を進めています。
1章 PCの仕組みとハローワールド
この章でやること
バイナリファイルを書いてUSBに配置して起動させます。
やっとOS自作入門の1章が終わった🎉めっちゃ嬉しいー!! pic.twitter.com/COzMKy2FBD
— 宮水 (@mymz_engineer) 2021年4月29日
CPU
デジタル回路で構成されており、電圧の高低、すなわち2進数を扱う。今回バイナリファイルを16進数で書いたのは、16進数の方が2進数に変換しやすいから。
UEFI
オペレーティングシステム(OS)とプラットフォームファームウェアとの間のソフトウェアインタフェースを定義する仕様のこと。OSを起動するために必要な機能を提供するブートサービスと、OS起動前、起動後どちらでも使える機能を提供するランタイムサービスから構成されている。
Unified Extensible Firmware Interface - Wikipedia(ja)
UEFI BIOS
UEFIという標準仕様に従って作られたBIOSのこと。本書でやったファイルシステムFATでフォーマットされた起動ディスクの \EFI\BOOT\ ディレクトリ下に配置されたファイルで起動するというのは、UEFIの仕様のひとつ。
mount
脳死でumountとかmountとかコマンドを打っていました。
どうして普通にUSBにファイルを置くだけでは起動しないのか分からなかったので、teratailで質問してコマンドの丁寧な解説までいただきました😢 USBメモリのルートディレクトリ下にただコピーしただけでは、PCのUEFIからOSを起動することはできないそうです。UEFIの仕様に従ってBIOSを起動するために、USBをFATでフォーマットし、mountして起動ディスクの \EFI\BOOT\ ディレクトリ下にファイルを配置したということでした。(難)
Linux - デバイスファイルにアクセスしてコピーしないと起動しないのはどうしてですか|teratail
mountの説明は以下の通りです。
「mount」は、HDDやUSBメモリ、DVD-ROMなどのフォーマット済みの領域(ファイルシステム)を指定したディレクトリ(マウントポイント)と一時的に結び付けてアクセスできるようにするコマンドです
引用元:
【 mount 】コマンド――ファイルシステムをマウントする:Linux基本コマンドTips(183) - @IT
2章 EDK Ⅱ 入門とメモリマップ
この章でやること
- EDK Ⅱという開発ツールを使ってみる。C言語で書かれたファイルをBuildして、上記で書いたバイナリファイルと同じものを作り、これをUSBメモリからメインメモリに読み込ませます。
- UEFIの機能を使ってOSにメモリマップを渡すための準備として、メモリマップを取得したりファイルに一時保存してみたりします。
C言語で書かれたファイルをコンパイルして、USBにコピーして読み込んだやつらしいです(難) pic.twitter.com/6afZBcP0iE
— 宮水 (@mymz_engineer) 2021年4月30日
メモリマップ
メインメモリのどの部分がどんな用途で使われているか載っている地図のことです。
3章 画面表示の練習とブートローダ
この章でやること
- 画面全体を塗りつぶすだけの簡単なOS本体を作り、ブートローダから起動します。
- ブートローダはUEFIアプリとして、カーネルはELFバイナリとして別々に開発し、ブートローダからカーネルを呼び出す形式にします。
- main.cppを書く→clang++コマンドでソースコードをコンパイルし、オブジェクトファイルmain.oを作成→ld.lldによってオブジェクトファイルから実行可能ファイル(kernel.elfファイル)を作成する。→edk2を使ってブートローダをbuildする→カーネルが起動する
Main.cファイルがブートローダで、main.cppがカーネルなんですね☺️
3章が終わりました。
— 宮水 (@mymz_engineer) 2021年5月8日
OSの本体ができたらしいです。 pic.twitter.com/ERmHATANhx
レジスタ
CPUに内蔵された記憶領域のこと。容量が小さく読み書きが速い。
まとめ
今回は、3章まで進めました。正直なところ、CとC++で書かれたファイルはあんまりちゃんと読めていません。 しかしながら、何をやっているか抽象的に理解しつつ、書き写して実行するだけでも楽しいです👍 これからも少しずつ進めていこうと思います。
ここまでお読みいただきありがとうございました!