Skip to content
Takym edited this page Jan 10, 2020 · 42 revisions

自作OSの知識はまだまだ浅いです。今はOS開発用のIDEを開発しています。 Takymは 「タキム」 では無く 「たかやま」 と読みます。

目次


リンク


OSに関係のあるプロジェクト

名前 プロジェクト ページ 説明 備考/状態
OSDeveloper GitHub OSの開発ができるIDEになる予定です。 開発中 (サボり中)
Takym/osdev-jp.github.io GitHub osdev.jpのウェブサイトを個人的に改造しています。リポジトリはosdev-jp/osdev-jp.github.ioをforkして作りました。 開発継続中
syswiki GitHub 自分で集めた低レイヤに関する情報を保存する予定です。 準備中

メモ

低レイヤに関する自分用のメモです。Slack等で流れた会話を自分なりに要約しています。間違い等がありましたら、教えてください。

  • このメモで特に指定が無ければ、CPUはx86_32かx86_64を指します。

EDK II (vUDK2018) on Windows 10

Windows 10 (1709 ビルド 16299.1087) での EDK II (vUDK2018) の自分の環境では上手くできたインストール方法です。

  1. vUDK2018 からツールキットをダウンロードする。
  2. NASM をインストールする。(インストール先のパスは空白を含めると上手く読み込めなくなる)
    • 例: C:\nasm\
  3. 環境変数の NASM_PREFIX と PATH に NASM のインストール先のディレクトリを追加する。
  4. Microsoft Visual Studio 2017 の「C++ によるデスクトップ開発」をインストールする。
  5. Cygwin か MinGW をインストールする? (必要かどうかは試していません。)
  6. ダウンロードしておいたツールキットを適当なディレクトリに配置する。
    • ここでは便宜的に %WORKSPACE% 呼ぶ。
  7. %WORKSPACE%\BaseTools\Bin\Win32 内に edk2-BaseTools-win32 からダウンロードしてきたツールを入れる。
  8. edksetup.bat を実行。
  9. %WORKSPACE%\Conf\tools_def.txt から /WX を全て削除。
  10. %WORKSPACE%\Conf\target.txtTOOL_CHAIN_TAGVS2017 に変更する。
  11. build してテストする。

巨大なコードの読み方


GDTのGビット

  • GDTのG-bitフラグが立っている場合、4KB(=0x1000bytes)単位で設定できる様になる。
  • ただし、リミットにaと設定した場合はa+0xFFFと復元されて、4095バイトだけはみ出してしまう。
  • これは例えば、0x54321をリミットにしたい場合、G-bitを1にして0x54だけを書き込める様にする為。(残りの0x321の領域は無視されない)
  • Haribote OS では以下の様に設定されている。
(中略)
if (limit > 0xFFFFF) {
    ar    |= 0x8000; // G-bit = 1
    limit /= 0x1000;
}
(中略)

VGAのカラーパレット

  • 取得する場合は0x03C7にパレット番号を指定して、0x03C9で読み込む。(RGBの順番で1バイトずつ)
  • 設定する場合は0x03C8でパレット番号を指定して、0x03C9で書き込む。(RGBの順番で1バイトずつ)
  • パレット番号は0~255の8ビットまで、RGBの一つの要素は0~63の6ビットまで。
  • 予めカラーパレットに以下の様に設定すれば、8ビットでIIRRGGBBの様に指定できる。(Iで明暗度(Intensity)を指定できる)
(中略)
int i, j;
io_out8(0x03C8, 0);
for (i = 0; i < 256; ++i) {
    j = (((i >> 6) & 3) + 1) * 4; // IIのビットを取得、0b00の時は4、0b01の時は8、0b10の時は12、0b11の時は16
    io_out8(0x03C9, (((i >> 4) & 3) + 1) * j - 1); // RRのビットを取得して書き込み、1~4の値にjを掛けて1を引く
    io_out8(0x03C9, (((i >> 2) & 3) + 1) * j - 1); // GGのビットを取得して書き込み、1~4の値にjを掛けて1を引く
    io_out8(0x03C9, (((i >> 0) & 3) + 1) * j - 1); // BBのビットを取得して書き込み、1~4の値にjを掛けて1を引く
}
(中略)
  • カラーパレットの書き込み中は割り込みを禁止した方が良い。

