前置き
本記事は「ゼロからのOS自作入門」のメモになります。
仕事上OSの知識があってもいいなと思って、取り組むことにしました。
各章に対し、1記事をOutputする予定です。
前の章はこちら
https://qiita.com/fuji3195/items/1495df96a164b23a9007
EDKとは
EDKⅡ:UEFI BIOS本体および、UEFI BIOS上で動くアプリケーションを開発するための開発キット
もともとIntelが実装したものをオープンソースにした。
Mikan OSを取得
git clone https://github.com/uchan-nos/mikanos.git
# EDKⅡのディレクトリににMikanOSのブートローダディレクトリをリンク
cd $HOME/edk2
ln -s $HOME/'workspace'/mikanos/MikanLoaderPkg ./
source edksetup.sh
workspace
にはgitでcloneしたワークスペースのパスを入れる。
Conf/target.txt
が生成されるので、中身のうち以下の項目を書き換える。
設定項目 | 設定値 |
---|---|
ACTIVE_PLATFORM | MikanLoaderPkg/MikanLoaderPkg.dsc |
TARGET | DEBUG |
TARGET_ARCH | X64 |
TOOL_CHAIN_TAG | CLANG38 |
build
でビルドすると、何かがビルドされる。
ハローワールド
通常のC/C++では,main()がスタートになるが、EDK2では、自由にスタート地点を決められる。
その際に、Loader.infにある、ENTRY_POINTを参照する。
buildを行おうとすると、そのままではうまくいかず、以下のエラーが出て失敗する。
/home/user/edk2/MikanLoaderPkg/MikanLoaderPkg.dsc(...): error 4000: Instance of library class [RegisterFilterLib] is not found
in [/home/user/edk2/MdePkg/Library/BaseLib/BaseLib.inf] [X64]
consumed by module [/home/user/edk2/MikanLoaderPkg/Loader.inf]
これは新しいEDKでエラーの原因が追加されたためらしい。
そこで, gitからcheckoutするとうまくいく。古いバージョンをインストールしているイメージ。
cd $HOME/edk2
git checkout 38c8be123aced4cc8ad5c7e0da9121a181b94251
メモリマップ
git checkoutで02bに変更する。
GetMemoryMap()について解説。
gs->GetMemoryMap(
IN OUT UINTN *MemoryMapSize, // 入力:メモリマップ書き込み用のメモリ領域の大きさ。出力:実際のメモリマップの大きさ。
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, // メモリマップ書き込み用のメモリ領域の先頭ポインタ。後ほど紹介。
OUT UINTN *MapKey, // メモリマップを識別するための値を書き込む変数。後で使う。
OUT UINTN *DescriptorSize, // メモリマップの個々の行を表すメモリディスクリプタのバイト数を表す。UEFIの実装によっては構造体が拡張されていたりしてByte数が異なる可能性があるため。
OUT UINT32 *DescriptorVersion // メモリディスクリプタの構造体のバージョン。
);
メモリ領域に書き込まれるデータの構造は、EFI_MEMORY_DESCRIPTOR構造体の配列になっている。
EFI_MEMORY_DESCRIPTOR配列は以下の構造
フィールド名 | 型 | 概要 |
---|---|---|
Type | UINT32 | メモリ領域の種別 |
PhysicalStart | EFI_PHYSICAL_ADDRESS | メモリ領域の先頭の物理メモリアドレス |
VirtualStart | EFI_VIRTUAL_ADDRESS | メモリ領域の先頭の仮想メモリアドレス |
NumberOfPages | UINT64 | メモリ領域の大きさ(4KiBページ単位) |
Attribute | UINT64 | メモリ領域が使える用途を示すbit集合 |
メモリマップはUefiMain()
でファイル保存する。
指定されたプログラムを実行すると、下のような情報が手に入る。
Memory Mapはファイルへ保存する。
その際にSaveMemoryMap()
で行う。
printはPrint(L"...", format)
を使っている。ここは通常のprintf文とは異なる。
AsciiPrintでそれぞれの要素をAsciiで出力する。
出力する要素は,itr num, Descriptor Type, GetMemoryType, 物理Startアドレス, Page数, Attribute&0xFFFFF
の順で並べている.
Buildすると,Loader.efiが作成される.
これを実行した後,mountし下にあるmemmapを除くと,Memory Mapの中身を確認できる.
ここら辺は指示通りに行えば問題ない.
ポインタに関しては基本なので省略.
感想
まだ何をやっているかわかっていない,という感じ.
EDK2を使っているのに,EDK2の全貌が見えない.
今後EDK2を理解できるようになるのか,それともそんなに使わないのかで,ここの理解度も変わってきそう.