戻る

メインメモリ

目次


メインメモリ

メモリマップ


メモリマップの構造
名称
PhysicalStartAddressのこと。数値はバイト単位の値。
Typeその領域が何に使われているか、使われていない空き領域かを示す。
Type値Type名OSが自由に使えるか意味
0EfiReservedMemoryType×予約領域予約領域(使用禁止)
1EfiLoaderCodeブートローダのコード(UEFIアプリケーションの実行コード)
2EfiLoaderDataブートローダのデータ(UEFIアプリケーションが使うデータ領域)
3EfiBootServicesCode×Runtime Services が使用Boot Services のコード(ブートサービスドライバの実行コード)
4EfiBootServicesData×Runtime Services が使用Boot Services のデータ(ブートサービスドライバが使うデータ領域)
5EfiRuntimeServicesCodeRuntime Services のコード
6EfiRuntimeServicesDataRuntime Services のデータ
7EfiConventionalMemory通常 RAM(OS が自由に使える空き領域)
8EfiUnusableMemory×壊れている壊れているメモリ(使用不可)
9EfiACPIReclaimMemory×ACPI テーブル保持ACPI テーブル(再利用可)
10EfiACPIMemoryNVS×スリープ復帰に必要ACPI NVS(スリープ復帰用)
11EfiMemoryMappedIO×デバイス用MMIO
12EfiMemoryMappedIOPortSpace×デバイス用MMIO ポート空間
13EfiPalCodePAL コード(古い CPU 用)
14EfiPersistentMemory×特殊用途永続メモリ(NVDIMM など)
15–0x6FFFFFFFReserved予約領域
0x70000000–0x7FFFFFFFOEM 用ベンダー固有
0x80000000–0xFFFFFFFFOS ベンダー用OS ローダー用
NumberOfPagesメモリ領域の大きさを「ページ単位」で表した数値。「1ページ」の大きさは文脈によって異なる(x86_64アーキテクチャのCPUではページング機能があり、ページサイズは4KiB,2MiB,4MiB,1GiBのいずれかに設定可能。)。UEFIのメモリマップにおいては4KiB。

プログラミング

GetMemoryMap関数

関数引数戻り値説明
GetMemoryMap()
  1. IN OUT UINTN *MemoryMapSize:[入力/メモリマップ書き込み用のメモリ領域の大きさ(byte)][出力/実際のメモリマップの大きさ]
  2. IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap:メモリマップ書き込み用のメモリ領域の先頭ポインタ
  3. OUT UINTN *MapKey:メモリマップを識別するための値を書き込む変数。この値はプログラムやUEFIの処理によって変化する。2つの時点で同一の値であればその間はメモリマップに変化がないととれる。
  4. OUT UINTN *DescriptorSize:メモリマップの個々の行を表すメモリディスクリプタのバイト数
  5. OUT UINTN *DescriptorVersion:メモリディスクリプタの構造体のバージョン番号
EFI_STATUSメモリマップを取得する

EFI_MEMORY_DESCRIPTOR構造体

struct EFI_MEMORY_DESCRIPTOR{};
フィールド名型説明
TypeUINT32メモリ領域の識別
PhysicalStartEFI_PHYSICAL_ADDRESSメモリ領域先頭の物理メモリアドレス
VirtualStartEFI_VIRTUAL_ADDRESSメモリ領域先頭の仮想メモリアドレス
NumberOfPagesUINT64メモリ領域の大きさ(4KiBページ単位)
AttributeUINT64メモリ領域が使える用途を示すビット集合

グローバル変数

変数説明
gBSブートサービスに含まれる機能を使う場合に使う変数。なんの用途に使うかは不明
gRTランタイムサービスに含まれる機能を使う場合に使う変数。なんの用途に使うかは不明

その他

IN入力用であることを意味するマクロ
OUT出力用であることを意味するマクロ

コード


トップへ戻る

メインメモリの構造

0xfee000b0End of Interruptレジスタ値を書くことで割込み処理の終了をCPUに伝えられる。(ここでは0が書き込まれる)

トップへ戻る

メモリ管理

概要

メモリ管理の変更点


トップへ戻る

スタック領域の移動

RSPに0x7fff1000が設定されている場合の例

  1. 「call rax」(call命令)を実行すると、CPUはRSPの値を8減らす。(0x7fff1000から0x7fff0ff8へ)そしてそのメモリ領域へ現時点でのRIPの値を書き込む(上の図では(a)のcall raxの上の部分が0x12345672であるとしている)。その状態が(b)
  2. RAXに格納されたアドレスへジャンプ。RAXを実行
  3. RAXを実行し完了したら、ret命令を実行する。
  4. ret命令を実行するとき、RSPが指すメモリ領域から8バイトを読み取り、RSPを8増やす。
  5. 読み取ったアドレスへジャンプする。

コードファイル


トップへ戻る

セグメンテーションの設定

GDT(グローバルディスクリプタテーブル)

GDTを再構築する関数

セグメントディスクリプタのフィールド

フィールド意味
ヌルディスクリプタ
(null descriptor)
GDTの0番目は使われないことになっている。8byte全部を0で埋める
base_...セグメントの開始アドレス(32bit)
64ビットモードでは無視される
limit_...セグメントのバイト数-1(20bit)
64ビットモードでは無視される
typeディスクリプタタイプ
system_segment1ならコードまたはデータセグメント
descriptor_privilege_level(DPL)ディスクリプタの権限レベル。値の意味はディスクリプタの種類に応じて少し変わる。
  • コードセグメントディスクリプタの場合:CPUの現在の権限レベル(CPL:CurrentPrivilegeLevel)を設定する
CPUの動作権限
0特権モード
1
2
3ユーザモード
present1ならディスクリプタが有効。0のディスクリプタを利用しようとすると、CPUが例外を発生させる。
availableOSが自由に使って良いビット(CPUからは利用しないフィールド)
long_mode1なら64ビットモード用のコードセグメント。0なら互換モード(compatibility mode)
default_operation_sizelong_modeが1なら必ず0とする。CPUが64ビットモードで動作中はデータセグメントのdefault_operation_sizeの設定は無視されるが、syscall命令と整合性を取るために1を設定することになっている。
データセグメントではlong_modeフィールドが予約フィールドとなっているため、必ず0を設定する必要がある。
granularity1ならlimitを4KiB単位として解釈する。(64ビットモードではそもそもlimitが無視される)
セグメントの意味

※本書が対象としているCPUの動作モード⇒「IA-32eモード(AMDではロングモード)」
サブモードとして「64ビットモード」「互換モード(compatibility mode)」がある。


トップへ戻る

ページングの設定


トップへ戻る


トップへ戻る


トップへ戻る


トップへ戻る