読者です 読者をやめる 読者になる 読者になる

S.F. Page

Programming,Music,etc...

スペース・ウォーとPDP-1のグラフィックスについて

ビデオゲーム

lubuntuのインストールでありえないハマりの連続で、ちょっとラズパイへの意欲が削がれてしまっている私である。 それはさておき、私は風呂に入りながら本を読むのだが、最近よく読んでいるのは「NHKスペシャル 新・電子立国〈4〉ビデオゲーム・巨富の攻防」である。

NHKスペシャル 新・電子立国〈4〉ビデオゲーム・巨富の攻防

この本は1997年発売なのでかなり古い本である。今はなきハドソンがシャープのパソコン用ソフトの開発・製造・販売で成長したところとか、任天堂の山内社長のインタビューとか、何度も読みかえしているので本はボロボロである。

この本にビデオゲームの元祖である、PDP-1で開発された「スペース・ウォー」というゲームのことが載っている。 スペース・ウォーとは2人プレイのゲームで、宇宙船を操作してミサイルを撃ち合うシューティング・ゲームである。下はPDP-1の実機で動かした動画のようである。

このスペース・ウォーが世に出たのは1962年で、私が生まれる数年前である。この時代にこのようなグラフィックスを備えたゲームを完成させること自体すごいことだが、PDP-1というミニコンがこのようなゲームを作成できうるようなグラフィック機能を備えていたというのも驚きである。ビットマップグラフィック(ラスタースキャンディスプレイ)がこの時代ですでにできていたということなのだろうか。 ウィキペディアによれば「1024×1024のアドレス指定可能な位置を持ち、毎秒2万点を描画できる。CRT上に1点を表示するための特殊な命令を使って画像を構築した。」とある。これはどうもビットマップディスプレイというわけではなさそうだ。おそらく昔のベクタースキャンディスプレイのようなものだったのだろうと推測する。

このゲームを見たノラン・ブッシュネルが「コンピューター・スペース」を作って失敗し、その後アタリ社を設立して「ポン」を作って、アーケード・ゲームの礎を築くのである。

レガシーBIOSの話。

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

結論として、

  • BIOSは、OSのブートプログラムコードのためのハードウェアアクセス用ABIを提供するため、BIOSである。

といえる。この役割はUEFIになった現在でも変わっていない。

(余談)CPUはリアルモードで実行を開始する

BIOSのことを調べていて一番驚いたのはこれだ。 64ビットOS全盛の時代にあっても、CPUがCore i7であっても電源ON時にはCPUはリアルモード(8086モード)で動き始める。 BIOSはそのモードのまま、起動される。 なのでメモリの上限は1MBまでで、その空間のE0000番地-FFFFF番地にBIOS ROMはマップされる。

レガシーBIOSはどのように起動されていたのか

Intel® 64 and IA-32 Architectures Developer's Manual」の「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は起動される。

このあたりの情報は以下のサイトが詳しい。

ブート ストラップ - パソコンの起動

レガシーBIOSが持つABI

BIOSが持つABIは、BIOS割り込みルーチンと呼ばれ、ソフトウェア割り込み(X86のアセンブラではINT XX)で実装されている。

BIOS interrupt call - Wikipedia

レガシー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割り込みルーチン)は上記動作を行うのに使用されている。

Windows 10とlubuntuのデュアルブートで起こる障害とその解消法

Windows 10 lubuntu

うーむ。なぞだ。。 今Windows 10とlubuntuをデュアルブートで使おうと思っているんだけれども、ここ1週間障害に苦しめられていた。

障害

Windows 10でブートした後、lubuntuをブートすると、lubuntuの起動パーティションが破壊される。

どのような環境で起こるか

Windows 10とlubuntuのデュアルブート環境。 grub2で起動しても、Windowsブートマネージャーで起動しても、物理ディスクを分けてブートローダーを分けても、結果は同じ。

根本原因

不明

発生時の対処

e2fsck -p -b 32768 /dev/(ブートするパーティション)

で修正すると起動できるようになる。

暫定的な対処

Windows 10のディスクの管理で、linuxが入っている物理ディスクをオフラインにする。 こうするとなぜか障害が解消する。 なので物理ディスクのパーティションをWindowsとlinuxで分け合う形では、私の環境ではデュアルブート不可能である。 このことからWindows 10のパーティション管理機能がlinuxのパーティションに対して何かをやらかしているのではないかという推測が立つ。

そういうわけで、ここ一週間は暫定的な対処法を見つけるまで、ひたすらインストールを繰り返した。もう15回くらいはインストールしたと思う。 これでようやく次のステップに進めるようにはなった。