Intelが発表したX86-Sについて(2/3) – 詳細編

はじめに

Intelが公開したX86-Sの提案について取り上げる3本中2本目の本メモでは、Intelが公開したX86-SのPDFドキュメントの内容を「詳細編」として日本語化して掲載します。内容はとても高度で、IA-32とIntel 64を仮想化関連、その後のセキュリティー向けの追加仕様、マルチコア/マルチCPUが起動してから実際にUEFIやOSを起動するまでの動きなどを含めて理解していることが前提となっています。それらに対する変更点と、それによる影響を論じるものとなっています。

お願い

もしもIntelの関係者で、私がこの日本語ドキュメントを公開することが何らかのライセンスや法的問題があるとお考えであるならば、メールにてご連絡をいただければと思います。その際は、私がメールの送付主がIntel関係者であることを認識できるようにIntel社内からメールを送信し、所属・肩書き等を添えてください。

英語版の資料をベースにしているこの日本語ドキュメントはIntelの著作権が及ぶ範囲内にあります。その上で、この日本語ドキュメントには“さかきけい”の著作権が発生しています。“さかきけい”はすべての著作権法上の権利を留保します(詳しくは「ご利用上の注意とお願い」を参照ください)。

免責の表明

この日本語ドキュメントはIntel Corporationが公開している「X86-S ISA External Architectural Specification」に記載されている情報を元に、“さかきけい”の理解で作成したものです。このためIntel Corporationには何らこの日本語ドキュメントに対する責任はありませんので、この日本語ドキュメントに関連する問い合わせをIntelに対して行うことを禁止します。

また、この日本語ドキュメントを作成した“さかきけい”も何ら責任を負いません。この日本語ドキュメントの内容は、利用者自身の責任においてのみ使用することができます。

使用上の注意

  • Intelによる法的な意味合いを持つと考えられる記述は英文のままとしています。これは、日本語にすることで意味合いが変化することを防ぐ目的のものです。しかし、その部分は英語原文に付属する部分であることを前提としなければなりません。したがって、本日本語ドキュメントではなく、文脈としては原書に付属することになります。本日本語ドキュメントにおいては、Intelが免責を宣言する部分はその通りですが、何らかの権利や許可を与える部分についてはすべて無効であるとご理解ください。※1今回は提案書であるということを鑑み、日本語参考訳を付記していますが、状況としては前述のとおりです。
  • 複数の英単語によって構成される語は、単語間に「・」を入れて表現しています。例:ルート・ファイル・システム※2
  • 原則として単語末の長音記号「ー」は省略しない方針で編集しています。例:プロセッサー※3
  • 気づいたTypoや編集ミスなどは明確であると考えられる場合に若干修正しています。
  • 日本語での記述におかしいと思われる個所がある場合には原書をあたってください。
  • 技術的などの理由で記載内容にわからない事項がある場合には別途調べてください(“さかきけい”に質問のメールを送るのはご遠慮ください※4)。
  • 明らかな誤訳がある場合には具体的なご指摘をメールまたはコメントでお知らせいただけると助かります。
  • 記述内容に誤りがある場合にもお知らせいただけると嬉しく思います。ただし、原書も間違っている場合には特に日本語ドキュメントを修正することはせずに、訳注を追加するだけとするかもしれません。
  • 前述の内容と被りますが、“さかきけい”は何ら責任や義務を負うものではありません。

文書についてのご指摘をいただける方へのお願い

  • なるべく平坦でかつ理解しやすい程度に周辺情報を含む、日本語でのご指摘をお願いします。
  • “さかきけい”の主観において、いただいた情報の適用を行わないことがあることをあらかじめご理解ください。

X86-S
外部設計仕様書

Rev. 1.0
2023年4月
ドキュメント番号: 351407-001

Notice: This document contains information on products in the design phase of development. The information here is subject to change without notice. Do not finalize a design with this information.

Intel technologies may require enabled hardware, software or service activation.

No computer system can be absolutely secure. Intel does not assume any liability for lost or stolen data or systems or any damages resulting from such losses.

Your costs and results may vary.

You may not use or facilitate the use of this document in connection with any infringement or other legal analysis concerning Intel products described herein. You agree to grant Intel a non-exclusive, royalty-free license to any patent claim thereafter drafted which includes subject matter disclosed herein.

No license (express or implied, by estoppel or otherwise) to any intellectual property rights is granted by this document.

All product plans and roadmaps are subject to change without notice.

The products described may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request.

Intel disclaims all express and implied warranties, including without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement, as well as any warranty arising from course of performance, course of dealing, or usage in trade.

Copies of documents which have an order number and are referenced in this document may be obtained by calling 1-800-548-4725 or by visiting www.intel.com/design/literature.htm.

Copyright © 2023, Intel Corporation. Intel, the Intel logo, and other Intel marks are trademarks of Intel Corporation or its subsidiaries. Other names and brands may be claimed as the property of others.

告知:このドキュメントには開発・設計フェーズの製品に関する情報が含まれています。この情報は予告なしで変更されることがあります。この情報で設計を確定させないでください。

Intelの技術は、有効にするためのハードウェア、ソフトウェア、またはサービス・アクティベーションが必要となることがあります。

どのようなコンピューター・システムも絶対的にセキュアであるはずがありません。インテルはそのような損失から生じる喪失、またはデータまたはシステムの略取またはその他の損害に対して一切の責任を負いません。

あなたの費用と結果は釣り合わないことがあります。

あなたは、ここで説明されるインテル製品に関して、どのような侵害あるいは他の法的分析を目的として、本ドキュメントの使用または援用をすることはできません。あなたは、ここで明らかにされた内容を含む、その後に作成されたどのような特許請求の範囲に対しても、非排他的で、ロイヤルティーの発生しないライセンスをインテルに与えることに同意します。

全ての知的所有権への(禁反言またはそれ以外、明示または暗示による)ライセンスが、このドキュメントによって与えられることはありません。

すべての製品計画およびロードマップは、告知なく変更されることがあります。

説明した製品には、発表された仕様から逸脱するエラッタとして知られている設計上の欠陥あるいはエラーを含むことがあります。現状の判明済みエラッタについては(その内容を)請求することができます。

無制限な市場向けの暗黙的な保証、特定目的への適合性、および非侵害性を含む、履行の過程、取引の過程、または貿易における取り扱いから生じる、すべての保証と同様に、インテルはすべての明示的および暗黙的な保証を放棄します。

注文番号および本ドキュメントから参照されるドキュメントのコピーは、電話番号1-800-548-4725またはwww.intel.com/design/literature.htmから入手できるものがあります。

Copyright © 2023, Intel Corporation.
Intel、Intelロゴ、および他のインテル・マークはIntel Corporationまたはその子会社の商標です。他の名称とブランドは他のものの所有権が設定されていることがあります。

目次

図の一覧

表の一覧

1 このドキュメントについて

1.1 対象とする読者

このドキュメントはX86-S ISA用のソフトウェア開発のためを意図しています。

フィードバックは電子メールでx86s_feedback@intel.comまでお送りください※5

2 はじめに

X86-Sは過去の時代の実行モードとオペレーティング・システム用ISAを取り除いた「レガシーを削減したOS用のISA(legacy-reduced-OS ISA)」です。

X86-S ISAの存在は将来のCPUIDフィールドにおけるメインCPUID機能ビットの1つ、LEGACY_REDUCED_OS_ISAによって示されます。このビットは本ドキュメントで説明しているすべてのISAの削除を意味します。いくつかの追加機能があります。64ビットSIPIまたは5レベル・ページ・テーブル・スイッチのような、別々のCPUID機能フラグを持っているものは、X86-Sであるかどうかを問わずに独立して実装することができます。

X86-S ISAによる変更点は以下の通りです:

  • CPUは常にページ化モードであるように制限する。
  • 32ビットのリング0および仮想86モードを削除する。
  • リング1とリング2を削除する。
  • 16ビットのリアル・モード及びプロテクト・モードを削除する。
  • 16ビットのアドレッシングを削除する。
  • 固定MTRRを削除する。
  • ユーザーレベル入出力およびストリング入出力を削除する。
  • CR0ライトスルー・モードを削除する。
  • CR0のレガシーFPU制御ビットを削除する。
  • リング3の割り込みフラグ制御を削除する。
  • 旧式のCRアクセス命令を削除する。
  • INIT/SIPIを再設計する。
  • 4から5レベルの間のページ・テーブルの新しい切り替え手段を追加する。
  • XAPICを削除し、X2APICのみをサポートする。
  • APICから8259のサポートを削除する。
  • EFER MSR内のNXまたはSYSCALLまたはロング・モードの無効化を削除する。
  • #SSおよび#NP例外を削除する。
  • 以下の条件でセグメンテーション設計のサブセットをサポートする:
    • IDTイベント・デリバリーをサブセットに制限する。
    • FS、GSのbaseのみ。
    • GDT、IDT、およびTSSのbaseとlimit。
    • (64ビットと同様に)32ビット・モードにおけるコードとデータのフェッチにlimitが存在しない。
    • すべてのモードにおいて、CS、DS、ES、FS、およびGSにおけるデータまたはコードのフェッチについて、非ARまたは使用不可能なセレクターの検査をしない。
    • far call、far return、far jump、およびIRETのサポートを制限する(FREDのように)。

3 設計変更

3.1 32ビットのリング0を削除

32ビットのリング0は今後サポートせず、(32ビットのリング0に)入ることはできません。

3.2 リング1およびリング2の削除

リング1およびリング2は今後サポートせず、(リング1とリング2に)入ることはできません。

3.3 16ビットおよび32ビットのプロテクト・モードの削除

16ビットおよび32ビットのプロテクト・モードは今後サポートせず、(それぞれのモードに)入ることはできません。CPUは常にロング・モードで動作します。32ビット・サブモードはIntel64(コンパチビリティー・モード)として依然存在しています。CS.L==0およびCS.D==0を持っているディスクリプターをCSにロードする試みは#GP(sel)例外を生成します。

3.4 16ビットのアドレッシングおよびアドレス・サイズを示すオーバーライドの削除

ジャンプ以外の命令によるメモリーの参照によって、32ビット・コンパチビリティー・モードにおいて、16ビットのアドレスを生成するオーバーライド・プリフィクス(0x67)は#GP(0)例外のトリガーとなります。

0x66をプリフィクスに置くかつてのジャンプ命令によってRIPが16ビットへと切り取られる(キャストされる)場合(Jump Short 0x7*、Jump Near 0x0f 8*、 LOOP 0xE0-2、JECZ 0xE3、JMP near 0xE9および0xEB、CALL 相対 0xE8、JMP near 0xFF/4、 CALL 間接 near 0xff/2、RET near 0xC2-3、JMP far 0xEAおよび0xFF/5、CALL 間接 far 0xFF/3、CALL far 0x9A、RET far 0xCA-B)には#UD例外となります。

0x67をプリフィクスに持つジャンプ命令によって16ビット(CALL 相対 near mem 0xff/2 mem、JMP far 0xeaおよび0xff /5、CALL 相対 far 0xff /3)へと切り取られる(キャストされる)場合には#GP(0)となります。

LEAまたNOPのようなメモリーの変更またはジャンプを行わない操作は非フォルトの存在であることに注意が必要です。

