note.nikachu.net

OS作(ろうとす)る #1

2024-02-11T20:00:00+09:00
link title link+title API link

目的

ゼロからのOS自作入門 を読みながら、UEFI上でHello, world!を表示する。

まずは機械語でHello, world!

機械語を書く

本を読んでいくと、まずはバイナリエディタを用いて機械語を書くとのことだったので、Okteta を用いてバイナリを書いていく。

お怒りのようです

お怒りのようです

大量に行があるのでどこかわからなくなるのが頻繁に起きた。
書き終わったのでsumコマンドを用いてチェックサムが一致するかを調べたが、同じにならない。

どこを間違えたのかと思ったら、1行抜けていたり、見間違えていたりした。
何回か試して直すを繰り返し、やっとチェックサムが一致した。

書いた機械語は以下に示す。

 10000000 4d 5a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >MZ..............<
 20000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
 3*
 40000060 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 >................<
 50000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
 6*
 70000200 50 45 00 00 64 86 02 00 00 00 00 00 00 00 00 00 >PE..d...........<
 80000220 00 00 00 00 f0 00 22 02 0b 02 00 00 00 02 00 00 >......".........<
 90000240 00 02 00 00 00 00 00 00 00 10 00 00 00 10 00 00 >................<
100000260 00 00 00 40 01 00 00 00 00 10 00 00 00 02 00 00 >...@............<
110000300 00 00 00 00 00 00 00 00 06 00 00 00 00 00 00 00 >................<
120000320 00 30 00 00 00 02 00 00 00 00 00 00 0a 00 60 81 >.0............`.<
130000340 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 >................<
14*
150000400 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 >................<
160000420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
17*
180000600 00 00 00 00 00 00 00 00 2e 74 65 78 74 00 00 00 >.........text...<
190000620 14 00 00 00 00 10 00 00 00 02 00 00 00 02 00 00 >................<
200000640 00 00 00 00 00 00 00 00 00 00 00 00 20 00 50 60 >............ .P`<
210000660 2e 72 64 61 74 61 00 00 1c 00 00 00 00 20 00 00 >.rdata....... ..<
220000700 00 02 00 00 00 04 00 00 00 00 00 00 00 00 00 00 >................<
230000720 00 00 00 00 40 00 50 40 00 00 00 00 00 00 00 00 >[email protected]@........<
240000740 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
25*
260001000 48 83 ec 28 48 8b 4a 40 48 8d 15 f1 0f 00 00 ff >H..(H.J@H.......<
270001020 51 08 eb fe 00 00 00 00 00 00 00 00 00 00 00 00 >Q...............<
280001040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
29*
300002000 48 00 65 00 6c 00 6c 00 6f 00 2c 00 20 00 77 00 >H.e.l.l.o.,. .w.<
310002020 6f 00 72 00 6c 00 64 00 21 00 00 00 00 00 00 00 >o.r.l.d.!.......<
320002040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
33*
340003000

0x2000番地以降に文字列のデータがあることぐらいしかわからない。

USBメモリにコピーして起動

USBメモリに efi/boot/ フォルダを作り、そこに作ったバイナリデータをBOOTX64.EFIという名前で保存する。
そのUSBメモリからブートすればHello, World!が表示される。
USBメモリをサブPCに刺し、起動してブートメニューを開く。しかし表示されない。
サブPCは4000円で買ったMac Proなのだが、Apple製品は普通じゃないので他のコンピュータで試してみることにした。

Mac Pro 2010
Mac Pro 2010

家に転がっているCore 2 Duo(Centrino2)のPCに刺して起動したが、やはり起動しない。
ちょうど飯の時間だったので飯を食いながら考えていたが、UEFIのコンピュータではなくBIOSのコンピュータであることに気づいた。

編集した後すぐに試せなくなるので、めんどくさかったがUEFIに対応しているメインコンピュータで、再起動してUSBメモリから起動してみた。
今度はしっかり起動し、以下のようになった。

機械語でHello, world!
機械語でHello, world!

バイナリを変えて文字列を変える

また、バイナリをいじり、少し長い文字列を表示しようとした。機械語は読めないので適当に長くしたら、画面がまずいことになった。
多分読み取るバイト数の指定がどこかにあるのだろうが、めんどくさいので後にする。

まずくなった画面は以下に示す。

image3_bug.png

また、UEFIが日本語に対応していることもわかった。

とりあえず遊んでないで次へ進む。

C言語でHello, world!

ソースコード

解説が少ないのでよくわからなかったが、以下のコードをC言語で書き、ビルドすることでHello, world!を表示することができる。

 1typedef unsigned short CHAR16;
 2typedef unsigned long long EFI_STATUS;
 3typedef void *EFI_HANDLE;
 4
 5struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
 6typedef EFI_STATUS (*EFI_TEXT_STRING)(
 7  struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *This,
 8  CHAR16                                   *String);
 9
10typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
11  void             *dummy;
12  EFI_TEXT_STRING  OutputString;
13} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
14
15typedef struct {
16  char                             dummy[52];
17  EFI_HANDLE                       ConsoleOutHandle;
18  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL  *ConOut;
19} EFI_SYSTEM_TABLE;
20
21EFI_STATUS EfiMain(EFI_HANDLE        ImageHandle,
22                   EFI_SYSTEM_TABLE  *SystemTable) {
23  SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello, world!\n");
24  while (1);
25  return 0;
26}

C言語なのにメンバ関数が存在しているのがよくわからないが、このコードでも同じようにHello, world!を表示することができた。

結果

C言語を用いた文字の出力

C言語を用いた文字の出力

\nはよく改行コードとして用いられているが、本来はLine Feed(次の行に送る)という意味であるため、行頭が戻っていない。行頭を戻すためには\r (Carriage Return)を追加する必要がある。
薄々知ってはいたが、ここでその違いを目にするとは思っていなかった。

また、QEMUを用いることで再起動しなくてもコンピュータ上で試せるようになった。

C言語とライブラリを用いてHello, world!

EDK II というライブラリを用いて、Hello, world!を短いコードで作る。

ソースコード

 1#include  <Uefi.h>
 2#include  <Library/UefiLib.h>
 3
 4EFI_STATUS EFIAPI UefiMain(
 5    EFI_HANDLE image_handle,
 6    EFI_SYSTEM_TABLE *system_table) {
 7  Print(L"Hello, Mikan World!\n");
 8  while (1);
 9  return EFI_SUCCESS;
10}

結果

C言語とEDK IIのライブラリでHello, world!

C言語とEDK IIのライブラリでHello, world!

現在と今後

現在は、メモリマップの取得をし、ファイル保存をすることまで行えている。

C言語とEDK IIのライブラリでHello, world!

C言語とEDK IIのライブラリでHello, world!

メモリマップのファイル保存

メモリマップのファイル保存