ゼロからのOS自作入門で引っかかる人がいるかもしれないこと

こんにちは~
ゼロからのOS自作入門、通称みかん本?を読んでいるひとしか
このブログを見ていないとは思いますが。
私はまだ矩形描くあたりまでしか進んでません。頑張ります。

 

本が出るもーちょっと前から、UEFI起動の自作OSを作っています。MikanOSはまさにその参考となり、みかん本は私を導くマニュアルです。0から1(pdfから実装)は嫌いですが1から2(実装や誰かがまとめてくれたマニュアルから自分でアレンジしたりする)は得意目なのです。
はい。自分語りが過ぎました。そんなもののために来ているわけではないはずですので。

そんなこんなで見つけた、タイトルの"引っかかりそうな問題"を解説していきます。
その問題は、カーネル呼び出し時に引数をちゃんと受け取れない、というバグです。写経していては起きません。ここ大事です。

あくまでg++で実装してみた!みたいな人に起きる可能性のあるバグです。

 

注:ぶっちゃけMikanOSのコードを流用しているからと人の目につきやすいタイトルにしてます。必要な情報がなかった場合、本当にごめんなさい。

 

解決法を答えてしまうと、-mabi=sysvというオプションをつけようってことです。

 

はい。これだけです。これだけのためにgdgdとごめんなさい。どうしてもうまくまとまらなかったのです。

さて、理由を説明します。長いので、結論を知りたかった方は上を見て実行してください。


typedef void EntryPointType(UINT64, UINT64);

EntryPointType* entry_point = (EntryPointType*)entry_addr;

entry_point(gop->Mode->FrameBufferBase, gop->Mode->FrameBufferSize);

ここの部分でカーネルを呼び出して、

extern "C" void KernelMain(uint64_t frame_buffer_base,uint64_t frame_buffer_size) {

ここで引数を受け取っているのは理解している前提です。
なぜ?ってなった人は本を読み返しましょう。
しかし、qemuのinfoで確認すると、引数がおかしくなっていることがあります。具体的にわかる例としてはframe_buffer_baseを使っているのに描画ができていないなどでしょうか。

 

MikanOSでは、EDKII(UEFIで起動するブートローダーを作るのに使うもの)もカーネルもclangを使っています。(EDKIIのほうはConf/target.txtにCLANGって書いてあります。)
私の環境では、両方ともgccですが、片方でしか上のオプション(-mabi)を使っていませんでした。その結果、ABIがそれぞれで違い、うまく与えられたデータを扱えなかったわけです。
例えると、数字を求められているのに文字列を渡されたようなもの(?)です。
ABIのわかりやすい解説は、みかん本の101ページにあります)
みかん本ではSystem V AMD64 ABIを使っているので、そのABIに対応させているのが上のオプションです。


はい。全然うまく伝わっていない気がしますが、私の説明力の限界でした。脳内OCしてこれです。
こんなひどい文章ですが、最後まで読んでくださった方、ありがとうございます。

(このブログ1400文字以上あるんだなぁって)

UEFIアプリ作ろうとしたら苦戦しまくった話

自作OSを作る->ブートする必要がある->UEFIときた。
もともとはEDKIIを使うはずだったんだけど、なんとビルドが全くできない!
undefined 何とかっていわれちゃうんだよね

 

そんなわけで、gnu-efiを使うことになりました。

その中でもいろいろ苦戦したので備忘録的に。

 

まず環境設定

いれるパッケージは
qemu-system-x86 gnu-efi binutils-mingw-w64 gcc-mingw-w64

よくあるOVMFは今はいれません
ダウンロードしておきます(https://sourceforge.net/projects/edk2/files/OVMF/)

 

またisoやHDD用イメージを作るものも入れましたが
今回は特に記述しません。

 

ソースコードはネットの丸コピ

#include <efi.h>
#include <efilib.h>

EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  EFI_STATUS Status;
  EFI_INPUT_KEY Key;

  ST = SystemTable;

  Status = ST->ConOut->OutputString(ST->ConOut, L"Hello     World\r\n");
  if (EFI_ERROR(Status))
  return Status;

  Status = ST->ConIn->Reset(ST->ConIn, FALSE);
  if (EFI_ERROR(Status))
  return Status;

  return Status;
}