コンパチビリティー・モードにおいて、SS.B==0 (16ビット・データ・セグメント)を指定するディスクリプターをロードする試みは#GP(sel)例外を生成します。

3.5 CPUID

LEGACY_REDUCED_OS_ISA機能ビットは本ドキュメントが解説するすべてのISAを削除することを示す将来のCPUIDです。

将来のCPUID機能フィールドにおけるSIPI64は64ビットSIPIのサポートをすることを示します。

将来のCPUID機能フィールドにおけるLA57SWITCHは5レベル・ページング・スイッチに対応することを示します。

3.6 制限されたサブセットのセグメンテーション

X86-Sはセグメンテーションのサブセットをサポートします:

  • GDT/LDTにおいてゲートをサポートしない; サポートはデータ・セグメント、非コンフォーミング・コード・セグメント、およびTSSに限定して行う。
  • baseについてはFS、GS、GDT、IDT、LDT、およびTSSレジスターのためにサポートされる; CS、DS、ES、およびSSの32ビット・モードのためのbaseは、64ビット・モードでは無効(ゼロとして扱われる)となる。
  • limitのサポートはGDT、IDT、LDT、およびTSSに対してのみ行われる; CS、DS、ES、FS、GS、およびSSのためのlimitは無制限として扱われる。
  • 下方伸長、コンフォーミング、および使用不可能なセグメントはサポートしない。
  • descriptor.DPLフィールドおよびselector.RPLは0または3でなければならない; そうでなければ、セグメント・ロードのアクセス権は同一となる。
  • ロード/ストアにおいては、R/W権限とNULLは無視される。
  • IRETはリング0から3に切り替えるか、現在のリングにとどまることはできるが、タスク・スイッチを引き起こすことはできず、仮想8086モードに入ることはできない。
  • LAR命令を通してアクセス済みと設定されているように見える以外には、ディスクリプターのアクセス済みビットはメモリーにセットされない。
  • セグメントを参照する際に、セグメント・オーバーライド・プリフィクスは無視される(ただし、FSとGSを除く)。セグメント・オーバーライドの優先順位は変更できない; それがFSあるいはGS以外の何かを意味するオーバーライドの全てのグループはDSを使用するように置き換えられる。
  • #SS例外は削除され、代わりに#GP(0)を通知する。
  • #NP例外は削除され、代わりに#GP(0)を通知する。
  • LMSW命令は削除され、#UD例外を通知する。

表1に示している3つのオペレーティング・モードをサポートします。

表1. サポートするオペレーティング・モード

  CPL=0 CPL=3
LMA=1 CS.L=0 サポートしない User32(制限されたリング3のコンパチビリティー・モード)
LMA=1 CS.L=1 Supervisor(リング0の64ビット・モード) User64(リング3の64ビット・モード)

3.7 新しいセグメント・レジスターへのロード時チェック

セグメント・レジスターへロードする際には、以下の条件をチェックします:

  • descriptor.DPLフィールドは0または3であること。
  • コード・ディスクリプターが、コンフォーミングではないこと、DPL == 0の時に16ビットまたは32ビットにならないこと。
  • データ・ディスクリプターは下方伸長ではないこと。

これらの条件が満たされなければ、#GP(sel)例外を通知します。

非無制限limitまたは非ゼロbaseをセグメントにロードするとき、#GP例外は生成されません。

第4章で変更後の命令の疑似コードを見ることができます。

3.8 #SSおよび#NP例外の削除

全ての失敗するスタック・セグメントの参照、明示的および暗黙的の両方において、今後は#SS例外を引き起こすことはありません。代わりに、#GP例外を生成します。全てのディスクリプターのロード時にdesc.P==0である場合には、(今後は#NP例外ではなく)#GP(sel)例外を生成します。

3.9 固定されたモードのビット

CPUは常にIntel 64の64ビット・サブモードで動作します。リアル・モード、プロテクト・モード、または仮想86モードを有効にすることはできません。

3.9.1 固定されたCR0のビット

CR0レジスターのすべてのビットを図1に示します。この図のTS、WP、AM、およびCDビット以外は固定されます。ETは1に固定されていますが、入力時に無視されます。不適切な値を固定ビットに設定すると#GP(0)例外を生成しますが、構成されたことによってCR0 exitingからVM exitが引き起こされた後に限られます。CR0 exitingからVM exitに変更されていない場合には、読み出しは常に可変ビットの現行値と固定ビットに基づく値を返します。

CR0レジスターの内容について説明する表です。

CR0ビット 固定値 ビット 意味内容
PE 1 0 保護有効: 常にプロテクト・モードとなる。
MP 1 1 コプロセッサーの監視: 常に有効となる。
EM 0 2 FPエミュレーション。
TS 3 タスク・スイッチ。FPU無効。このビットは依然として可変である。
ET 1 4 拡張タイプ(入力は無視される)。※6
NE 1 5 数値演算エラー。
WP 16 書き込み禁止ページ・テーブル。このビットは依然として可変である。
AM 18 RFLAGS.ACによるアライメント・チェック有効となる。
NW 0 29 キャッシュ・ライト・スルーは常に無効である。
CD 30 キャッシュ無効。このビットは依然として可変である。
PG 1 31 ページングは常に有効である。

図1. CR0レジスター

3.9.2 固定されたCR4ビット

図2に示すCR4レジスター内の固定ビットは以下の通りです。これらのために、いかなる他の値(VMEの任意の値を除く)を書き込むと、CR4 exitingからのVM-exitという結果でなければ#GP(0)例外が生成されます。

CR4レジスターの内容について説明する図です。

CR4ビット 固定値 ビット 意味内容
VME 0 0 仮想86モードをサポートしない(入力は無視する)。
PVI 0 1 プロテクト・モード仮想割り込みをサポートしない。
PAE 1 5 8バイトPTE。常に64ビット・モードが有効となる。

図2. CR4レジスター

3.9.3 固定されたEFERビット

表2にEFER MSR内の固定されたビットのリストを示します。他の値をEFERに書き込むと#GP例外を生成しますが、LMAは対象外で無視されます。

表2. 固定されたEFERビット

EFERビット 固定値 ビット 意味内容
SCE 1 0 SYSCALLは常に有効となる。
LMA 1 8 常にロング・モード、しかし変更は無視される。
LME 1 10 常にロング・モードとなる。
NXE 1 11 ページ・テーブルにあるNXビットは常に有効となる。

3.9.4 旧式のRFLAGS

図3にRFLAGレジスターのビットを示します。IOPL、VM、VIF、およびVIPビットは常にゼロです。表3の規則が適用されます。

図3. RFLAGSレジスター

RFLAGSレジスターの内容について説明する図です。

表3. 旧式のRFLAGSの振る舞い

操作 newIOPL != 0における操作 newVIF != 0またはnewVIP != 0における操作 newVM!=0における操作
POPF CPL3 無視 無視 無視
POPF CPL0 無視 無視 無視
SYSRET #GP(0) #GP(0) N/A (常にクリア)
IRET CPL3→CPL3 無視 無視 無視
IRET CPL0 #GP(0) #GP(0) 無視
ERETU #GP(0) #GP(0) #GP(0)
ERETS #GP(0) #GP(0) #GP(0)
VMEntry 不正なゲスト状態エラー 不正なゲスト状態エラー 不正なゲスト状態エラー
SEAMRET 不正なゲスト状態エラー 不正なゲスト状態エラー 不正なゲスト状態エラー
RSM 強制的に0 強制的に0 強制的に0

3.9.5 旧式のステータス・レジスター命令

LMSW命令は削除され、#UDフォルトを引き起こします。

3.9.6 リング3 入出力ポート命令の削除

(もうこれ以上)ユーザー・モードにおける入出力ポートへのアクセスの構想はありません、そしてリング3でINB/INW/INL/INQ/OUTB/OUTW/OUTL/OUTQを使用すると常に#GP(0)例外につながります。その#GP(0)チェックはVM実行チェックまたは入出力許可ビットマップのチェックの前に行われます。これは入出力許可ビットマップからのロードを全く行わないということを含意します。

3.9.7 ストリング入出力命令の削除

INS/OUTSはサポート外となり、#UD例外を引き起こします。この対象にはINS/OUTS命令のREPありを含みます。

3.10 64ビットSIPI

64ビットSIPIはアーキテクチュラル・パッケージ・スコープIA32_SIPI_ENTRY_STRUCT_PTR MSRを定義し、これにはメモリー上のエントリー構造体へのフィジカル・ポインターが含まれます。

これは64ビット・ページ化モードにおいてAP※7を起動するために、64ビットのスタートアップ・シーケンスが使用します。64ビットSIPIがIA32_SIPI_ENTRY_STRUCT_PTR MSRおよびMSRがポイントするメモリー上のエントリー構造体機能ビットによって有効にされた後に、X2APIC ICRレジスターを通じてINITまたはSIPIメッセージをトリガーとしてCPUが起動します。従来型のINIT/SIPIはサポートしません。64ビットSIPIの存在はCPUID機能ビットのSIPI64で示されます。

3.10.1 IA32_SIPI_ENTRY_STRUCT_PTR

SIPIメッセージを受け取った後の、表4で示す IA32_SIPI_ENTRY_STRUCT_PTRパッケージ・スコープMSRがターゲットCPUの実行コンテキストを定義します。これはメモリー上のエントリー構造体をポイントしています。BIOS_DONE MSRビットをセットした後のMSRは読み出し専用です。

表4. IA32_SIPI_ENTRY_STRUCT_PTR MSR

ビット フィールド 属性 初期値 内容説明
63:MAXPA 予約 NA 0
MAXPA:12 SIPI_ENTRY_STRUCT_PTR RW 0 SIPI_ENTRY_STRUCTへのフィジカル・ポインター
11:1 予約 NA 0
0 ENABLED RW 0 64ビットSIPI有効

INITの後に、ERETS/ERETU/IRETによって明示的にブロックが解除されるまでNMIはブロックされます。

SIPIを受け取ると、ターゲットCPUはエントリー構造体からレジスター状態をロードして、指定されたRIPから実行を開始します。INIT/SIPI IPIメッセージのベクター・フィールドで提供されたベクターは無視します。また、SIPI_ENTRY_STRUCTにおけるどのような整合性検査の失敗も、ターゲットCPUにおけるシャットダウンにつながります。

3.10.2 SIPI_ENTRY_STRUCTの定義

表5に示すエントリー構造体メモリー・テーブルは、SIPIを受け取ったCPUの実行コンテキストを定義します。

表5. SIPI_ENTRY_STRUCT メモリー内の構造体

オフセット サイズ RW 名称 内容説明
0 8 R FEATURES Bit 0 – 有効ビット (0 – シャットダウン)。その他のビットは予約。
8 8 R RIP SIPIの後に実行する新しい命令ポインター。新しいCR4における有効値。
16 8 R CR3 新しいCR3の値。新しいCR4.PCIDEと整合し、予約ビットはセットしてはならない。
24 8 R CR0 新しいCR0の値。変更不可ビットは固定値と一致していなければらなず、そしてどのような予約ビットもセットしてはならない。
32 8 R CR4 新しいCR4の値。変更不可ビットは固定値と一致していなければならない。新しいCR3、新しいRIP、新しいCR0と整合していなければならず、そして予約ビットはセットしてはならない。

3.10.3 非ブロック状態でINITを受け取った場合における疑似コード

