はじめて読む486　第6章 保護

## 6. 保護

## 6.1 保護機能

- 保護機能とは
    - プロテクトモードでは。1つ1つのマシン語命令を実行するたびに、その命令を実行して良いかどうかのチェックをCPU内部で行い、安全性を確認してから命令の実行が行われる
    - 安全性が確認できなかった場合は、フォールトを発生させ、オペレーティングシステムに制御を移す
- セグメントリミット
    - 486は、セグメント内のメモリをアクセスするすべての命令の実行に先立ち、アクセスしようとするメモリのオフセットアドレスがリミット値を超えていないかどうかをチェックする
- セグメントの属性
    - セグメントの属性は、セグメントディスクリプタの一部としてオペレーティングシステムがセットする
    - 保護
    
    | TYPE=0 | 読み出し専用データセグメント |
    | --- | --- |
    | TYPE=1 | 読み書き可能データセグメント |
    | TYPE=2 | 読み出し専用スタックセグメント |
    | TYPE=3 | 読み書き可能スタックセグメント |
    | TYPE=4 | 実行専用コードセグメント |
    | TYPE=5 | 実行および読み出し可能コードセグメント |
    | TYPE=6 | 実行専用今フォーミングコードセグメント |
    | TYPE=7 | 実行および読み出し可能コンフォーミングコードセグメント |
    | S | セグメントの場合は1 |
    | DPL | セグメントの特権レベル |
    - メモリ管理
        - Pビットはセグメントが物理メモリ上に存在するかどうかを表す
        - Aビットはあまり使われていないセグメントを探すために使われる
        - この2つのビットを使うことで、仮想記憶を実現することができる
    
    | P | セグメントが存在する |
    | --- | --- |
    | A | セグメントがアクセスされた |
- セグメントの種類
    - 486は、セグメントをアクセスする命令を実行するたびにTYPEフィールドの値をチェックし、誤ったアクセス方法を検出するとフォールトを発生させる
    
    | Typeフィールドの値 | セグメントの種類 | セグメント |  |
    | --- | --- | --- | --- |
    | 0 | 読み出し専用データセグメント | DS, ES, FS, GS, SS | データセグメント |
    | 1 | 読み書き可能データセグメント | DS, ES, FS, GS, SS | データセグメント |
    | 2 | 読み出し専用スタックセグメント | DS, ES, FS, GS, SS | データセグメント |
    | 3 | 読み書き可能スタックセグメント | DS, ES, FS, GS, SS | データセグメント |
    | 4 | 実行専用コードセグメント | CS | コードセグメント |
    | 5 | 実行および読み出し可能コードセグメント | CS, DS, ES, FS, GS | コードセグメント |
    | 6 | 実行専用今フォーミングコードセグメント | CS | コードセグメント |
    | 7 | 実行および読み出し可能コンフォーミングコードセグメント | CS, DS, ES, FS, GS | コードセグメント |

## 6.2 特権レベル

- 特権レベル
    - プロテクトモードのプログラムを実行している状態には0から3までの4段階の動作レベルがある
    - 動作レベルは、実行できる命令の種類とアクセスできるメモリの範囲を規定する
    - オペレーティングシステムは特権レベル0の動作レベルで実行させる
    - 特権レベル1や2の動作レベルでは、オペレーティングシステムの補助的な機能を担当するプログラムやハードウェアを操作するプログラムなど、中間的な立場のプログラムを実行させる
    - アプリケーションソフトウェアは、特権レベル3の動作レベルに切り替えてから実行する
- DPL
    - Descriptor Privilege Level
    - セグメントの特権レベルを表す
- CPL
    - Current Privilege Level
    - CPLは、プログラムの置かれているセグメントのDPLで決まる
    - 動作レベルを変更するためには、セグメント間CALL命令やセグメント間JMP命令を実行する
        - ただし、特権レベルの異なるセグメントへ直接ジャンプすることはできず、コールゲートを介してジャンプする
    - 原則DPLとCPLは一致するが、コンフォーミングセグメント上のプログラムを実行している状態では両者の値が異なることもある