ソースコードMarkdownの都合上丸コピできませんでした

そしたらビルドするのですが
data.cというgnu-efiのソースが必要らしいです
しかし、私の場合検索しても見当たらない!
さてどうするか...
githubから落としてきちゃいました!(https://github.com/vathpela/gnu-efi)

ビルド失敗!えぇ...
参考文献によると
LibStubUnicodeInterface構造体の中をすべてNULLにします
とのこと
その通りにするとビルド、リンクが通りました!

そのファイルをFATでフォーマットされた中の
EFI/BOOT/BOOTX64.EFIにします

 

さて最後にqemuでテスト
オプションはこんな感じ
-bios OVMF.fd -device usb-ehci,id=usb,bus=pci.0,addr=0x4 -drive id=boot_usb,file=リンクしてできたimg,format=raw,if=none -device usb-storage,drive=boot_usb

qemuのUSBストレージに関する情報がなかなかなかったので書いておきます。

無事Hello Worldが出たので完成。
長かった。

次回はグラフィック処理かな。

P.S.
グラフィック処理でリンクが全くできず、情報もなく諦めました。

参考文献:

wiki.osdev.org

自作OSで時間を使いたい

この記事は 自作OS Advent Calendar 2020 の3日目です。
Advent Calendar初めてですがよろしくお願いします。 

なぜ今RTCなのか

現在時刻を取る方法として、UEFIとかそういうのを今は使うのでしょうか
私は最新、今時な方法がとても危ういため、最もわかりやすいであろうレガシーなRTCを使っていきます。せっかくだし誰か今どきな方法教えて

早速使ってみよう

 まず割り込み不許可の状態で、初期化を行います

io_out8(0x70, 0x0b); // Status Register Aを初期化する NMIを無効化
char prev = io_in8(0x71) | 0x10; // IRQ8に割り込ませるための設定っぽい?
io_out8(0x71, prev);


RTCの割り込みは8番です
(今回の例ははりぼて準拠なので28番です)

set_gatedesc(idt + 0x28, (int)asm_inthandler28, 2 * 8, AR_INTGATE);

 

 そうすると1秒ごとに割り込みが来るようになります
ここで一つ注意があります
割り込みの最後にRTCにデータを送ったりしなくてはいけません

 

io_out8(0x70, 0x0c);
io_in8(0x71);

 
こうしないと割り込みが再度行われないらしいです

さて
時刻が変わったとのことなので時刻を取って表示してみましょう!

初めに時刻がもうすぐ更新されないか調べます

io_out8(0x70, 0x0a);
if(io_in8(0x71) & 0x80) == 0)

これで1(true)になったら更新はしばらく来ないのでデータを読み取っていきます

時刻の取り方はいたってシンプル(?)

io_out8(0x70, addr);
int data = io_in8(0x71);

これだけなのですがaddrにはとりたいデータを指定します
0x00: 秒 0x02:分 0x04:時
0x07:日 0x08:月 0x09:年 下2桁 0x32:年 上2桁

昔のハードウェアっぽい付け足し感が垣間見えますね(笑)

これで終わりです!お疲れ様でした!


最後に 

私が作ったOSを少し宣伝させてください
はりぼてOSを改造したOSになっています
上で上げたRTCを使う実装が組み込んでありますので
参考にしてみてください!

github.com


ありがとうございました!

OS自作を始める

こんにちは~

HonokaNoと申します。

もともとOS自作をしています。


このブログはOS自作についての備忘録として書いています。
目指しているOSは、
・32bit/64bit環境対応

・インターネット接続可能

・高度なグラフィック

・USBデバイス(最終的にはゲームのコントローラなど)

とかなり高度なものを目指しています

 

流石にいきなりそこまでたどり着くのは不可能なので、まずは
ブート -> グラフィック
ここまでを目指して進んでいます。

 

現在はC標準ライブラリを作成しています。

なぜなら、自作OS環境ではprintfやscanfなどの関数が
全く使えないからです。

そのため、OSに依存しないsprintfやisdigitを
作成することにしました。

初めてですし特に書くこともないのでここまで。