IF ゲスト・モード中 THEN
      トリガーを抜ける
FI
IF IA32_SIPI_ENTRY_STRUCT_PTR.ENABLED = 0 THEN
      シャットダウン // 非X86-Sでは従来のINITに戻る
FI
RFLAGS = 2 # RFLAG内の変更可能ビットをすべてクリアする
CR2/CR3/CR4の可変ビットをクリアする
CR0のTSとAMビットをクリア、CR0.CDを保護する # 残りは固定値
CS/SS/DS/ES/FS/GS/GDTR/IDTR/LDTR/TSセレクターに0かつP=1、W=1をセットする
IDTR/TS/GDTR/LDTRのlimitに0にセットする
FS/GSのbaseをクリアする
KERNEL_GS MSRをクリアする
RDXに0x000n06xxx(nは拡張モデル値、xはステッピング番号)をセットする
その他すべてのGPRをクリアする
DR0/DR1/DR2/DR3をクリアする
DR6に0xffff0ff0をセットする
DR7に0x400をセットする
x87 FPU制御ワードに0x37fをセットする
x87 FPUステータス・ワードに0をセットする
x87 FPUタグ・ワードに0xffffをセットする
全てのTLBをフラッシュする
IF IA32_APICBASE.BSP = 1 THEN
      リセットのように64ビットSupervisorモードを強制する
      リセットからのCR3値を使用して64ビットのリセット・ベクターを実行する
ELSE
      SIPI状態待ちに入る
FI

3.10.4 SIPIを受け取った場合の疑似コード

IF IA32_SIPI_ENTRY_STRUCT_PTR.ENABLED = 0 THEN
    シャットダウン // 非X86-Sでは従来のSIPIに戻る
FI
// 範囲レジスターと許可を尊重する通常のリング0として、以下のメモリー読み出しはフィジカルとして完了する
TDXではないMKTMEキー
ENTRY_STRUCT = IA32_SIPI_ENTRY_STRUCT_PTR[12:MAXPA]
IF ENTRY_STRUCT->FEATURES != 1 THEN
    トリプル・フォルトではないシャットダウン // 非X86-Sでは従来のSIPIに戻る
FI
# これらにはチェック事項が定義されていないことに注意すること
newCR4 = ENTRY_STRUCT->CR4 # entry_struct.CR4から読む
newRIP = ENTRY_STRUCT->RIP # entry_struct.RIPから読む
newCR0 = ENTRY_STRUCT->CR0 # entry_struct.CR0から読む
newCR3 = ENTRY_STRUCT->CR3 # entry_struct.CR3から読む
IF newCR4.VME != 0 OR newCR4.PVI != 0 OR newCR4.DE != 1 OR newCR4.PSE != 0
  OR newCR4.PAE != 1 OR newCR4.UMIP != 1 OR
  newCR4の予約ビットがセットされている OR
  newCR0.PE != 1 OR newCR0.MP != 1 OR newCR0.EM != 0 OR
  newCR0.NE != 1 or newCR0.NW != 0 OR
  newCR0.PG != 1 OR
  newCR4.PCIDEに関連してnewCR3の予約ビットがセットされている OR
  newCR4.LA57に関連してnewRIPがキャノニカルではない THEN
    停止不可能なシャットダウン
FI
CR4 = newCR4 ; CR3 = newCR3 ; CR0 = newCR0
受け付けたSIPIベクターをゼロ拡張してR10へ代入する
64ビットSupervisorモードを強制する
NMIをブロックする
RIP = newRIP

3.11 ファームウェア・インターフェース・テーブルを通じた64ビットのリセット

リセット後にCPUは64ビット・ページ化モードで実行を開始します。ファームウェア・インターフェース・テーブル(Firmware Interface Table : FIT)のリセット状態構造体はRIPとCR3を含むCPUの初期実行状態を定義します。

3.12 固定MTRRの削除

今後は固定MTRRをサポートしません。固定ビット、IA32_MTRRCAPレジスター内のbit[8]はクリアーされ、すべてのMTRR_FIX_* MSRは実装されません。MTRR_DEF_TYPE bit[10]は予約されます。

表6に固定MTRR MSRから削除された内容を示します。

表6. 削除されたMTRR MSR

対象
IA32_MTRR_FIX64_00000
IA32_MTRR_FIX16_80000
IA32_MTRR_FIX16_a0000
IA32_MTRR_FIX4_c0000
IA32_MTRR_FIX4_c8000
IA32_MTRR_FIX4_d0000
IA32_MTRR_FIX4_d8000
IA32_MTRR_FIX4_e0000
IA32_MTRR_FIX4_e8000
IA32_MTRR_FIX4_f0000
IA32_MTRR_FIX4_f8000

3.13 XAPICとExtINTの削除

X2APICへアクセスする唯一の方法はMSRを経由したアクセスです。仮想XAPICはVMXを経由して依然としてサポートされます。

CPUは常にX2APICモード(IA32_APIC_BASE[EXTD]が1)で、そして有効です。APICを無効にするため、またはX2APICモードを離脱するために、IA32_APIC_BASEへ書き込みを試みると#GP(0)例外を引き起こします。

これはIA32_XAPIC_DISABLE_STATUS[LEGACY_XAPIC_DISABLED] MSRビットを1にすることを通じてソフトウェアに示します。

さらに詳しい内容についてはこちらを参照してください:https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/cpuid-enumeration-and-architectural-msrs.html

ローカルAPIC内のExtINTデコードは削除されました。ExtINTエンコードで割り込みが通知されると、それはAPICエラー・ステータス・レジスターのビット6をセットすることでエラー通知とするトリガーとなります。これはビット6の意味について若干の再定義をすることになります。

3.14 4L/5Lページング・スイッチ

4Lと5Lページングの切り替えは、2スレッドスコープのMSR: CR3_LOAD_4LPGTBLおよびCR3_LOAD_5LPGTBLを使用します。これはCR3へのロードと同じように作用し、CR3と同じレイアウトを持っていますが、CR4.5Lビットをセットまたはクリアするという副次的な効果があります。これが読み出されるとき、MSRは常にCR3の値を返します。この切り替えMSRは、VMXロード/ストア・リストまたはMSRリスト命令によって禁止することができます。

CR3_LOAD_4LPGTBLとCR3_LOAD_5LPGTBLの両方は、CPUが5レベル・ページ・テーブルのサポートを示すLA57 CPUID機能ビットおよび将来のCPUIDフィールド内のLA57SWITCH CPUID機能ビットが報告される場合に限って使用することができます。

3.15 仮想化の変更

このセクションでは仮想化状態の変更について説明します。

“固定”フィールドは整合性が確認され、もし固定値と一致しないとVM entryは失敗します。

3.15.1 VMCSゲスト状態

ゲストVMCSフィールドの変更点を表7に示します。

表7. VMCSフィールドの変更点 (ゲスト状態)

VMCSフィールド 変更点 理由
ゲストのアクティビティー状態中のWFSエンコード 0固定 64ビットSIPIをサポートしていない。

3.15.2 VMCS Exit制御

VM Exit制御の変更点を表8に示します。

表8. VMCS Exit制御の変更点

VMCSフィールド 変更点 理由
ホスト・アドレス空間サイズ
(Host Address Space Size: HASS)
1固定 ホストは常に64ビットSupervisorモードであるため。
IA32モードのゲスト 1固定 ゲストは常にロング・モードであるため。

3.15.3 VMCSセカンダリー・プロセッサーベースの実行制御

変更点を表9に示します。

表9. セカンダリー・プロセッサーベースの実行制御の変更点

VMCSフィールド 変更点 理由
無制限ゲスト 0固定 無制限ゲストをサポートしないため。

3.15.4 VMX関連MSR一覧

表10にVMX関連MSR一覧の変更点を示します。

表10. VMX関連MSRの変更点

MSR ビット 対応フィールド 注記
IA32_VMX_EXIT_CTLS 9, 41 ホスト・アドレス空間サイズ 1 EFER LMEとLMAは1に固定される。
IA32_VMX_TRUE_EXIT_CTLS
IA32_VMX_PROCBASED_CTLS2 39 無制限ゲスト 0 非無制限ゲスト。
IA32_VMX_MISC 8 アクティビティー状態のサポート:SIPIの待機 0 サポートしない。
IA32_VMX_CR0_FIXED0 0 PE: プロテクト・モード有効 1
(レガシー)
常にロング・モードでレガシーFPUモードではない。0に固定。※8
1 MP: コプロセッサーの監視 1
5 NE: 数値演算エラー 1
(レガシー)
31 PG: ページ化有効 1
(レガシー)
IA32_VMX_CR0_FIXED1 2 EM: FPエミュレーション 0 これらのCR0ビットは0に固定。
29 NW: ライト・スルーではない 0
IA32_VMX_CR4_FIXED0       変更なし。
IA32_VMX_CR4_FIXED1 1 PVI: プロテクトモード仮想割り込み 0 プロテクトモード仮想割り込みはサポートしない。

3.16 削除対象のまとめ

表11に削除対象のまとめについて示します。

表11. 削除対象のまとめ

削除対象 代替 暗黙的な意味
32ビット・モードにおけるセグメントbase(FS/GS/GDT/IDT/LDT/TSSを除く)、limit(GDT/IDT/TSS/LDTを除く) 限定されたセグメンテーション
リアル・モード(ビッグおよび16ビット) 64ビット・ページ化モード、64ビットSIPI
16ビット・プロテクト・モード
他のモードにおいてアドレスを参照するときの16ビット・アドレス・オーバーライド
32ビットのリング0に含まれる2または3レベル・ページ化モード 64ビット・リング0
CR0.MPを通じたFPUの無効化
レガシー数値エラーの取り扱い
仮想86モード 16ビット・モードの削除
プロテクトモード仮想割り込み(PVI: Protected-mode Virtual Interrupts)
クリアすることでページ・テーブル・エントリーのNXビットを無効にするために存在しているEFER.NXEの無効化
EFER.SCEを通じたSYSCALLの無効化
FAR jumpによるリングの変更 SYSCALL、INT 限定されたセグメンテーション
IRET/SYSCALL/SYSRETによる16ビット・モード、仮想86モードまたはコンフォーミング・セグメントへの遷移 16ビット・モードの削除および限定されたセグメンテーション
固定MTRR 可変MTRRおよびページ・テーブル内のPAT
MMIOベースのXAPICアクセス MSRを通じたX2APICへのアクセス
APICのExtINTの削除
リング1、リング2の削除
リング3による入出力ポートへのアクセス(IOPL、(TSS32の)入出力ビットマップ) リング0による入出力ポートへのアクセス
INSおよびOUTS命令 ループに対応したINおよびOUT命令
#SS例外 #GP(0)例外 限定されたセグメンテーション
#NP例外 #GP(0)例外 限定されたセグメンテーション
VMCS有効時のINIT/SIPIサポート 64ビット SIPI
VMCSにおける無制限ゲストのサポート 16ビット・モードの削除、ページ化は常に有効
VMCSによる32ビット・リング0のサポート 32ビット・リング0の削除

3.17 追加事項のまとめ

アーキテクチャーへ新たに追加する内容を表12に示します。

表12. 追加事項のまとめ

追加内容 理由 要求事項
64ビットのSIPIとINIT 64ビット・ページ化モードにおけるAPの起動 リアル・モードの削除
MSRによる4L/5Lページング・スイッチ リアル・モード以外 リアル・モードの削除