- 特権命令

| MOV CR0,  レジスタ | CR0にレジスタの値をロードする |
| --- | --- |
| LGDT メモリ | GDTRにメモリの値をロードする |
| LIDT メモリ | LDTRにメモリの値をロードする |
| LLDT メモリまたはレジスタ | LDTRにメモリまたはレジスタの値をロードする |
| LTR メモリまたはレジスタ | TRにメモリまたはレジスタの値をロードする |
| HLT | CPUの動作を停止する |
- 特権レベルとセグメントのリード/ライト
    - 動作レベルよりも高い特権レベルを持つセグメントにアクセスすることはできない
    - セグメントアクセスのチェックは、セグメントレジスタにセレクタ値をロードする瞬間に行われる
- IOPL
    - I/OポートはDPLを持たないが、特権レベルの設定はできる
    - I/Oポートの特権レベルのことをIOPL（I/O Privilege Level）と呼び、CPU内にあるEFLAGSレジスタ内のIOPLフィールドに設定する
    - 動作レベル0の状態に限り、スタック領域からフラグレジスタに値をPOPするPOPFD命令を使って、I/Oポートの特権レベル（IOPL）を設定することができる

## 6.3 ゲート

- コールゲートによる動作レベルの移行
    - 動作レベル間の移行には、保護機能によって強い制限が敷かれている
    - 特権レベルの低いコードセグメントから特権レベルの高いコードセグメントを、コールゲートを開始て呼び出すことだけ許される
    - コールゲートは486に組み込まれた動作レベル移行のための仕組みのことで、主な用途はオペレーティングシステムの呼び出し口
        - オペレーティングシステムに設置した関所のようなもの
- ゲートディスクリプタとゲートの呼び出し方法
    - オペレーティングシステムは、アプリケーションソフトウェアからの呼び出し口として、起動時にコールゲートを作成しておかなければならない
    - コールゲートとは、ゲートと呼ばれるシステムオブジェクトの一種で、ディスクリプタによって定義されるもののうち、セグメント以外のものを指す
    - ディスクリプタテーブル中にゲートディスクリプタを作成するとゲートを作成したことになる
    - ゲートディスクリプタには、ゲートを介して呼び出す先のルーチンのアドレスが格納されている
    - コールゲートを呼び出すCALL命令では、セレクタ値とオフセットアドレスの組みを指定するが、オフセットアドレスの方は全く使われずに捨てられてしまう
- ゲートディスクリプタの構造
    
    ```c
    typedef struct _GateDesc {
    	unsigned short offsetL;
    	unsigned short selector;
    	unsigned char count;
    	unsigned char type;
    	unsigned short offsetH;
    } GateDesc;
    ```
    
- ゲートの種類
    - ディスクリプタは、属性部分のSビットが1ならセグメントディスクリプタを表し、0ならシステムオブジェクトを表す
    - システムオブジェクトの種類は以下のようにTYPEフィールドで区別される
    
    | TYPE | ゲートの種類 |
    | --- | --- |
    | 0H | 予約ずみ |
    | 1H | 16ビットTSS |
    | 2H | LDT |
    | 3H | ビジーな16ビットTSS |
    | 4H | 16ビットコールゲート |
    | 5H | タスクゲート |
    | 6H | 16ビット割り込みゲート |
    | 7H | 16ビットトラップゲート |
    | 8H | 予約ずみ |
    | 9H | 32ビットTSS |
    | AH | 予約ずみ |
    | BH | ビジーな32ビットTSS |
    | CH | 32ビットコールゲート |
    | DH | 予約ずみ |
    | EH | 32ビット割り込みゲート |
    | FH | 32ビットトラップゲート |
    - ゲートディスクリプタにも特権レベル（DPL）がある
    - ゲートが指すルーチンのセグメントの特権レベルが、プログラムの動作レベルよりも高い場合でも、ゲートの特権レベルが条件を満たせば（動作レベルよりも低ければ）呼び出すことが可能

## 6.4 動作レベルの移行を実験する

省略