Rust

  • ※僕はまだRustを弄った事が無いので間違った情報を含んでいる可能性が充分あります。
  • 参考スライド
  • 利点と欠点
  • 低レイヤ界で結構人気があるコンパイル型プログラミング言語。
  • 命令型言語と関数型言語を混ぜた感じ。
  • メモリ解放等がコンパイル時に静的に行われる(確認される)ので、効率が良く安全。
  • 静的解析を行うので、コンパイルが通るまでが大変。ただし、不具合は出にくくなる。
  • 以下は hello world プログラムの例。
fn main() {
    println!("Hello, World!!");
}

HLT命令と特権

  • HLT命令はリング3で動きそうな処理の命令だが、動かない。
  • この命令はリング0では確実に動く。(リング1、リング2で動くかどうかは知らない)
  • リング3で動かせないのは、アプリケーション上で実行させるとOSや他のアプリケーションが困るから。
  • 何故かと言うと、HLT命令はCPUを止める命令であり、マルチタスクの場合は時間の無駄になってしまう。
  • CPUを停止させる位なら、他のアプリやOSに処理を渡した方が効率的になる。

UEFIの注意点

  • ブート処理を行ったら必ずExitBootServicesを呼び出してUEFIを停止させなければならない。
    • UEFIが裏で何をしているか分からない為、OSの実行中にUEFI何か処理を行うと危険だから。
  • ブートローダーとカーネルは分ける必要は無く、UEFIアプリとしてOSを開発しても良い。

プロテクトモード移行とパイプライン

  • CR0レジスタの値を書き換える等をしたら、CPUの動作モードを変更する事ができる。
  • CR0の値と0x00000001の論理和を取り代入すると、プロテクトモードに移行する事ができる。
    • CR0の一番右側のビットが1ならプロテクトモード、0ならリアルモード。
  • CPUにはパイプラインと呼ばれる機能があり、命令の実行中に次の命令を先に読み込んでおき、高速に実行できる様にしている。
  • 動作モードを変更した後はこのパイプラインを初期化しなければならない。
  • far JMPという命令を呼び出せば、パイプラインをフラッシュ(初期化)させる事ができ、安全に動作モードを移行させられる。
  • Haribote OSでは以下の様にして動作モードを移行させている。
(中略)
		LGDT	[GDTR0]			; 暫定GDTを設定
		MOV		EAX,CR0
		AND		EAX,0x7fffffff	; bit31を0にする(ページング禁止のため)
		OR		EAX,0x00000001	; bit0を1にする(プロテクトモード移行のため)
		MOV		CR0,EAX
		JMP		pipelineflush
pipelineflush:
		MOV		AX,1*8			;  読み書き可能セグメント32bit
		MOV		DS,AX
		MOV		ES,AX
		MOV		FS,AX
		MOV		GS,AX
		MOV		SS,AX
(中略)
GDT0:
		RESB	8				; ヌルセレクタ
		DW		0xffff,0x0000,0x9200,0x00cf	; 読み書き可能セグメント32bit
		DW		0xffff,0x0000,0x9a28,0x0047	; 実行可能セグメント32bit(bootpack用)

		DW		0
GDTR0:
		DW		8*3-1
		DD		GDT0
(中略)
  • 注:Haribote OSのパイプラインのフラッシュ(初期化)にはfar JMPは使われていない。
  • 実機では無くQEMU ではパイプラインのフラッシュ処理を挟まなくても正常に実行できた。
    • この後にfar JMPを利用してカーネル本体を呼び出しているからだろうか?
    • 無駄な遅延処理を挟んでみる実験をしたけど、これでも動作した。
    • もしかしたら、正常に動作している様に見えて、実は不具合が発生しているかもしれない。
  • Intelのマニュアル(SDMのVol.3の9.1.1)にはモードの移行後はfar JMPを呼ぶ事が推奨されている。
  • 内部動作的な部分は記載されていなかった。

Clone this wiki locally