3.18 変更された命令

以下の解説は命令の新しい振る舞いのみに関係します。セグメンテーションに関連する命令についてのより長いリストは変更された振る舞いが、もしあればセクション4.3に示されています。細かな変更に伴う命令が概要に記録されるのみです。これまでの振る舞いについては「Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D and 4.」を参照ください。

3.18.1 SYSRET

SYSRETによってゼロではない値がRFLAGS.IOPL、RFLAGS.VIP、またはRFLAGS.VIFにロードされると#GP(0)例外が生成されます。

3.18.2 IRET

IRETは16ビット・モード、タスク・ゲートまたはコンフォーミング・セグメントにジャンプすることはできません。IRETによって、リング0においてゼロではない値をRFLAGS.IOPL、RFLAGS.VIP、またはRFLAGS.VIFにロードをすると#GP(0)例外を生成します。IRET命令の詳細については、セクション4.2.6の疑似コードによって示しています。

3.18.3 POPF – スタックからRFLAGSレジスターへ

オペコード 命令 Op/ En 64ビット・モード コンパチビリティー/レガシー・モード 内容説明
9D POPFD ZO 実行不可※9 有効 スタックの先頭からPOPしてEFLAGSへ代入
9D POPFQ ZO 有効 実行不可 スタックの先頭からPOPしてゼロ拡張をしてRFLAGSへ代入

POPFは現在のオペランド・サイズ属性が32ビットであれば、先頭からDWORD(POPFD)をポップし、ELFAGSレジスターに値を保存します。また、スタックのオペランド・サイズ属性が16ビットであれば、(先頭からWORD※10でポップし)それをEFLAGSレジスターの下位16ビットに保存します(すなわち、それはFLAGSレジスターです)。これらの命令はPUSHF/PUSHFD/PUSHFQ命令の操作を逆転させるものです。

IOPL、VM、VIP、およびVIF フラグは常にゼロであり、POPでは無視されます。

POPF命令は#SS例外を決して引き起こしません、#GP(0)または#PF例外のみです。

表13に変更されたRFLAGSを示します。

表13. POPF命令によるRFLAGSの変更

モード オペラント・サイズ CPL フラグ
21 20 19 18 17 16 14 13:12 11 10 9 8 7 6 4 2 0
ID VIP VIF AC VM RF NT IOPL OF DF IF TF SF ZF AF PF CF
User32、User64およびSupervisorモード 32、64 * S N N S N 0 S N S S N S S S S S S
キー
S スタックからの更新
N 値は変更しない
0 値はクリアされる

疑似コード:

tempFlags = POP // 32/64ビットのオペランド・サイズに従う
IF CPL = 0 THEN
    // RF、IOPL、VIP VIF、VMを除き、“tempFlags”から予約されたフラグ以外を変更する。
    // RFはクリアする。
    // オペランド・サイズによってPOPされないフラグは変更してはならない。
ELSE
    // RF、IOPL、VIP VIF、VM、IFを除き、“tempFlags”から予約されたフラグ以外を変更する。
    // RFはクリアする。
    // オペランド・サイズによってPOPされないフラグは変更してはならない。
FI

表14に削除された命令のまとめを示します。

表14. 削除された命令

命令 使用することができるレガシーにおけるリング 代替
INS/OUTS リング3、1、2、0 IN、OUT
0x67プリフィクスを伴う64ビットの間接ジャンプは#UDとなる。
0x67プリフィクスを伴う32ビットNEAR RET、FAR CALL、FAR RET、FAR JMPは#UDとなる。
0x67プリフィクスを伴う32ビットNEAR JMP、各種条件ジャンプ、JECX*、NEAR RET、NEAR CALL、各種LOOP、FAR JMPは#UDとなる。
0x67プリフィクスを伴うジャンプ以外のメモリーの参照を伴う全ての32ビット命令は#GPとなる。
リング3、1、2、0 32ビット/64ビットのメモリー参照
LMSW リング3、1、2、0※11 MOV CR0

3.19 変更された命令のまとめ

表15に変更された命令のまとめを示します。

表15. 命令の変更

命令 リング 変更
ERETU 0 16ビット・モードまたは仮想86モードまたはゲートをサポートしない。限定されたセグメンテーション設計。RFLAGSの取り扱いの変更。
ERETS 0 RFLAGSの取り扱いの変更。
IRET 3、0 16ビット・モードまたは仮想86モードまたはゲートをサポートしない。限定されたセグメンテーション設計。RFLAGSの取り扱いの変更。
SYSRET 0 RFLAGSの取り扱いの変更。
SYSEXIT 0 RFLAGSの取り扱いの変更。
FAR CALL 3、0 限定されたセグメンテーション設計。0x66プリフィクスは#UD。32ビット・モードおよび間接における0x67であれば#GP。
FAR JMP 3、0 限定されたセグメンテーション設計。0x66プリフィクスは#UD。32ビット・モードにおける0x67であれば#GP。
POPF 3、0 RFLAGSの取り扱いの変更。
FAR RET 3、0 限定されたセグメンテーション設計。0x66プリフィクスは#UD。
STI 3、0 VM86/PVI/IOPLを経由したリング3による変更はサポートしない。
CLI 3、0 VM86/PVI/IOPLを経由したリング3による変更はサポートしない。
ARPL、VERW、VERR、セレクターへMOV、セレクターからMOV、PUSHセレクター、POPセレクター、LAR、LGS、LFS、LES、LFS、LGS、LSS、LDS、LKGS 3、0 限定されたセグメンテーション設計。
IN*、OUT* 3 リング3における入出力ポートの廃止。
JMP short、JMP、LOOP、JECX、CALL、RET、JMP 3、0 32ビット・モードにおける0x66プリフィクスであれば#UD。

3.20 ソフトウェアの互換性に関する注記

3.20.1 リング3における入出力ポートへのアクセスのエミュレーション

TSS入出力ポート・ビットマップを使用するリング3入出力ポート・アクセスあるいはIOPLによるレガシー用途であれば、カーネルにおいて#GP(0)ハンドラーを通じて入出力をエミュレートすることが可能です。#UDハンドラーにて、適切なエミュレーション・ルーチンにおいてINS/OUTSをエミュレートすることができます。

3.20.2 64ビットSIPI

制御をOSに渡すまでは、BIOSはSIPI_ENTRY_STRUCT ENABLESフィールドにおいて常に64ビットSIPIを無効にすべきです。レガシー・アーキテクチャーでは、これがレガシーOSとレガシーSIPIを使用することを確実にします。64ビットのSIPIに依存しているOSが有効にすることができます。X86-Sでは、レガシーSIPIを使用することはできませんが、OSは整合性のために64ビットSIPIを有効にすることを選択できます。

制御をOSへ移行する前に、BIOSはすべてのパッケージでIA32_SIPI_ENTRY_STRUCT_PTRがSIPI_ENTRY_STRUCTを指し示すと常に想定することができます。

3.20.3 レガシーOSの仮想化

VMMはVM Exitの失敗がVMMによるレガシーの振る舞いのエミュレートが必要となる場合のために、適切にシステム状態とVMCSをセットアップすることに責任があります。VMMがVM entryを実行することを試みることがない場合もありますが、サポートされたゲスト状態に到達するまで、代わりにエミュレートを行います。

  • システムとVMCS状態
    • 固定値のために予約されたすべてのフィールドのためにCR0とCR4のマスクを設定する。
    • 無条件I/O exitingは、IOPL変更のために1をセットする。
    • 無制限ゲストは0をセットする。
  • VM Enrtyの要求事項
    • ゲストの状態
      • アクティビティー状態: WFSの用意はできていない。これはVM Entryの際に整合性の確認が行われる。
      • CR0: 以下で説明されるようにフィールドを設定する必要がある。エミュレーションまたは別の方法としてシャドウ・ページ・テーブルを伴う実行が必要とされる。
        • PE=1
        • EM=0
        • NE=1
        • PG=1
      • CR4: 全ての16ビット・モードはエミュレーションを必要とする。VMEはクリアでなければならない。
      • EFER: LME/LMAは1をセットされなければならない。
      • RFLAGS: VMはクリアされなければならない。
    • セカンダリー・プロセッサー・ベースの実行制御。無制限ゲスト = 0(無制限ゲストをサポートしない)
    • 終了制御。ホスト・アドレス空間(HASS) = 1(ホストは常に64ビットでCPL0)
  • エミュレーション
    • フラットではないセグメント(FS/GS baseを除く)
    • リアルおよび仮想8086モード

ゲストが互換性を必要とするのであれば、VMMには(a)例外ビットマップを設定し、これによる#UDと#GPがVM Exitを引き起こし、(b)例外と適切な応答の原因を確定させるためにエミュレートをする責任があります。いくつかの例:

  • いくつかの異なるCLIが#GP(0)を引き起こす。例えば、レガシー・ゲストがリング3かつRFLAGS.IOPL==3でCLIを実行することを試みた場合。RFLAGS.IOPLは常に0、そしてリング3であるため、CLIは常に#GP(0)となる。ゲストがこれらのIOPLの作用を必要とするのであれば、レガシー・ゲストのRFLAGS.IOPLの値でこの命令をエミュレートするかどうかはVMMによる。これが後で述べるゼロではないIOPLの仮想化できない側面であることに注意すべきである。
  • #SSと#NPは#GPへと変換される。ゲストが#SS/#NPを検出すると予測される場合には、VMMは#GPの実態が#SSか#NPかを判断し、ゲストに対してそれらを注入する必要がある。

いくつかのゲストのCR値はVMENTRYにおいて無視されます(それは固定値のある、一貫性が確認されていないものです)。ゲストが必要とするなら、VMMはこの違いを仮想化することができます。それらについては以下で説明します。一般に、Intel 64ゲストとしてはこれらは珍しいと予想します。

  • CR0.MPは1に固定されている。
    • VMMは偽フォルトの内容を分析してエミュレートすべきである。
  • CR4.PVIは0に固定されている。
    • VMMはSTI/CLIによる#GPを分析して、ゲストが想定する振る舞いをエミュレートすることができる。
  • CR4.DEは1に固定されている。
    • VMMは偽フォルトの内容を分析してエミュレートすることができる。
  • CR4.PSEとCR4.PAEは固定されている。レガシー・ページ化モードはシャドウ・ページングまたはエミュレーションを必要とする。
  • EFER.LME: LMEは1に固定されている。ゲストが32ビットのCPL0モードであり、VMMがVMentryをすることを求めるのであれば、それはエミュレーションを使用すべきである。
  • RFLAGS:
    • IOPLは0に固定されている。
    • VIF、VIPは0に固定されている。これに関連していくつかのCLI/STIは#GP(0)となる。ゲストがこの機能を必要とするのであれば、適切にこれらを扱うためにエミュレートすることができる。

