レガシーBIOSの話。

公開:2017-03-23 21:23
更新:2017-11-15 21:58
カテゴリ:bios

はじめに

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を呼び出すことができ、開発の手間(主にドライバ)を省くことができた。

Layer 1 BASIC言語本体 BIOS モニタ キーボード ストレージ 共通呼び出し規約 アプリケーション

でも実際はBIOSを介すると遅いので、直接アクセスすることのほうが多かったような気もするが。 X1などもBIOSを持っていたが、ほぼサブルーチン的な仕様であり、FM-7ほどの洗練さは持っていないように思う。

このBIOSという言葉は、CP/Mが発祥だそうだ。 CP/MにおけるBIOSの役割は、

であった。このころのBIOSはOS側に実装されていた。 このBIOS部分を各メーカーのハードウェアによってカスタマイズを行うことによって、CP/M上で動くプログラムは、異なるハードウェア間でも実行させることができた。

Layer 1 ハードウェアA ハードウェアB BIOS BIOS アプリケーション

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が自身のドライバを読み込み、それが動作するまで間、ハードウェアに対して入出力を行うときに使われている。

結論として、

といえる。この役割は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カーネルを読み込み、起動するまでの動きはおおむね以下となる。

  1. Power OnすることでCPUが初期化され、リアルモード(8086モード)になる。
  2. 0xFFFF0番地から始まる命令を実行する。ここには通常BIOSの初期化処理へジャンプする命令が書かれている。
  3. BIOSのPOSTプロセスが走る。
  4. 周辺装置を初期化する。
  5. 割り込みベクタを初期化する。
  6. 起動ディスクからMBR(Master Boot Record)をメモリの07C00番地に読み込む。
  7. MBRを読み込んだ先頭番地(07C00H)にジャンプする。
  8. 起動パーティションを探し、パーティションからブートセクタをメモリに読み込む。
  9. ブートセクタを読み込んだメモリの先頭番地にジャンプする。
  10. カーネルローダーをメモリにロードする。
  11. カーネルローダーを読み込んだメモリの先頭番地にジャンプする。
  12. カーネルローダーはカーネルをメモリにロードする。
  13. カーネルを読み込んだメモリの先頭番地にジャンプする。

上記のような順序でOSカーネルが起動される。BIOSのABI(BIOS割り込みルーチン)は上記動作を行うのに使用されている。