システムメモリマップ取得、ページング、マルチタスク — つぎはぎOSの方針

とりあえず、「つぎはぎOS」はページングで仮想記憶を実現した上で、マルチタスクOSを移植することにした。

以前挫折したページングに再度挑戦しようとして調べていたら、リアルモードのステップローダーで、ACPI仕様の拡張BIOSでシステムメモリマップを取得する必要があることが分かった。その理由は、i686のRAMは最大4G-byteなのだが、その全てが使えるわけではないからだ。ハードウェアから作成するような組み込みシステムだと、固定情報として内部に持てばよいが、パソコンは実際のRAMのサイズは各マシンで個別だし、BIOS領域やDMA領域、VRAM領域があって、そこは使えない。そういった個別のマシン情報をBIOSから取得してテーブルマップのようなものを内部で作成する必要がある。動的メモリ割り当てのmalloc()とかも、そういった情報を基にRAMの領域を割り当てているらしい。拡張BIOS機能の0xE820のINT 0x15というシステムメモリマップ取得で、ループで情報を読み出し、BOOT_INFOにそのまま格納して、ステップローダーからブートモニターへ渡すようにした。実際のシステムメモリマップ生成と参照は、ブートモニターの初期化処理で行った。新しくコマンドを作成し、BOOT_INFOの内容を画面へ表示させるようにした。システムメモリマップのエントリー情報は20バイトのサイズだったので、VirtualBoxのACPIは3.0より前の仕様のようだ。これで実メモリのどこを使ってよいか、利用可能なRAMサイズがどれくらいかが明確になった。
余談だが、Windows用のVirtualBoxは利用しない方が良い。というのは、テストのためにWindows10へVirtualBoxをインストールしたら、VMwareのネットワーク機能と競合して、VMwareの動作がおかしくなった。アンインストールも簡単ではない、ネットで検索すれば分かるが、レジストリや隠しファイルのようなものがそこかしこに残っていて、削除が面倒だ。Oracleがわざとやっているのか、フリーソフトのため手が回らないかのどちらかだろう。

このシステムメモリマップは、malloc()などの動的メモリ管理にも必要な情報であり、ページングのPDE/PTEの作成でも、この情報を基に物理アドレスの上位10bitと続きの中位10bitを設定することになる。下位12bitは実行プログラムでのオフセットを使ってアクセスするらしい。32bitモードでの仮想メモリは4Gbyteのリニアアドレスなのだが、実メモリは1Gbyteしかなかったりすることは普通にあるわけで、実メモリと仮想メモリの対応付けをするテーブル情報をPDE/PTEで持つわけだ。仮想メモリのどこに実メモリを割り付けるか、スワップするのかという設定もこのテーブル情報で行う。
はっきり言って、ディスクへのスワップ機能がないなら、実メモリをセグメント分割してアプリケーションへ割り当てた方が簡単だが、将来的な拡張を考えて、ページングを実装することにした。実メモリを割り付けない領域にアクセスしたら、ページフォールトが発生することになる。常識的に考えれば、OSのプログラムをディスクへスワップさせてはならないのだから、スワップする領域はアプリケーションに割り当てることになる。現状、ディスクへのスワップ機能を実装しないので、実メモリ=仮想メモリという対応付けとなる。だから、仮想メモリ4GBのどの領域をOSが使って、アプリケーションにどの領域を割り当てるかという計画的な配分を考えなければならない。
ちょっと頭を悩ませたのが、PDEとPTEのデータ形式だ。資料では4-byteのフラグビットとアドレスの簡便な形式なのだが、メモリ上に作成しなければなない。知っての通り、x86はリトルエンディアンで、メモリ上にもリトルエンディアンで作成しなければならないのか、ビッグエンディアンで作成しなければならないのか、資料では0-bitから31-bitまでの意味付けしか書いてなくて迷った。結論から言うと、リトルエンディアン形式でメモリ上に作成するのが正解だった。そういうものだと受け入れるしかないのだろうが、自分は生理的にビッグエンディアンの方が精神衛生上、好ましい。