VMMは必要に応じてレガシーの機能をエミュレートすることを選択することができます:

  1. メインストリームのIntel64ゲストがレガシーSIPIまたは非64ビットによる起動を使用するのであればVMMの変更が必要である。
    1. 16ビット・モードのエミュレート(リアル・モード、仮想8086モード)
    2. 非ページ化モードのエミュレート
    3. レガシーINIT/SIPIのエミュレート
  2. 珍しいケースを取り扱うための任意のVMMの変更
    1. IOPL != 0(ゲストがリング3で入出力ポートへのアクセスあるいはリング3でCLI/STIの実行を想定している場合)
      1. CPL3におけるCLI #GPをキャッチしてエミュレートする。
      2. CPL3におけるSTI #GPをキャッチしてエミュレートする。
      3. CPL3におけるIN/OUT #GPをキャッチしてエミュレートする。
      4. CPL0におけるIRETによってIOPLを変更することを試みると発生する#GPをキャッチしてエミュレートする。
      5. 次のセクションで説明する、ゼロではないIOPLの仮想化できない側面があることに注意すること。
    2. INS/OUTS命令の削除: #UDをキャッチしてエミュレートする。
    3. コール・ゲート: VMMは関連する#GPをキャッチしてエミュレートする必要がある。
    4. #SSの削除: VMMは関連する#GPをキャッチしてゲストに#SSとして通知することができる。
    5. #NPの削除: VMMは関連する#GPをキャッチしてゲストに#NPとして通知することができる。
    6. CR4.PVIは関連する#GPをキャッチしてエミュレートする。
    7. 16ビット・アドレッシングによる#GP/#UDをキャッチしてエミュレートする。
    8. CR4.VME、RFLAGS.VM: 仮想8086モードのエミュレートをする。
    9. 32ビット・リング0のエミュレートと、レガシー・ページ化モードにおけるシャドウ・ページングを伴った32ビット・リング3の実行。
    10. サポートされていない下方伸長のようにあまり知られていないセグメンテーションの機能または非コンフォーミング・コード・セグメント※12のサポート: #GPをキャッチすることでエミュレートすることができる。
  3. 処理コストのかかる切り替え対策が必要な珍しいケース:
    1. CPL1/2は部分的なエミュレーションを必要とする。
    2. フラットではないCS/DS/ES/SSセグメントまたはメモリー内のディスクリプターのアクセス・ビットの設定は、Descriptor Table ExitingとGDT/LDT limitにゼロを設定(またはGDT/LDT読み出し/書き込み保護)することをトリガーとしてセグメンテーション命令をキャッチする、完全なエミュレーションを必要とする。
    3. EFER.NXEがクリアされているなら、PTE内のNXビットのセットはシャドウ・ページングが必要となる。
    4. ロード/ストア/実行におけるセグメンテーション権限チェック: 完全なエミュレーションを必要とするだろう。
  4. 仮想化ができないケース
    1. RFLAGS.IOPL != 0: ほとんどの場合、IOPLがゼロではないことによる振る舞いが典型的に変更されているため、代わりに#GPをVMMがキャッチ/エミュレートすることができる(すなわち、多くのケースにおいて仮想化をすることができる)。問題が発生すると思われるIntel 64のケースは以下の通りである。
      1. リング0にはIOPLを3にしてリング3に変更することができる権限がある。リング3への切り替えをPUSHFまたはSYSCALLを実行することで行う場合には、メモリーまたはレジスターの指し示す先がIOPL=3の値であることを確認しなければならない。VMがこのシーケンスを実行するとき、IOPLに3を設定するリング0の命令は#GPを引き起こしてVMExitのトリガーとなる。VMMが“間違った”IOPLとともにVMを再開するなら、例えば、IOPL==0でリング3のPUSHFまたはSYSCALLがメモリーあるいはレジスターを経由して、この不正確なIOPLを漏洩させることになるだろう。また、リング3のPOPFはIFを更新することはない。適切な枠組みは、IOPLが0に戻されるまでVMMがゲストをエミュレートすることだ。このようなケースは現代のOSでは想定されない。
      2. ゲストがリング0でPOPF命令を使用してIOPLをゼロ以上に設定することを試みると、これは警告なしで無視される。IOPLの値は更新されずに、そしてVMMは、これが起こったことを検出することはできない。後続の命令は、この値によって#GP(例えば、CLI/STI/IN/OUT)や、警告なしで異なる意味を持って実行される(例えば、POPFによるIFの更新、PUSHFによるメモリーへの書き込み、SYSCALLによるフラグのストアなど)。
    2. EFER.SCEがクリアされている時に、SYSCALL/SYSEXITを実行したときの振る舞いを#UDとする。

4 参考情報

この参考情報は限定されたセグメンテーションと例外の互換性に関する詳細に言及するものです。

4.1 セグメンテーション命令の振る舞い

説明文は命令の新しい振る舞いについて説明する目的のみであることに注意してください。これまでの振る舞いについてはSDM※13を参照してください。疑似コードには、最終的なフォルトの発生またはエラー・コードについて説明が存在していない部分があります。何かの変更がベースラインから適用されていない場合には、それには言及しません。

Check_selector(selector): // NULLであればセグメントをロードしてはならない
    IF CS AND selector is NULL THEN
        #GP(0); // あるいはVMEntry 不正なゲスト状態
    FI
    IF (selector.TI == 0 AND selectorはGDT limitを超えている) OR
      (selector.TI == 1 AND selectorはLDT limitを超えている) OR
      テーブルの中のディスクリプター・アドレスがキャノニカルではない THEN
        #GP(selector); // あるいは VMEntry 不正なゲスト状態 あるいは ZF := 0
    FI
END

Check_CS_desc(selector, Descriptor, newCPL):
    IF Descriptorは非コンフォーミング・コード・セグメントではない
      OR (Descriptor.L == 0 AND Descriptor.D == 0) // 16ビット・サイズを防ぐ
      OR Descriptor.DPL == 1
      OR Descriptor.DPL == 2
      OR Descriptor.DPL != selector.RPL
      OR Descriptor.DPL != newCPL
      OR Descriptor.L == 0 AND Descriptor.DPL == 0 THEN // SUP32を防ぐ
        #GP(selector);
    FI
    IF descriptor.P == 0 THEN
        #GP(selector);
    FI
    Descriptor.Accessed := 1 // メモリーの中ではない
    Save_descriptor_for_VMX(selector, Descriptor);
END

Check_CS_desc_for_IRET(selector, Descriptor):
    IF Descriptorは非コンフォーミング・コード・セグメントではない
      OR (Descriptor.L == 0 AND Descriptor.D == 0) // 16ビット・サイズを防ぐ
      OR Descriptor.DPL == 1
      OR Descriptor.DPL == 2
      OR Descriptor.DPL != selector.RPL
      OR selector.RPL < CPL
      OR Descriptor.L == 0 AND Descriptor.DPL == 0 THEN // SUP32を防ぐ
        #GP(selector);
    FI
    IF descriptor.P == 0 THEN
        #GP(selector);
    FI
END

// newModeは現在のモードまたはVMCS/SMM状態からのモード
Check_Data_desc(selector, Descriptor, newMode):
    IF selectorはNULLではない THEN
        IF selectorはGDT/LDT limitを超えている // これはVMEntry/RSMには適用されない
          OR Descriptorはデータではない、あるいは読み出し可能な非コンフォーミング・コード・セグメントではない
          OR Descriptor.DPL == 1
          OR Descriptor.DPL == 2
          OR Descriptor.DPL < selector.RPL
          OR Descriptor.DPL < CPL THEN
            #GP(selector); // あるいは VMEntry 不正なゲスト状態 あるいは ZF := 0
        FI
        IF descriptor.P == 0 THEN
            #GP(selector); // あるいは VMEntry 不正なゲスト状態 あるいは ZF := 0
        FI
    FI
    Descriptor.Accessed := 1 // メモリーの中ではない
    Save_descriptor_for_VMX(selector, Descriptor);
END

// newCPLは現在のCPLあるいはVMCS/SMM/IRET状態からのもの
Check_SS_desc(selector, Descriptor, newCPL):
    IF NOT (selectorはNULLかつnewCPL != 3) THEN
        IF selectorはGDT/LDT limitを超えている
          OR ((selector is NULL) AND newCPL == 3)
          OR Descriptorは書き込み不可能なデータ・セグメント
          OR Descriptor.DPL == 1
          OR Descriptor.DPL == 2
          // Descriptor.B=1は32ビット・モードにおいて最初にSSを参照すると#GP(0)につながる
          OR Descriptor.DPL != selector.RPL
          OR Descriptor.DPL != CPL THEN
            #GP(selector); // あるいは VMEntry 不正なゲスト状態 あるいは ZF := 0
        FI
        IF descriptor.P == 0 THEN
            #GP(selector); // あるいは VMEntry 不正なゲスト状態 あるいは ZF := 0
        FI
    FI
    Descriptor.Accessed := 1 // メモリーの中ではない
    Save_descriptor_for_VMX(selector, Descriptor);
END

Load_descriptor_from_GDT_LDT(selector):
    IF (selector & 0xFFF8) != 0x0 THEN
        IF selector.TI == 1 THEN BASE := LDT Base;
        ELSE BASE := GDT Base; FI;
        Desc := load_physical_sup(BASE + (selector & 0xFFF8));
        メモリーの中ではなく、Descriptorにコピーされたアクセス・ビットを立てる;
        Return Desc;
    ELSE
        Return 0;
    FI
END

Load_descriptor_from_IDT(vector):
    Desc := load physical_sup(IDT base + vector << 4);
    Return Desc;
END

4.2 セグメンテーション命令の疑似コード

4.2.1 CALL Far

FAR CALLはイントラレベル※14専用です。モード制限が強制されます。セレクターはGDT/LDT内のコンフォーミング・コード・セグメントではないディスクリプターを指し示さなければなりません。CS.accessedビットはセットしません。新しいディスクリプターはVMXで使用するために保存します。0x66プリフィクスが伴う命令は#UDとなります。0x67プリフィクスで間接かつ32ビット・モードの命令は#GP(0)となります。#NPと#SSは#GPに置き換えられます。

IF 0x66プリフィクスがある THEN #UD ; FI
IF 0x67プリフィクスがある AND 間接 AND 32ビット・モード THEN #GP(0); FI
Check_selector(newCS);
newCSdesc := Load_descriptor_from_GDT_LDT(tempCS);
Check_CS_desc(tempCS, newCSdesc, CPL);
IF newRIPはキャノニカルではない THEN
    #GP(0)
FI
Push CS;
Push RIP;
CS := newCS;
RIP := newRIP;
Save newCSdesc;
有効にされているならシャドウ・スタックにPUSHする
有効にされているなら分岐終了状態に遷移する

4.2.2 ERETU

RFLAGSの制限が強制されます。モードの制限はコード・セレクター・タイプの制限と同様に強制されます。ディスクリプターのアクセス・ビットをセットすることはありません。#NPと#SSは#GPに置き換えられます。

Intel64と同じフローで開始します。

// Intel64 FREDに関連してCS/SSがSTARに入っていることをチェックする
ELSE IF newCSはSTARに入っていない OR newSSはSTARに入っていない THEN
    Check_selector(newCS);
    newCSdesc := Load_descriptor_from_GDT_LDT(newCS);
    // 変更されたセレクターをチェックする
    Check_CS_desc_for_IRET(tempCS, newCSdesc, newCPL);
    // CS.L = 0であってもCSのためのlimitチェックがない
    newSSdesc := Load_descriptor_from_GDT_LDT(newSS);
    Check_SS_selector(new_SS, newSSdesc, newCPL);
    newCSとnewSSをロードする
FI

残りの流れはIntel64と同じです。

4.2.3 ERETS

