2021年4月7日水曜日

ゼロから作るOS自作入門3日目番外編:きれいな模様セルフコンテスト

永遠に時間が潰せる、と思った。 

平日は大体仕事してるので、というかまぁ忙しいので定時じゃ上がれないわけですね。

でもOS作りたいなって思ってるんだけどガッツリはできないからその代わりに遊んでる。

シンプルに

彩度をいじる



れいんぼー


もっとれいんぼー




もやもや
X軸:明度をへらす
Y軸:彩度をへらす



WindowsとかのGUIプログラミングではあんまりこういうのやったこと無いし、
正直できる気がしない。

ベアメタルのプログラミングでならメモリにカラーコード書き込むだけでできて直感的なので割とこういう事が簡単にできて良いよね。

複雑な図形をかけって言われると微妙だけどね。

箸休め終わり。


本をゆるーく進めて、何か得るものがあって、まだ情報が出てなさそうなものは書いていくスタンスにしよう。

本を読んで、毎日書きましょう だと続かない人間だし。

2021年4月5日月曜日

ゼロからのOS自作入門をRustで書いていく3章~UEFIライブラリがしんどい件について

最新のリポジトリはこちら。(作業完了時のコミット→Day3のコミット


 マジでこの苦しみを分かち合いたい。

この辺の人達もだいたい同じところで苦戦してる。

【ゼロからのOS自作入門】MikanOSをRustに移植する 1章・2章

MikanOSをRustでやってますが、しんどい。

Rustの人たち3人よれば文殊の知恵になったらいいな。
3人目の俺がポンコツなのでならないかもしれないけど。

というわけでさらなる4人目のRust使いがこのあたりしんどい・・・ってなったときの道標として↑の記事読んでも詰まった部分を書いていく。

何度も言うけど、UEFIライブラリ(uefi-rs)で詰まった。

詰まりどころじゃない部分のソースもgithubに載せておくので、コピペして使ってOK

3章(3日目)は1~2日目とは違って、カーネルファイルをロードするというそれっぽいことをします。が、Rust使いには茨の道だったという話を書いていくつもり。

ファイル読み込みは苦行

事前に言っておくと、uefi-rsを使う以上、カーネル側のkernel_main関数もEFI_API呼び出し規約で合わせて置かないと、うまくカーネル側で受け取れないので結構な時間ハマることになる。普通にハマった。呼び出し規約については「MikanOSをRustでやってますが、しんどい。」の記事に書いてあるので省略する。


みかん本でもUEFIのファイル開くところは深く触れられてないので、正直ここを理解しつつ移植するのは骨が折れた。
ファイル読み込み関数(open_file)でやっていること
このあたりはUEFI規格書に書いてあるが、ライブラリのほうと整合させるのに苦労した。簡潔すぎてドキュメントの読み方がわからん。
  1. LoadedImage ProtocolをBootServicesのhandle_protocolメソッドで取得する
  2. 取得したLoadedImage Protocolのインスタンスのdeviceメソッドを叩くとデバイスオブジェクトが取得できる(どのデバイスを開くか)
  3. SimpleFileSystem Protocolの引数に2で取得したデバイスオブジェクトを引数にすると、ファイルシステムが開ける
  4. SimpleFileSystemオブジェクトのopen_volumeを叩くとディレクトリオブジェクトが取れる
  5. ディレクトリオブジェクトを使って「ファイルハンドル」オブジェクトを取得する
    1. なお、ここで取得している「ファイルハンドル」はファイルだけでなく「ディレクトリ」である可能性もあるので本当はオブジェクトの種別をちゃんとチェックしないといけない。現状は決め打ちでやっている。
  6. ファイルオブジェクトをRegularFileオブジェクトに変換する
  7. RegularFileオブジェクトを返却する
というのが、open_file関数でやっていること。
かつ、その上位にあるFileReaderWriterはRegularFileオブジェクトをラップするオブジェクトになっている。

殆どは、RegularFileオブジェクトに存在するメソッドを叩いているだけだが、ファイルサイズ取得メソッド(get_size)だけは少し毛色が違うので大きめになっている
具体的にやっていること
  1. get_infoメソッドを使い、FileInfoを取得する。(公式ドキュメントがわかりづらすぎる件。)
    1. このメソッドは、確保しているバッファが少ないと、失敗したときにerrorオブジェクト内に必要なバッファサイズを返却するという仕様。
    2. とりあえず動的にバッファを確保してFileInfoをしまうバッファを作った。
      1. そして書いてる途中に気づいたけど、確保したメモリを開放してないからメモリリークしてる。だめじゃん
  2. 取得したFileInfoオブジェクトのfile_sizeメソッドを呼び出してファイルサイズを取得している。

これでようやく、カーネルをロードできるようになった。

あとは「MikanOSをRustでやってますが、しんどい。」の記事に習って、ロードするだけ。

で、色々やりたいことをやればよろしい。

UEFIで動くHSV色空間からRGBに変換する部品は2年くらい前に作ってあったので、それを動かしてみた。

モジュール分割してみる

とりあえずローダとカーネルでファイルが分かれているので分割したい。
でも分割するのはファイルだけで、共通部分は共通で使いたい。
なので以下の分割方針を取ることにした
  • ブートローダ:バイナリクレート
  • カーネル:バイナリクレート
  • その他共通部品:ライブラリクレート
    • アセンブラ関数やフレームバッファと言ったブートローダやカーネルで共通に使うものを入れておくライブラリ
というわけで方針が決まったのでざっと分割すると今のリポジトリみたいな感じになる。

苦行だけど、できると楽しい。
神書籍だと思う。

おまけ

ライブラリクレートは、バイナリクレート経由でビルドされることによって、バイナリクレート側のビルド設定ファイルが適用されてビルドされる。
ただし、ビルドスクリプトはライブラリクレート固有のものになる。

つまりこういう事
ビルド設定:バイナリクレートの設定(build-stdなどのライブラリ設定)が継承される
ビルドスクリプト:ライブラリクレートのものが使われる

ライブラリクレートはUEFI側とカーネル側、つまるところ、PEファイルとELFファイル両方にリンクできる形式でビルドされなければならない。
とりあえず、PEファイルELFファイルに対してコンパイラとリンカを個別に使って解決することにした。

ゼロからのOS自作入門をRustに書き換えながら作っていく1章~2章

ゼロからOSを作る本(通称:みかん本)、某30日本のモダンOS版ですね。

day3はこちら

なんとなくPDF版を買いました。

余剰のモニター使えば顔上げたまま読めるし^Fの検索も効くので。

とりあえずRustでやるからには環境を整えないといけない。
Day1はバイナリ打ち込もうぜ。っていう話でPEバイナリをひたすらバイナリエディタで作るだけなのでただやるだけ。ひたすらにやるだけ。なので記事は書いてない。

ビルドについて

Rustのデフォルトビルドコマンドである、 cargo build コマンドでビルドができるようにしたので、この界隈でよく使われるxargoとかxbuildは使っていない。
Rustでやるならここらはしっかりこだわりたい。
Makefileとか使わなくてええんやで。という強い推しをしていきたいんだけど
それ以外の部分がだいぶ苦行だからちょっと推せない気がしてきてる。


ちょっと早いけど、こちらがリポジトリ(Day2終了時点のコミット)

最新のリポジトリ本体

  1. 環境構築(WSL2)
    1. qemu-system-x86_64のインストール
    2. ovmf.fdを導入(みかん本では、ovmf_code.fd ovmf_vars.fdを使っているが、特に分ける理由もないので、ovmf.fdを使っていく)
  2. X-Serverのインストール(これはみかん本の最後の方に書いてあった)
  3. WSL2にRust(nightly版の最新)をインストールする
これが終わってようやく開発が始められる。
というわけで続き。

C++ではEDK-IIですが、Rustではuefi-rsを使って、ブートローダを書きます。
みかん本通りに進めているなら自然とEDK-IIは使えているわけですが
いかんせんこのuefi-rsはみかん本のスコープ外なので自力で調べる必要があります。
ここが難所です。マジわかりにくいのなんの。
大体コード書く時間を1割とすると、ライブラリを調べる時間とデバッグする時間が9割くらい。

とはいえ、Day2はDay3に比べるとそんなに分かりにくいライブラリは使わずに終えたのでウォーミングアップとしてはそれなり。
でも難しいものは難しいので勘所を書いておこうかと。
特にファイル入出力あたりの書き方が分からなさすぎて辛い。

なので、ファイル入出力のサンプルコードとして、リポジトリの当該コードにリンクを貼っておく。

で、確かDay2の目的はとりあえずメモリマップを吐ければOKだったので、吐いてみた。

とりあえず、吐けたのでDay2は完了
ただ、たまによくわからないバイナリがボコッと入ってくるのはなんでだろう。
多分メモリ上のゴミだと思うんだけど、原因不明なので類似事象が発生した方の報告まち。

Day2はおわり。