Apple Lisaを調べて見た

Appleが1983年に発売した世界初のGUIパソコンとはどんなものだったのか調べて見たら予想以上に先進的なハードウエアでした。

f:id:k_igrs:20051011141700j:plain

CPUにはモトローラ社のMC68000を5MHzで動作させています。

MC68000マルチタスクシステムを構築するための機能、例えばOSとユーザープログラムを分離する特権モードなどを有しています。

Macintosh,Amiga,AtariST,X68000などのMC68000を採用したパソコンはこのような機能を有効に使用していませんでした。

現代的なパソコンではユーザープログラムがOSを巻き込んで暴走しないように、OSとユーザーの実行を分離する、暴走したプログラムがOSや他のタスクのメモリ空間に影響を与えないメモリ保護が必要でLisaではその機能を実装しています。

Lisaのメモリ保護

LisaではMC68000の外部にMMUを接続してOSやユーザーのプログラムが他のメモリ空間に影響を与えないようになっています。

MMUMC68000の上位7bitを使用して24Bit 16MByteのアドレス空間を128KByte 128のセグメント空間に分割します。

128のセグメントはA20-A9までのセグメントアドレス12bitを記述できるレジスタと4bitの属性フィールドおよび8bitのメモリリミットフィールドで構成されます。このセグメントに設定したアドレスとCPUのA16-A9の加算を行いメモリアドレスのA20-A9を生成します。メモリアドレスのA8-A0についてはCPUのアドレスをそのまま使用します。

つまりLisaのMMUはCPUの論理アドレスを128KByte単位で2MByte(21bit)の任意の物理アドレスへ再配置を行います。したがってLisaに搭載できるメモリは最大2MByteとなります。

128KByte以上のメモリを使用するには連続したセグメントを使用することで対応します。

Lisa MMUによるアドレス変換

f:id:k_igrs:20210203162240p:plain


このセグメントテーブルはOS用に1,ユーザー用に3の計4つが用意され、それぞれのセグメント毎にアクセスの属性をセットできる4bitのフィールドとセグメント使用の上限を決める8bitのメモリリミットフィールドがあり、 属性に違反する不正アクセスやメモリ使用の上限を越えた場合、CPUに対してバスエラーを発生させてOSに制御を移します。

属性にはメモリかI/Oか、Read OnlyかRead/Write可か、スタック領域かどうかが設定できます。

プログラム領域はメモリ-Read Only-Nonスタックに、Data領域はメモリ-Read/Write化-Nonスタックに設定する様です。

メモリリミットフィールドはセグメント空間を128KByte以下のメモリ空間を設定するために使用されます。ユーザーは128KByteのセグメント空間のうち、A8-A0の512Byteを1ブロックとして何ブロック使用するかをOSに通知します。例えば32KByte使用する場合は64ブロックです。OSはCPUのアドレスA16-A9の値と要求されたブロック数を加算したときに桁上がりが生じる値(2の補数)をメモリリミットフィールドに書き込みます。たとえば32KByte=64(0011_1111b)ブロックなら1100_0000bです。プログラムが32KByteを超えるメモリをアクセスすると、CPUアドレスと設定値を加算した結果に桁上がりが生じるため、要求メモリを越えたと判断してMMUはCPUに対してバスエラーを発生させてメモリアクセス違反とします。このようにしてどのようなプログラムサイズであっても、MMUは無駄なく物理メモリに割り当てることができます。

このMMUの仕組みは実に巧妙にできています。ユーザープログラムは使用するメモリに応じてOSにセグメントの割り当てを要求した後はセグメントを意識しないでコードを記述でき、OS側ではコードの再配置とメモリプロテクトによりMacintoshの様にユーザープログラムの暴走がシステムを巻き込むことを防止できます。

またユーザー用のセグメントテーブルを3つ用意する事でプログラムの切り替えの高速化を図っています。

Lisa OSのマルチタスクが協調型となっているのはプリエンプティブマルチタスクでは遅くて使い物にならなかったのでしょう。

Lisaのメモリアクセス

LisaのメモリアクセスはCPUとビデオアクセスの競合によるオーバーヘッドを避けるため、Apple IIと同様に1回のメモリアクセスをビデオとCPUのアクセスに分割しています。

MC68000のメモリアクセスは4クロックなので前半2クロックでビデオアクセスを、後半2クロックでCPUアクセスを行います。

前半2クロックのビデオアクセスの期間にCPUがアクセスするセグメントの属性チェックを行うのでしょう。

f:id:k_igrs:20210202214522p:plain

Lisa OS

Lisaが起動すると、メモリマネージャーとシェルの二つのプロセスが実行されます。プロセスは子プロセスを生成できます。

シェルプロセスが子プロセスを生成してユーザーのプロセスを実行します。生成されたプロセスにはプロセスIDが付加され、Lisaのセグメント空間に割り当てられます。

プロセスは最大16のデータセグメントと106のコードセグメントを使用します。さらにプロセス専用のStack領域とデータ共有のためのセグメントが割り当てられます。

f:id:k_igrs:20210220081443p:plain

Lisa OSは複数のプロセスに1から255の優先度をつけ、スケジューラは優先度の高いプロセスから実行していきます。

プロセスの制御に関しては強制終了、一時停止、アクティブ化の操作が行えます。

実行中のプロセスは以下の場合に停止します。

  • 実行中のプロセスが入力または出力を要求した場合。スケジューラは、最初のプロセスがI/Oの完了を待機している間に、次に実行中の優先度の高いプロセスを開始します。
  • 実行中のプロセスが、その優先度を別の準備完了プロセスの優先度より低くするか、別のプロセスの優先度をそれ自体よりも高く設定した場合。
  • 実行中のプロセスが、CPUを別のプロセスに明示的に譲った場合。
  • 実行中のプロセスが、優先度の高いプロセスをアクティブにした場合。
  • 実行中のプロセスはがそれ自身を一時停止した場合。
    優先度の高いプロセスの準備が整った場合。
  • 実行中のプロセスが、コードをメモリにスワップする必要があった場合。
  • 実行中のプロセスが、イベント待機呼び出しを実行した場合。
  • 実行中のプロセスがDELAY_TIMEを呼び出した場合。

上記以外ではプロセスが終了しないのでバックグランドで実行する必要なプロセスはCPU資源要求を記述しておく必要があります。

実行が停止すると、Lisa OSのタスクスケジューラは現在のプロセスの状態を保存し、準備ができたプロセスのプールを調べて次のプロセスを選択して実行します。新しいプロセスが、コードやデータをメモリにロードする必要がある場合は、メモリ・マネージャ・プロセスが起動されます。

プロセスIDに対してKlLL_PROCESSを実行するとそのプロセスは子プロセスごと終了します。

終わりに

LisaではOSとユーザープログラムを特権モード、ユーザーモードに分け、MMUを使用してメモリの不正アクセスからシステムを守っています。これが1世代で終了したのは実に惜しいです。

Lisaの翌年にでたMacintoshMacOSXになるまで、ユーザープログラムの暴走で爆弾マークを出してシステムが落ちることがよくありました。MC68030以降のMMUを内臓したCPUになっても初期仕様に基づくプログラムの互換性のため、堅牢なOSを作ることができませんでした。この辺は同じMC68000を搭載したAmigaでも同様でMMUガベージコレクションにしか使われなかった様です。