RFLAGSの制限が強制されます。

4.2.4 FRED Entryの流れ

RFLAGSの制限が強制されます。

4.2.5 CR4.FRED ==0におけるINT n、INT3、INTO、外部割込、例外

モードの制限とディスクリプター・タイプの制限が強制されます。ディスクリプターのアクセス・ビットはセットしません。#NPは#GPに置き換えられます。

※訳注:次の疑似コードの冒頭部分には何か処理名(と場合によっては+α)が記述されていたか、冒頭処理の最後のEND;が表記上不要なものであるかのいずれかの可能性があります。


    IF INTOでCS.L = 1 THEN
        #UD;
    FI;
    IF ((vector_number « 4) + 15)がIDT.limitを超える THEN
        #GP(error_code(vector_number,1,EXT));
    FI;
    gate := Read_descriptor_from_IDT(vector_number);
    IF gate.typeがintGate64とtrapGate64のいずれでもない THEN
        #GP(error_code(vector_number,1,EXT));
    FI;
    IF ソフトウェア割り込み (* INT1には適用されない *) THEN
        IF gate.DPL < CPL THEN
            #GP(error_code(vector_number,1,0));
        FI;
    FI;
    IF gate.P == 0 THEN
        #GP(error_code(vector_number,1,EXT));
    FI
    newCS := gate.selector;
    IF newCS is NULL THEN
        #GP(EXT); (* エラー・コードにはNULLセレクターが含まれる *)
    FI;
    Check_selector(newCS);
    newCSdesc := Load_descriptor_from_GDT_LDT(newCS);
    Check_CS_desc(newCS, newCSdesc, 0);
    IF newCSdesc.DPL < CPL THEN
        GOTO INTER-PRIVILEGE-LEVEL-INTERRUPT;
    ELSIF newCSdesc.DPL = CPL THEN
        GOTO INTRA-PRIVILEGE-LEVEL-INTERRUPT;
    ELSE
        #GP(error_code(新しいコードセグメント・セレクター,0,EXT));
    FI
END;

// 訳注:特権レベルをまたぐ割り込みの疑似コード
INTER-PRIVILEGE-LEVEL-INTERRUPT:
    IF gate.IST == 0 THEN
        TSSstackAddress := (newCSdesc.DPL « 3) + 4;
    ELSE
        TSSstackAddress := (gate.IST « 3) + 28;
    FI;
    IF (TSSstackAddress + 7) > TSS.limit THEN
        #TS(error_code(TSS.selector,0,EXT);
    FI;
    NewRSP := (TSS.base + TSSstackAddress)から8バイトをロード;
    NewSS := newCSdesc.DPL; (* RPL = new CPLであるNULLセレクター *)
    IF gate.IST = 0 THEN
        NewSSP := IA32_PLi_SSP; (* i = newCSdesc.DPLの場合 *)
    ELSE
        NewSSPAddress := IA32_INTERRUPT_SSP_TABLE_ADDR + (gate.IST « 3);
        IF ShadowStackEnabled(CPL0) THEN
            NewSSP := NewSSPAddressから8バイトをロード;
        FI;
    FI;
    IF NewRSPはキャノニカルではない THEN
        #GP(EXT); (* エラー・コードにはNULLセレクターが含まれる *)
    FI;
    IF gate.IPはキャノニカルではない THEN
        #GP(EXT); (* エラー・コードにはNULLセレクターが含まれる *)
    FI;
    RSP := NewRSP & FFFFFFFFFFFFFFF0H;
    SS := NewSS;
    SSdesc := const;
    Push(SS);
    Push(RSP);
    Push(RFLAGS); (* 8バイトのプッシュ *)
    Push(CS);
    PUSH(RIP);
    Push(ErrorCode); (* 必要なら8バイト *)
    RIP := gate.RIP;
    CS := newCS;
    IF ShadowStackEnabled(CPL) AND CPL == 3 THEN
        IA32_PL3_SSP := LA_adjust(SSP);
    FI;
    CPL := newCSdesc.DPL;
    CS.RPL := CPL;
    IF ShadowStackEnabled(CPL) THEN
        oldSSP := SSP
        SSP := NewSSP
        IF (SSP & 0x07 != 0) THEN
            #GP(0);
        FI
        IF (CS.L = 0 AND SSP[63:32] != 0) THEN
            #GP(0);
        FI
    FI;
    expected_token_value := SSP; (* busyビットはクリアであるに違いない *)
    new_token_value := SSP | BUSY_BIT; (* busyビットをセットする *)
    IF (shadow_stack_lock_cmpxchg8b(SSP, new_token_value,
      expected_token_value) !=
      expected_token_value) THEN
        #GP(0);
    FI;
    IF oldSS.DPL != 3
        ShadowStackPush8B(oldCS);
        ShadowStackPush8B(oldRIP);
        ShadowStackPush8B(oldSSP);
    FI;
    IF EndbranchEnabled (CPL)
        IA32_S_CET.TRACKER = WAIT_FOR_ENDBRANCH;
        IA32_S_CET.SUPPRESS = 0
    FI;
    IF gate.typeはintGate64 THEN
        RFLAGS.IF := 0 (* 割り込みフラグに0を設定し、割り込みを禁止する *);
    FI;
    RFLAGS.TF := 0;
    RFLAGS.RF := 0;
    RFLAGS.NT := 0;
END;

// 訳注:特権レベルをまたがない割り込み
INTRA-PRIVILEGE-LEVEL-INTERRUPT:
    NewSSP := SSP;
    CHECK_SS_TOKEN := 0;
    IF gate.IST != 0 THEN
        TSSstackAddress := (IDT-descriptor IST « 3) + 28;
        IF (TSSstackAddress + 7) > TSS.limit THEN
            #TS(error_code(現在のTSSセレクター,0,EXT));
        FI;
        NewRSP := (current TSS base + TSSstackAddress)から8バイトをロード;
    ELSE
        NewRSP := RSP;
    FI;
    IF ShadowStackEnabled(CPL) THEN
        NewSSPAddress := IA32_INTERRUPT_SSP_TABLE_ADDR + (IDT gate IST « 3)
        NewSSP := NewSSPAddressから8バイトをロード
        CHECK_SS_TOKEN := 1
    FI;
    IF NewRSPはキャノニカルではない THEN
        #GP(EXT); (* エラー・コードにはNULLセレクターが含まれる *)
    FI;
    IF gate.RIPはキャノニカルではない THEN
        #GP(EXT); (* エラー・コードにはNULLセレクターが含まれる *)
    FI;
    RSP := NewRSP & FFFFFFFFFFFFFFF0H;
    Push(SS);
    Push(RSP);
    Push(RFLAGS); // 8バイトをプッシュ、これにはIFを含み、IOPLとCPLは影響しない
    Push(CS);
    PUSH(RIP);
    Push(ErrorCode); (* 必要なら8バイト *)
    oldCS := CS;
    oldRIP := RIP;
    RIP := gate.RIP;
    CS := newCS;
    CS.RPL := CPL;
    IF ShadowStackEnabled(CPL) AND CHECK_SS_TOKEN == 1 THEN
        IF NewSSP & 0x07 != 0 THEN
            #GP(0);
        FI;
        IF (CS.L = 0 AND NewSSP[63:32] != 0) THEN
            #GP(0);
        FI;
        expected_token_value := NewSSP (* busyビットはクリアであるに違いない *)
        new_token_value := NewSSP | BUSY_BIT (* busyビットをセットする *)
        IF shadow_stack_lock_cmpxchg8b(NewSSP, new_token_value,
          expected_token_value) !=
          expected_token_value THEN
            #GP(0);
        FI;
    FI;
    IF ShadowStackEnabled(CPL) THEN
        (* 次の8バイト境界に調整する *)
        tempSSP = SSP;
        Shadow_stack_store 4 bytes of 0 to (NewSSP − 4)
        SSP := newSSP & 0xFFFFFFFFFFFFFFF8H;
        ShadowStackPush8B(oldCS);
        ShadowStackPush8B(oldRIP);
        ShadowStackPush8B(tempSSP);
    FI;
    IF EndbranchEnabled (CPL)
        IF CPL == 3 THEN
            IA32_U_CET.TRACKER = WAIT_FOR_ENDBRANCH;
            IA32_U_CET.SUPPRESS = 0;
        ELSE
            IA32_S_CET.TRACKER = WAIT_FOR_ENDBRANCH;
            IA32_S_CET.SUPPRESS = 0;
        FI;
    FI;
    IF IDT gateは割り込みゲート THEN
        RFLAGS.IF := 0; (* 割り込みフラグに0を設定し、割り込みを禁止する *)
    FI;
    RFLAGS.TF := 0;
    RFLAGS.NT := 0;
    RFLAGS.RF := 0;
END;

4.2.6 IRET

IRETは16ビット・モード、仮想86モード、タスク・ゲートまたはコンフォーミング・セグメントに入ることはできません。ディスクリプターのアクセス・ビットはセットしません。モードの制限が強制されます。#NPと#SSは#GPに置き換えられます。

IF RFLAGS.NT == 1 THEN
    #GP(0);
FI
tempRIP := POP(); // オペランド・サイズに従う
tempCS := POP(); // オペランド・サイズに従う
tempFlags := POP();// オペランド・サイズに従う
IF CPL == 3 THEN
    tempFlags(VIP, VIF, IOPL) := (0, 0, 0);
ELSIF tempFlags(VIF, VIP, IOPL) != (0,0,0) THEN
    #GP(0);
FI
Check_selector(tempCS);
Descriptor := Load_descriptor_from_GDT_LDT(tempCS);
Check_CS_desc_for_IRET(tempCS, Descriptor);
IF tempCS.RPL > CPL THEN
    IF CR4.FRED THEN
        #GP(tempCS);
    ELSE
        GOTO RETURN_TO_OUTER_PRIVLEDGE_LEVEL; // レベル3であるに違いない
    FI
ELSIF Started_in_64b_mode THEN
    GOTO RETURN_FROM_IA32e;
ELSE
    GOTO RETURN_FROM_SAME_PRIVLEDGE_LEVEL;
FI

RETURN_FROM_SAME_PRIVLEDGE_LEVEL:
    IF tempRIPはキャノニカルではない THEN
        #GP(0); // RSPを元に戻す
    FI
    IF ShadowStackEnabled(CPL) THEN
        SDMで説明されているように、通常のシャドウ・スタック操作を実行する;
    FI
    CS := tempCS;
    RIP := tempRIP;
    Save_descriptor_for_VMX(CS, Descriptor);
    RFLAGS(CF, PF, AF, ZF, SF, TF, DF, OF, NT, RF, AC, IC) := tempFlags;
    IF CPL == 0 THEN RFLAGS(IF) := tempFlags; FI;
    NMIのマスクを解除する;
END;

RETURN_FROM_IA32e:
    tempRSP := POP();
    tempSS := POP();
    Check_sel(tempSS);
    tempSSdesc := Load_descriptor_from_GDT_LDT(tempSS);
    check_SS_desc(tempSS, tempSSdesc, newCPL);
    SS := tempSS;
    RSP := tempRSP;
    GOTO RETURN_FROM_SAME_PRIVLEDGE_LEVEL;

