3 日で作る OS の断片

こちら 自作 OS Advent Calendar 2014 の 21 日目の記事です.

ハードウェアにいくつかの適当な仮定をおいて簡単な OS の断片(以下,OScrap (おぉスクラップ)と呼びます)を作りました.コンセプトもぼんやりしておりますが,とりあえず OScrap はサーバ用途 x86 OS です.アプリケーション側にはメモリ管理とネットワーク送受信の API だけを提供します.OScrap はアプリケーション含めシングルアドレス空間,シングル CPU モード (Ring 0) で,完全にポーリングベースで動作し,NIC はごく一部の高性能なもの 10GbE, 40GbE だけを仮定して VMDq などの NIC 側の多重化機能を前提にしてたくさんあるコアがあまり協調せず並列動作することを考えています.今後,OScrap 上に何らかのサーバアプリケーションを実装して遊ぶ予定です(試しに In-memory database とか.).今のところ KVM 上と実機(Xeon E3-1241 / 16GB) で動作確認をしております.

目次

特徴

以下,現時点での OScrap の特徴について説明します.

  • 特徴 1) ローカルディスクなんてなかった.

PXE/iPXE での起動を前提にします.BIOS 環境でローカルディスクから起動すると通常,一番最初のコードは MBR 512 バイトに制限されますが, PXE/iPXE だと 512 バイトより多く読み込んでくれるので(少なくとも 480 KiB ぐらいはいいのかな?),いきなり OScrap カーネル本体がネットワーク越しに起動します.よって,OScrap には,一般的な OS のブートローダでよくある INT13h でカーネルを段階的に読み込むフェーズはありません.

  • 特徴 2) 32-bit Protected Mode なんてなかった.

OScrap は起動すると Real-mode から大して何も確かめず一氣に Long mode へ入ります.

  • 特徴 3) 例外・割り込みなんてなかった.

OScrap の IDT はからっぽです.NMI はごめんなさい.デバイスはすべてポーリングで処理する氣です.

  • 特徴 4) ページサイズとは 1 GB だった.

1 GB ページング前提で動作し,起動時に 12 KiB のページテーブルを構築し 512 GB のメモリ領域を恒等写像でマップします.また,MMIO 用途として,仮想アドレス 512 + X GB は,物理アドレス X GB へキャッシュしない設定でマップします.ページフォルトなんてなかった.

  • 特徴 5) APIC なんて最初から x2APIC だった.

x2APIC 前提で IPI 周りの処理をします.

  • 特徴 6) ネットワークデバイスは Intel x540 10GbE しかなかった.

Intel x540 10GbE のドライバだけを持っています.VMDq サポート前提で VMDq 有効化し,64 個ペアの送受信インターフェースを提供します.(将来的には 40GbE のドライバを持つ予定です.)

  • 特徴 7) 外部へのインターフェースはネットワークしかなかった.

デバッグ用にシリアル出力しますが,あくまでデバッグ用のつもりです.必要なものはネットワークで受け渡しすればいいというつもりです.

実装状況

  • 現状,OScrap はメモリ管理とネットワーク送受信(L2)の API を持っているだけです.今後,main.c/main(), init.c/init_ap() 以下に処理を書き加えて何か役に立ちそうなアプリケーションを作ろうと思います.
  • メモリ管理は liballoc を利用させて頂きました.また,実はページのアロケーションが適当で空いたページを解放しません(コード参照).
  • バグバグしているかもしれません.

ソースコードと使い方

コードは こちら になります(いずれはレポジトリへ).KVM 上で実行するにはダウンロードしたものを展開して make run するだけです.前述の通り,CPU が 1GB ページング,x2APIC などに対応していないとちゃんと動作しません.ちなみに KVM 上では Intel X540 をパススルーにしないと OScrap はネットワーク通信できません.

KVM 上での実行結果は以下のようになります.現在デフォルトの OScrap アプリケーションは 3 秒数えて終了します.

OScrap を実機で動作させたい場合は,OScrap をネットワークブートさせます.そこでサーバ側でまず PXE/iPXE の設定を行ないます.

はじめに PXE のための DHCP の設定をします.ファイル “undionly.kpxe” を PXE ブートするように設定します.よくある BOOTP の設定です.

次に PXE のための TFTP の設定をします.よくある TFTP の設定です.

続いて iPXE の準備です.

最後に OScrap のバイナリを TFTP ディレクトリへ.

以上,準備ができたら OScrap を動作させる実機を TFTP/DHCP サーバとネットワーク的につないだ状態で再起動します.これで実機上で OS が実行されます.

x540 10GbE 搭載実機上で Debug 出力を全部有効にして実行すると以下のようになります.

ソースファイルの説明

  • acpi.{ch} : ACPI テーブルを見つけてコアの数を数えたり,タイマーを見つけたりします.
  • alloc.{ch} : liballoc を使います.
  • apic.{ch} : x2APIC で IPI を飛ばして AP を起動させるコードです.
  • init.{ch} : 各種初期化処理を順番に呼び出すコードです.
  • kvi.ld : 0x7c00 から実行されるバイナリを生成するリンカスクリプトです.
  • loader.S : 最初に実行されるアセンブラのコードです.OScrap の IDT, GDT の設定,ページングの設定,CPU モード遷移はここで完結します.
  • main.c : アプリケーションの始まりとなる関数 main() が入っています.
  • Makefile : OScrap のコンパイルや,QEMU/KVM 上での実行のためのコマンドが入っています.
  • page.{ch} : ページを割当・解放するコードです.(解放は実は TODO.)
  • printf.{ch} : printf です.
  • putchar.{ch} : シリアルポートから文字をデバッグ用に出力します.
  • timer.{ch} : デバイスを初期化する際の sleep を実装するためのタイマーの実装が入っています.HPET を使います.
  • drivers/hpet.{ch} : HPET を初期化して使うコードです.割り込みは設定せずに,ただのカウンタとして使います.
  • drivers/ixgbe.{ch} : Intel X540 10GbE Controller を初期化します.VMDq を有効化し,64 個の送受信機能を有効化します.
  • drivers/pci.{ch} : PCI デバイスをスキャンするコードです.
  • drivers/pmt.{ch} : ACPI Power Management を使うコードです.(結局,未使用)
  • include/asm.h : C 言語からアセンブラ命令を呼ぶ必要がある時に使います.IO 命令や RDMSR, WRMSR などのインラインアセンブラです.
  • include/common.h : よく使うヘッダファイルを束ねています.
  • include/lock.h : ロックの処理です.
  • include/msr.h : MSR の番号のマクロです.
  • include/panic.h : panic 用関数ですが,ただ busy ループに突入するだけのスタブです.
  • include/string.h : 文字列操作系関数です.(簡易実装)
  • include/types.h : OScrap 全体で使われる型の定義です.
  • include/mmio.h : MMIO のための関数です.(512GB + X へアクセスするだけ.)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">