ページング機能を実装して思ったのは、ディスクへのスワップ機能がなければ、不要な機能だということだ。仮想メモリは、OSやタスク、プロセスを仮想的なメモリ配置へ再編するために、OSのアドレッシングが物理アドレスと違うため、リンクファイルでアドレス設定を工夫しなければならなくなる。全体的にシステムが複雑化して、デバッグが難しくなるというデメリットが大きい。(あるサイトでは、にわたま問題—-鶏が先か、卵が先か—-と書いてあった。それくらい悩ましい問題らしい)
それに、PDEの設定にはU/S-bit(user-privilegeとsupervisor-privilege)があって、つまり、supervisor-privilegeのPDEで指定した4M-byte分のPTEの仮想メモリは、ユーザーアプリケーションでアクセスできない領域になるわけで、結局、PTEテーブル一つ分の4M-byte単位でOS領域とユーザーアプリケーション領域を考えて配置することになり、柔軟性が全くない。それなら実メモリをGDT/LDTでセグメントで配分する方が簡単に思える。PTE毎にもU/S-bitはあるのだが、PDEレベルで設定された時は無視されるのだろうか?それなら、PDEにU/S-bitは必要ない。整合性を考えると不思議な仕様だ。それとも私の理解不足か。
ディスクへのスワップでメモリ不足を気にしなくても良いなら、その見返りはあるかもしれないが、HDDなどのディスク装置へのスワップは遅すぎて、RAMを増設した方が、ずっと効率的で費用対効果が高い。SSDの速度ならスワップも気にならないのだが、SSDでないなら、実記憶のまま、注意深く自分でメモリ配置をした方が、解りやすくて処理速度も早くて、絶対的に良い(と思う)。今回、BIOSで取得したシステムメモリマップを見ても、BIOSの利用領域などがあって、自由に使えるメモリ領域は途中で分断されていて、リニアに使えない。だから、仮想メモリに物理マップをマッピングする時も、OSやタスクでアクセスできない領域を避けるように考慮してマッピングする必要があり、それなら実メモリのまま、使えない領域を避ければ良いだけで、何のために仮想メモリという機能があるのか、どんな利便性があるのか分からなくなる。今回は勉強と将来の拡張(スワップ機能の実装)のために、ページングだけ実装して、見かけ上、今までと違和感なく動作させることができた。

マルチタスクには、T-Kernel2.0を採用することにした。理由はフリーで、日本語ドキュメントがきちんと整備されていること、ミドルウェアでTCP/IPのモジュールやFatFsと同程度のファイルシステムのモジュールが、フリーで提供されていることが理由だ。
詳しいことは分からないが、μT-Kernel仕様というのが、IEEEで採用され、国際標準になっていることも考慮した。Linuxは普通に動いて、皆が使っているし、自分で何かしようにも英語情報ばかりでは、自分でできることはほとんどない。T-KernelはARM CPUをターゲットにしているので、ハードウェア関連の初期化関数などを用意すれば、使えるのではないかと思っていた、、、、

しかし、その考えは甘かった。おそらく東京大学の頭のいい人が作成したのだろうが、スパゲッティプログラムではないが、システム合理的に最高性能を出すために最適化されているために、普通の人間が理解するには、既に組込みシステムやマルチタスクの経験豊富な人であれば別だが、余りにも複雑怪奇すぎて、勉強用の教材には向かない。FatFsを移植する時は、自作すべき関数の名称や機能が明確になっていて、何をしていいのか分からないということはなかった。改めてFatFsの出来の良さが分かった。
T-Kernel2.0は、特にMakefileの構造が複雑で、Perlスクリプトまで使った超絶技巧を用いてmakeしている。私はOSを勉強して移植したいだけであって、makeやPerlの超難度テクニックの習得を前提とされると、肝心のOSの内容にまで辿り着くことができない。頭のいい人の罪のない欠点だが、自分が理解できることは、普通の頭しか持たない人間でも同じように理解できるのだという単純な思い込みがあると思う。こんな複雑だと、全体構造をある程度は理解できないと、移植して再利用などできはしない。しばらくは解析をしようとおもうが、別のマルチタスクOSを探すことになるかもしれない。

(2023/2/4 追記)T-Kernel2.0のソースを解析していくと、T-Kernel2.0はARMコアの機能と仕様に強く依存していて、また、市場に出回っていない特殊なボード仕様にも依存していて、移植性がなかった。一応、ソースプログラム内でハードウェア依存部とかを切り分けてはいるが、プログラムのロジック全体が、ARM独自のアセンブラ命令や機能でないと実現できないプログラミング(至るところにARMのインラインアセンブラが埋め込まれていた)になっており、他のCPUに移植する場合、ARMのアセンブラや機能を把握できてないと移植作業もできない、、、、、というか、教材にもならないし、実用性もないOSだと分かった。
MakefileやPerlスクリプトも複雑で、自分の開発環境用に修正するのも容易ではない。FatFsは移植部分をdiskio.cというファイルで基本ロジックと機能の外形を提供していて、そこだけ理解してしまうと、実質的に数時間で移植できた。
μT-Kernelのソースも見てみたが、T-Kernel2.0と作りが同じで、ARM依存が強く、移植できそうにない。実際、STM32とかルネサスとかARM系(?)の4種類の開発環境と移植例しかなく、FreeRTOSのようにx86を含めた数十種類もの移植例はない。宣伝用のデモにでもVMwareなどの仮想マシン環境上で動作するサンプルを提供しても良さそうなものだが、開発元であっても、それが容易ではないくらい移植が難しいのだろう。
FreeRTOSは英語が基本だし、Amazonに買収されていて、情報を検索すると強制的にAWS関係の広告へ誘導されてしまう。つぎはぎOSの拡張のためにはマルチタスク化は避けて通れないが、他に適当なOSSが見つからない。ラウンドロビン方式でのリアルタイム性のない簡単なマルチタスクだけ自作してみるか、、、、、困った、、、、、

カテゴリー: Linux, VirtualBox, つぎはぎOS, 自作OS パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です