RETURN_TO_OUTER_PRIVLEDGE_LEVEL:
    IF tempCS.RPL != 3 THEN
        #GP(tempCS);
    FI
    tempRSP := POP();
    tempSS := POP();
    IF tempRIPはキャノニカルではない THEN
        #GP(0); // RSPを回復する
    FI
    CPL := tempCS.RPL;
    IF ShadowStackEnabled() THEN
        SDMで説明されているように、通常のシャドウ・スタック操作を実行する;
    FI
    Check_selector(tempSS);
    tempSSdesc := Load_descriptor_from_GDT_LDT(tempSS);
    check_SS_desc(tempSS, tempSSdesc, newCPL);
    CS := tempCS;
    RIP := tempRIP;
    SS := tempSS;
    RSP := tempRSP;
    Save_descriptor_for_VMX(CS, Descriptor);
    descriptor.DPL < CPLならばセレクターをNULLにする;
    RFLAGS(CF, PF, AF, ZF, SF, TF, DF, OF, NT, RF, AC, IC) := tempFlags;
    IF CPL == 0 THEN RFLAGS(IF) := tempFlags; FI;
    NMIのマスクを解除する;
END;

4.2.7 JMP Far

FAR JMPはイントラレベル専用です。モードの制限が強制されます。セレクターはGDT/LDT内のコンフォーミング・コードではないディスクリプターを示さなければなりません。CS.accessedビットへのセットは行いません。新しいディスクリプターはVMXにおいて使用するために保存します。0x66プリフィックスを伴う命令は#UDとなります。0x67プリフィクスを32ビット・モードで伴う命令は#GP(0)となります。

疑似コード:

IF 0x66プリフィクスがある THEN #UD ; FI
IF 0x67プリフィクスがある AND 32ビット・モード THEN #GP(0); FI
Check_selector(newCS);
newCSdesc := Load_descriptor_from_GDT_LDT(tempCS);
Check_CS_desc(tempCS, newCSdesc, CPL);
IF newRIPはキャノニカルではない THEN
    #GP(0);
FI
CS := newCS;
RIP := newRIP;
newCSdescの保存;
有効にされているならシャドウ・スタックにPUSHする
有効にされているなら分岐終了状態に遷移する

4.2.8 LSL、LAR、VERW、VERR

使用するセレクターのロード・アーキテクチャーを変更しました。LARはアクセス・ビットを常に1とします。

Check_Selector(selector);
// 失敗するのであればZF := 0で返す
Desc := Load_descriptor_from_GDT_LDT(selector);
// 失敗するのであればZF := 0で返す
Check_Data_Desc(selector, Desc, CPL);
// 失敗するのであればZF := 0で返す
// LARは常にAccess = 1で返す
// LSL/LAR/VERW/VERRのフローではディスクリプターからの情報で返す

4.2.9 LDS、LES、LFS、LGS、LSS

Desc.accessedビットは設定しません。新しいディスクリプターはVMXで使用するために保存します。使用するセレクターのロード設計を変更しました。

疑似コード:

If newSelはNULL AND LSS AND NOT (CPL0 AND CS.L) THEN
    #GP(0);
FI
Check_selector(newSel);
newDesc := Load_descriptor_from_GDT_LDT(newSel);
IF LSS THEN
    Check_SS_desc(newSEL, newDesc);
ELSE
    Check_Data_desc(newSel, newDesc);
Dest(sel) := newSel;
Dest(offset) := offest;
newDescの保存

4.2.10 LGDT

振る舞いはSDMで説明されているとおりです。

4.2.11 LLDT

振る舞いはSDMで説明されているとおりです。

4.2.12 LIDT

振る舞いはSDMで説明されているとおりです。

4.2.13 LKGS

セグメント・レジスターへのMOVと同じように、変更されたセレクターのロードをチェックします。

4.2.14 LSL

振る舞いはSDMで説明されているとおりです。

4.2.15 LTR

振る舞いはSDMで説明されているとおりです。TSSのbusyビットをセットします。

4.2.16 セグメント・レジスターからのMOV

振る舞いはSDMで説明されているとおりです。

4.2.17 セグメント・レジスターへのMOV

Desc.accessedビットはディスクリプターの内部キャッシュについては設定されますが、メモリーには設定しません。新しいディスクリプターはVMXで使用するために保存します。変更されたデータ・セグメントのロード手順を使用します。

If newSelはNULL AND MOV SS AND NOT (CPL0 AND CS.L) THEN
    #GP(0);
FI
Check_selector(newSel);
newDesc := Load_descriptor_from_GDT_LDT(newSel);
IF MOV SS THEN
    Check_SS_desc(newSEL, newDesc);
ELSE
    Check_Data_desc(newSel, newDesc);
Dest(sel) := newSel;
newDescの保存;
IF SS THEN MOV SS命令によるブロック※15; FI;

4.2.18 セグメント・レジスターのPOP

Desc.accessedビットはディスクリプターの内部キャッシュについては設定されますが、メモリーには設定しません。新しいディスクリプターはVMXで使用するために保存します。

IF 64ビット・モードでのPOP DS、POP ES、POP SS THEN   
    #UD;
FI
newSel := POP
Check_selector(newSel);
newDesc := Load_descriptor_from_GDT_LDT(newSel);
IF POP SS THEN
    Check_SS_desc(newSEL, newDesc);
ELSE
    Check_Data_desc(newSel, newDesc);
Dest:= newSel;
newDescの保存;
IF SS THEN POP SSによるブロック; FI

4.2.19 POPF

CPL0においてIOPLを変更するという試みを無視します。

4.2.20 PUSHセグメント・セレクター

振る舞いはSDMで説明されているとおりです。

4.2.21 PUSHF

振る舞いはSDMで説明されているとおりです。

4.2.22 RDFSBASE、RDGSBASE

振る舞いはSDMで説明されているとおりです。

4.2.23 RET far

FAR RETはイントラレベル専用です。セレクターはGDT/LDT内のコンフォーミング・コード・セグメントではないディスクリプターを指し示さなければなりません。CS.accssedビットはセットしません。新しいディスクリプターはVMXで使用するために保存します。0x66プリフィクスを伴う命令は#UDとなります。

疑似コード:

IF 0x66プリフィクスがある THEN #UD ; FI
newRIP := POP;
newCS := POP;
If newCSはNULL THEN
    #GP(0)
FI
Check_selector(newCS);
newCSdesc := Load_descriptor_from_GDT_LDT(tempCS);
Check_CS_desc(tempCS, newCSdesc, CPL);
IF newRIPはキャノニカルではない THEN
    #GP(0)
FI
CS := newCS;
RIP := newRIP;
newCSdescの保存;
有効にされているならシャドウ・スタックを使用する
有効にされているなら分岐終了状態に遷移する

4.2.24 SGDT

振る舞いはSDMで説明されているとおりです。

4.2.25 SLDT

振る舞いはSDMで説明されているとおりです。

4.2.26 SIDT

振る舞いはSDMで説明されているとおりです。

4.2.27 STR

振る舞いはSDMで説明されているとおりです。

4.2.28 SWAPGS

振る舞いはSDMで説明されているとおりです。

4.2.29 SYSCALL

FLAGSの制限を強制する部分を除き、振る舞いはSDMとFRED EAS※16で説明されているとおりです。

4.2.30 SYSENTER

振る舞いはSDMで説明されているとおりです。

4.2.31 SYSEXIT

振る舞いはSDMで説明されているとおりです。

4.2.32 SYSRET

RFLAGS(R11)のVIF、VIP、またはIOPLが0ではなくフォルトする場合を除き、振る舞いはSDMとFRED EASで説明されているとおりです。

4.2.33 WRFSBASE, WRGSBASE

振る舞いはSDMで説明されているとおりです。

4.2.34 VERR

振る舞いはSDMで説明されているとおりですが、本ドキュメントで示された手順でセグメントをロードする変更を伴います。

4.2.35 VERW

振る舞いはSDMで説明されているとおりですが、本ドキュメントで示された手順でセグメントをロードする変更を伴います。

4.2.36 VMEntry

Check_CS_Desc(newCS, newDesc, newCPL)
// 失敗するとVMEntryのエラーを通知する
Check_SS_Desc(newSS, newDesc, newCPL)
// 失敗するとVMEntryのエラーを通知する
For all of DS/ES/FS/GS:
Check_Data_Selector(newSelector, newCPL)
// 失敗するとVMEntryのエラーを通知する
64ビット・モードですべてのディスクリプターをロードする。

4.3 セグメンテーション命令と関連する振る舞いのリスト

表16にセグメンテーション命令と関連する振る舞いのリストを示します。

表16. セグメンテーション命令のリストと関連する振る舞い

命令 振る舞い
SGDT Intel64の振る舞いからの変更はない。
SIDT Intel64の振る舞いからの変更はない。
SLDT Intel64の振る舞いからの変更はない。
STR Intel64の振る舞いからの変更はない。
LGDT Intel64の振る舞いからの変更はない。
LIDT Intel64の振る舞いからの変更はない。
LLDT Intel64の振る舞いからの変更はない。
LTR Intel64の振る舞いからの変更はない。
VERR セクション4.1において説明するセグメンテーション設計に従うための変更を行った。
VERW セクション4.1において説明するセグメンテーション設計に従うための変更を行った。
ARPL Intel64の振る舞いからの変更はない。
FAR CALL セクション4.2において説明するセグメンテーション設計に従うための変更を行った。0x66プリフィックスによる#UD。32ビット・モードと間接を伴う0x67プリフィクスによる#GP。
FAR JMP セクション4.2において説明するセグメンテーション設計に従うための変更を行った。0x66プリフィックスによる#UD。32ビット・モードを伴う0x67プリフィクスによる#GP。
FAR RET セクション4.2において説明するセグメンテーション設計に従うための変更を行った。0x66プリフィックスによる#UD。
IRET IRET命令の振る舞いはセクション4.2で説明されている通り。
LDS DSにおけるFARポインターのロードはセクション4.1で説明したセグメント・チェック規則が適用される。
LES ESにおけるFARポインターのロードはセクション4.1で説明したセグメント・チェック規則が適用される。
LFS FSにおけるFARポインターのロードはセクション4.1で説明したセグメント・チェック規則が適用される。
LGS GSにおけるFARポインターのロードはセクション4.1で説明したセグメント・チェック規則が適用される。
LSS SSにおけるFARポインターのロードはセクション4.1で説明したセグメント・チェック規則が適用される。
LKGS カーネルGS.baseへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
DSへMOV DSへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
ESへMOV ESへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
SSへMOV SSへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
FSへMOV FSへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
GSへMOV GSへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
DSからMOV Intel64の振る舞いからの変更はない。
ESからMOV Intel64の振る舞いからの変更はない。
SSからMOV Intel64の振る舞いからの変更はない。
FSからMOV Intel64の振る舞いからの変更はない。
GSからMOV Intel64の振る舞いからの変更はない。
POP DS スタックの先頭からPopしてDSへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
POP ES スタックの先頭からPopしてESへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
POP SS スタックの先頭からPopしてSSへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
POP FS スタックの先頭からPopしてFSへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
POP GS スタックの先頭からPopしてGSへの代入はセクション4.1で説明したセグメント・チェック規則が適用される。
PUSH CS Intel64の振る舞いからの変更はない。
PUSH DS Intel64の振る舞いからの変更はない。
PUSH ES Intel64の振る舞いからの変更はない。
PUSH SS Intel64の振る舞いからの変更はない。
PUSH FS Intel64の振る舞いからの変更はない。
PUSH GS Intel64の振る舞いからの変更はない。
SWAPGS Intel64の振る舞いからの変更はない。
RSM セグメンテーションに対する変更はないが、他のモードとRFLAGSの制限は強制される。
WRFSBASE Intel64の振る舞いからの変更はない。
WRGSBASE Intel64の振る舞いからの変更はない。
RDFSBASE Intel64の振る舞いからの変更はない。
RDGSBASE Intel64の振る舞いからの変更はない。
SYSENTER 16ビット・モードと仮想86モードに入ることはできない。
SYSEXIT 16ビット・モードと仮想86モードに入ることはできない。
SYSCALL RFLAGSに対する制限を強制する。
SYSRET RFLAGSに対する制限を強制する。
ERETU セグメント・チェックのルールが変更される。RFLAGSの制限が強制される。
FRED entry Intel64の振る舞いからの変更はない。
IDT entry セグメント・チェックのルールの変更とFREDによる制限が適用される。

