はじめに
lubuntuとwindows 10のデュアルブート設定をいじっていて、GPTパーティションやUEFIなど、知らないことがたくさん出てきてちょっと困った。
しかしまあ、BIOSというのはなんなのだろう。 ブート順を変えたり、ハードウェアのコンフィグレーションを行うマザーボードのファームウェアという位置づけだと思うんだけど、それを何でBIOSと呼ぶのか不思議でしょうがない。
だってBIOSというのは「Basic Input/Output System」の略で、「基本的な入出力を行うシステム」のことだからね。 現代のBIOSはBIOSの役割を果たしていないのではないか? そのような疑問はかなり前からあって、ちょっと調べてみることにした。
調べてみると、私のPCは過去からずっとアップデートしてきているせいで、BIOSはUEFIになっているのに、レガシーなBIOS互換モードで使っていることにも気づいた。 このレガシーBIOSというのはちょっと興味深いものなので、ブログに書いておこうと思った。
今はUEFIを調べている。理解できた時点でブログに書こうと思う。UEFIもなかなかに興味深いものであるので。
BIOSはBIOSなのか?
BIOSとは「Basic Input/Output System」の略で、「基本的な入出力を行うシステム」のことである。
私がこの言葉を知ったのは8ビットPCが全盛のころである。このころのPCはOSはなく、BASIC言語がOSの役割を果たしていた。 当時一般的なPCは起動するとROMに格納されているBASIC言語が立ち上がった。 BASIC言語はエディタ兼コマンドプロンプトのようなものを持っており、BASIC言語の編集のほか簡単なPCのオペレーションができるようになっていた。 で、このBASICに寄り添うように、BIOSというものがあった。 例えばFM-7でBIOSを使用するには以下の手順で呼び出しを行う。
1. RCB領域として8バイトをメモリ上に確保する。
2. RCBにBIOS番号を始めとする必要なパラメータを全て設定。
3. インデックスレジスタXにRCBの先頭番地をセット。
4. BIOSをサブルーチンコールする。(JSR [$FBFA])
5. フラグ(RCBSTA)の確認を行う。エラー発生時は、その処理を行う。
参考:http://www23.tok2.com/home/fm7emu/ysm7/ysm7c/ysm7c1.htm#TOP
FM-7のBIOSはきっちりとした呼び出し規約(ABI(Application Binary Interface))を持っており、これに従えば自作プログラムからもBIOSを呼び出すことができ、開発の手間(主にドライバ)を省くことができた。
でも実際はBIOSを介すると遅いので、直接アクセスすることのほうが多かったような気もするが。 X1などもBIOSを持っていたが、ほぼサブルーチン的な仕様であり、FM-7ほどの洗練さは持っていないように思う。
このBIOSという言葉は、CP/Mが発祥だそうだ。 CP/MにおけるBIOSの役割は、
- ハードウェアに対しての基本的な入出力を、共通の呼び出し規約によって行うようにする(抽象化)。
であった。このころのBIOSはOS側に実装されていた。 このBIOS部分を各メーカーのハードウェアによってカスタマイズを行うことによって、CP/M上で動くプログラムは、異なるハードウェア間でも実行させることができた。
IBM PCではBIOSはROMとなって本体側に実装され、OS(PC-DOS)はBIOS ROMを経由して入出力を行うようになった。 このIBM PCのBIOSにはMBR(Master Boot Record)を使ってFDやHDDからプログラムをロード・実行する仕組みが備えられていた。さらにはハードウェアのコンフィグレーション機能が追加された。これがほんの数年前まで一般的であったPC BIOSである。
現在のOSはBIOS側に持っているABI(Application Binary Interface)を使って入出力をすることはなくなり、デバイスドライバーがその役割を担っている。 なぜならばBIOSのABIはリアルモードで呼び出さなくてはならない。しかしOSはプロテクトモードで動作しているので、リアルモード切替え→BIOSコール→プロテクトモードに切り替えという動作をしなければならない。 往々にしてこのようなコードはコストが高い。 またBIOSはマルチタスクでの利用は考慮されていない。BIOSはリエントラントなつくりになっていない。
しかしBIOSが持っているABI(BIOSコール)は、OSが自身のドライバを読み込み、それが動作するまで間、ハードウェアに対して入出力を行うときに使われている。
結論として、
- BIOSは、OSのブートプログラムコードのためのハードウェアアクセス用ABIを提供するため、BIOSである。
といえる。この役割はUEFIになった現在でも変わっていない。
(余談)CPUはリアルモードで実行を開始する
BIOSのことを調べていて一番驚いたのはこれだ。 64ビットOS全盛の時代にあっても、CPUがCore i7であっても電源ON時にはCPUはリアルモード(8086モード)で動き始める。 BIOSはそのモードのまま、起動される。 なのでメモリの上限は1MBまでで、その空間のE0000番地-FFFFF番地にBIOS ROMはマップされる。
レガシーBIOSはどのように起動されていたのか
「http://www.intel.co.jp/content/www/jp/ja/architecture-and-technology/64-ia-32-architectures-software-developer-manual-325462.html」の「9.1.4 First Instruction Executed」 によればCPUは電源ONもしくはリセットされた場合、リアルモードで起動し、FFFF0番地から命令を読み込んで実行するとのことである。私のCPU(Core i7 6700)であればメモリアドレスとしてはFFFFFFF0番地となるのだが、リアルモードではアドレスバスの20ビット-31ビットは強制的に0にセットされるそうだ。 このアドレスは8086のメモリの上限値 1MB - 16byteの位置となっている。
BIOS ROMはE0000番地-FFFFF番地にマップされているので、ROMに書かれてあるコードが実行されることになる。 メモリは16byteしかないので、FFFF0番地にはBIOSの初期化コードの先頭番地にジャンプする(JMP)コードが書いてある。 このようにしてBIOSは起動される。
このあたりの情報は以下のサイトが詳しい。
http://park12.wakwak.com/~eslab/pcmemo/boot/boot2.html
レガシーBIOSが持つABI
BIOSが持つABIは、BIOS割り込みルーチンと呼ばれ、ソフトウェア割り込み(X86のアセンブラではINT XX)で実装されている。
https://en.wikipedia.org/wiki/BIOS_interrupt_call
レガシーBIOSのブートプロセス
上で紹介したサイトにはブートプロセスの詳細な説明が書いてあるので、詳しくはそちらを読んでもらうとして、PC電源ONからOSカーネルを読み込み、起動するまでの動きはおおむね以下となる。
- Power OnすることでCPUが初期化され、リアルモード(8086モード)になる。
- 0xFFFF0番地から始まる命令を実行する。ここには通常BIOSの初期化処理へジャンプする命令が書かれている。
- BIOSのPOSTプロセスが走る。
- 周辺装置を初期化する。
- 割り込みベクタを初期化する。
- 起動ディスクからMBR(Master Boot Record)をメモリの07C00番地に読み込む。
- MBRを読み込んだ先頭番地(07C00H)にジャンプする。
- 起動パーティションを探し、パーティションからブートセクタをメモリに読み込む。
- ブートセクタを読み込んだメモリの先頭番地にジャンプする。
- カーネルローダーをメモリにロードする。
- カーネルローダーを読み込んだメモリの先頭番地にジャンプする。
- カーネルローダーはカーネルをメモリにロードする。
- カーネルを読み込んだメモリの先頭番地にジャンプする。
上記のような順序でOSカーネルが起動される。BIOSのABI(BIOS割り込みルーチン)は上記動作を行うのに使用されている。