4.4 LEGACY_REDUCED_ISAを伴わない64ビットSIPI / 5Lページ・スイッチ

LEGACY_REDUCED_ISAビットによるX86-Sシステムに対する互換性を持つように設定しないシステムにおいても、64ビットSIPIを実装することができます。このような場合、IA32_SIPI_ENTRY_STRUCT_PTRまたはSIPI_ENTRY_STRUCT FEATURESビットが有効化されていないのであれば、64ビットSIPIはレガシーINIT/SIPIへと戻る(フォールバックする)ことができます。

同様に、MSRによる5レベル・ページ・スイッチをX86-Sではないシステムにおいて自身のCPUIDによって互換性のある実装をすることができます。


まとめ

今回は内容が高度であった関係で内容量と比較して、だいぶ時間がかかりました。

英語からの日本語への翻訳については、今後いわゆる「AI」が本格的に進出してくる分野だとは思いますが、今回はそれよりも実務的でわかりやすい翻訳を提供することを目標にしてみました。それがどういうことかというと、「直訳」ではないということになります。一語一句分析のうえで翻訳する機械翻訳やDL(深層学習)系のAIではなく、英語の文書から読み取った意味を“さかきけい”の理解で日本語で書き出すという作業をしています。このことから私の理解が間違っていると結果的に間違った翻訳になります。いわゆる「意訳」というものです。各種仕様書を併読しつつ念入りに確認したつもりではありますが、内容に誤りがありましたら申し訳ありません。それとともにページの記載内容を修正し、自分自身の知識を更新したいと考えていますので、コメントでやさしくお教えいただければと思います(やさしくないと感じる場合には怖くて反応できないことがあります)。

また、これまでは英語のままとしていた法的宣言部分についても、今回からオプションとして日本語参考訳をつけることにしました(ボタンをクリックして開くまでは表示されません)。基本的にはあまり意味がない(=特に法的に意味がないと考えています)かとは思うのですが、何を前提として公表されている情報であるのかを理解するためには役立つのではないかと考えて追加しました。

本ドキュメントを翻訳する際に私が言葉の選択に関して検討したことを以下に書き出してみます:

  • 本文のヘッダー部分、箇条書き部分および表中の文章は基本的に「である調」とし、それ以外の部分は「ですます調」としました。
  • 頭文字で略語となる英語表記は、日本語表記にするとしても原文を何らかの形で残すか、そのまま表記するようにしました。それは事実上、本件における専門用語だからです。
  • x86に詳しくない方が読むと「fault」がそのままカタカナ表記の「フォルト」になっていることが気になるかもしれません。しかしこれはx86における例外機構の専門用語で挙動の違いを示すものなのでそのままとしています。
  • 「Canonical」を本サイトでは「キャノニカル」というカタカナ表記で記述しています。現時点で一般的に「カノニカル」とカタカナ表記するのが多数派であることは理解しています。
  • 「Compatibility mode」を「コンパチビリティー・モード」あるいは「互換モード」のどちらで表現するのかは、かなり悩んだうえで「コンパチビリティー・モード」としました。直訳するなら「互換性モード」でしょうか。
  • 「Protected mode」を「プロテクト・モード」にするか「保護モード」にするかも結構悩みました。これを直訳するならば「保護されたモード」です。「IA-32 インテル® アーキテクチャ ソフトウェア・デベロッパーズ・マニュアル」という、インテル株式会社が日本語で発行しているドキュメントを参照すると「保護モード」なのですが、「プロテクト・モード」という表記が一般的だと思われること、また往年のNEC PC-9800シリーズにおいても「プロテクト・メモリー」といった表現があることから、「プロテクト・モード」を選択しました。
  • 「Paged Mode」に関しては「ページド・モード」で通じる人は「英語で読める人なのではないか?」と思えたので「ページ化モード」と表記することにしました(日本語としてはこちらの方が理解が進むのではと考えました)。しかし、これを書きながら「ページ有効モード」の方がよりよいではないかと再度悩み始めています。というのも、X86-Sでは常にページが有効であることが特徴であるからです。
  • 「Legacy」は一般語だと思えるので基本的に「レガシー」と表現しました。
  • 「VM Entry」や「VM Exit」、「CR0 Exiting」や「CR4 Exiting」などは相当悩んだうえで訳さないことを選びました。これはニーモニックや固有名のある構造体やフィールドなどと同様に理解するしかないというのが理由です。これを理解しないと関連するドキュメントを読むことは難しいです。
  • 「non-XX mode」のような表現および関連する表現をどうするのかは悩んだうえで文脈によって「XXモードではない」と「非XXモード」といったような表現を使い分けることにしました。これは日本語として読んだときに、どちらがより違和感が少ないかと考えて選択しました。一方で一部疑似コード内に原文(not non-XX)由来の二重否定表現が残ってしまった点は今後の課題としたいと思っています(書いている途中で思考力が限界を迎えました)。
  • 「Prefix」を本サイトでカタカナ表記するときには「プリフィクス」としています。世間一般において、ほかには「プリフィックス」「プレフィックス」「プレフィクス」などのカタカナ表記が存在していることを承知しています。
  • 「architectural package scope」はかなり悩んだうえでカタカナ表記にするだけにとどめました。当初は「設計パッケージ・スコープ」という表記にもしていたのですが、これも違う感じがしましたし、他の部分に合わせる形で「architectural」を外すのも違う気がした結果です。
  • 疑似コードに関しては日本語にしすぎないことを注意しました。プログラミングの経験があれば意味が通じる程度の日本語化をしたつもりですが、いかがでしょうか?
  • 中間リング1および2がなくなった関係で、モードとしてはリング0の64ビット・モードを示す「Supervisor」とリング3の64ビット・モードを示す「User64」、リング3の32ビット・モードを示す「User32」という新しいモードの表記が含まれています(リング0の32ビット・モードおよび16ビット・モードは廃止されました)。単純に「スーパーバイザー」「ユーザー64」および「ユーザー32」にもしようかと考えはしたのですが、最終的にはカタカナ表記にしないこととしました。が、それでよかったのかどうかはまだ悩んでいます。
  • あらかじめ断りのない略語「N.E.」を「実行不可」と訳したのは、Facebookで事情を(非常に少ない情報で)説明して質問をして、いただいたアドバイスの中から私が「なるほど」と思ったものを選んだ結果によります。これがもし間違っていたとしたら選んだ私の責任です。
  • 50ページ弱と比較的短いドキュメントなのですが、複数の書き手がいるようで、同じことを言及するにしても異なる表現になっている点を一本化した理解をして解決するのに予想外に時間を取られました。結果としてちゃんと一本化できているといいのですが。
  • 暗黙の略語が多く、各種関連ドキュメントをいろいろと読む必要があり、理解をするのにだいぶ時間がかかりました。関連する仕様を完全に理解していることが前提になっていることをひしひしと感じました。
  • 翻訳していて仕様的/記述的に「おや?」と思ったことは最終回で言及する予定です。

次回は最終回である分析編に続きます。次回はなるべく早く出せるようにしたいと思ってはいますが、仕事との兼ね合いで明日は難しそうです。

変更履歴

2023年6月6日

  • 初版

2023年6月9日

  • 「segmentation」の表現について「セグメンテーション」とそのままカタカナ表記するように変更をしました。
  • 上記とともにセグメンテーションが機能的にどうなったのかという表現の一部を「制限」から「限定」に変更しました。
  • エミュレーションの説明に関する記述内容の誤りを修正しました。
  • 日本語表現としての全般的な調整を行いました。

2023年6月12日

  • HTMLの記述ミスの修正しました。
  • 表に枠線を加えました。

2023年6月21日

  • 翻訳時の原文から日本語へ記述ミスを修正しました。
  • 原文からのカタカナ表現、日本語表現の再調整を行いました。

2023年7月16日

  • HTMLの記述ミスの修正をしました。
  • 疑似コード内の誤訳を修正しました。
  • 原文由来の表現上の誤りを説明する訳注を追加しました。

2023年7月21日

  • HTMLの記述内容の修正をしました。

2023年8月16日

  • POPF/POPFD/POPFQに関する記述上の誤訳を修正しました。

2023年9月11日

  • 日本語による表現の調整を行いました。

2023年11月18日

  • 本文中のリンク先URLを修正しました。
  • 表現上の誤りを1か所修正しました。

  • 有効にしたい場合は原書をご確認ください。
  • インテル株式会社による表現がそうなっているので、それに合わせています。
  • インテル株式会社による表現がそうなっているので、それに合わせています。
  • 質問者の技術レベルに応じて必要な回答を用意するのは、非常に高いスキルと多くの時間を必要とするものです。私はこれらのサービスが可能な状態にはありません。
  • 訳注:翻訳元のホワイト・ペーパーが英語なのでフィードバックも英語であるべきであろうと私は考えますが、もしかすると日本語で送ったとしてもAI技術の専門家でもあり、日本法人もあるIntel Corporationであれば、読まれる可能性もゼロではないかもしれません。
  • 訳注:80386において、80287互換=0、あるいはそれ以降=1であるかを示すビットで、それ以降はFPUがある限り常に1となります。
  • 訳注:ここでいうAPとはApplication Processorのことです。マルチプロセッサー・システムではブート処理を実行するプロセッサーをBSP(Bootstrap Processor)と呼び、それ以外のプロセッサーをAPと呼びます。
  • 訳注:原文通りに記載をしましたが、「1に固定。」が正しいのではないかと思われます。
  • 訳注:「N.E.」を「実行不可」と訳しています。
  • 訳注:POPF
  • 訳注:原文通りとしています。詳しくは分析編で言及する予定です。
  • 訳注:原文通りとしていますが、コンフォーミング・コード・セグメントがサポートされないというのがX86-Sの特徴ですから、「非」のつかない「コンフォーミング・コード・セグメント」が正しいです。
  • 訳注:イントラレベルとは特権レベルの変更がないことを意味します。対義語はインターレベルです。
  • 訳注:SS更新後の次の命令の実行後まで割り込みは自動的にブロックされます。これは次の命令でRSP/ESP/SPレジスターが更新されることを前提に、新しいスタック・ポインターが確定するまで割り込みが起こらないようにするための8086からの機能です。
  • 訳注:「Flexible Return and Event Delivery (FRED) Specification」のことを示しているものと思われます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です