zebian.log

技術系備忘録とか

UEFI Memory Mapで躓いたポイント

概要

UEFIからブートするタイプのOSでは、ブートローダーで取得したUEFI Memory Mapを受け取り、その情報をもとにメモリアロケーションの初期化を行う。私の自作OSもしかり。

Memory Mapの内容は以下の通り(自作OSのコード)。 github.com

pub const UEFI_PAGE_SIZE: usize = 0x1000;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum MemoryType {
    Reserved,
    LoaderCode,
    LoaderData,
    BootServicesCode,
    BootServicesData,
    RuntimeServicesCode,
    RuntimeServicesData,
    Conventional,
    Unusable,
    AcpiReclaim,
    AcpiNonVolatile,
    Mmio,
    MmioPortSpace,
    PalCode,
    PersistentMemory,
    Other(u32),
}

#[derive(Debug, Copy, Clone)]
pub struct MemoryDescriptor {
    pub ty: MemoryType,
    pub phys_start: u64,
    pub virt_start: u64,
    pub page_cnt: u64,
    pub attr: u64,
}

ここで言うpage_cntは1ページがUEFI_PAGE_SIZEバイト=つまり4,096バイトのページの個数である。そして以下がOSが受け取ったMemory Mapの出力。

MemoryDescriptor { ty: BootServicesCode, phys_start: 0, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 4096, virt_start: 0, page_cnt: 159, attr: 15 }
MemoryDescriptor { ty: LoaderData, phys_start: 1048576, virt_start: 0, page_cnt: 909, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 4771840, virt_start: 0, page_cnt: 883, attr: 15 }
MemoryDescriptor { ty: AcpiNonVolatile, phys_start: 8388608, virt_start: 0, page_cnt: 8, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 8421376, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: AcpiNonVolatile, phys_start: 8433664, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 8437760, virt_start: 0, page_cnt: 4, attr: 15 }
MemoryDescriptor { ty: AcpiNonVolatile, phys_start: 8454144, virt_start: 0, page_cnt: 240, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 9437184, virt_start: 0, page_cnt: 3328, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 23068672, virt_start: 0, page_cnt: 698677, attr: 15 }
MemoryDescriptor { ty: LoaderData, phys_start: 2884849664, virt_start: 0, page_cnt: 32768, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 3019067392, virt_start: 0, page_cnt: 32769, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3153289216, virt_start: 0, page_cnt: 32, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 3153420288, virt_start: 0, page_cnt: 9909, attr: 15 }
MemoryDescriptor { ty: LoaderCode, phys_start: 3194007552, virt_start: 0, page_cnt: 56, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 3194236928, virt_start: 0, page_cnt: 53, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3194454016, virt_start: 0, page_cnt: 215, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 3195334656, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3195346944, virt_start: 0, page_cnt: 6, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 3195371520, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3195375616, virt_start: 0, page_cnt: 1501, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3201523712, virt_start: 0, page_cnt: 168, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3202211840, virt_start: 0, page_cnt: 17, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 3202281472, virt_start: 0, page_cnt: 6, attr: 15 }
MemoryDescriptor { ty: LoaderData, phys_start: 3202306048, virt_start: 0, page_cnt: 4, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3202322432, virt_start: 0, page_cnt: 88, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3202682880, virt_start: 0, page_cnt: 25, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3202785280, virt_start: 0, page_cnt: 5, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3202805760, virt_start: 0, page_cnt: 59, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203047424, virt_start: 0, page_cnt: 11, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203092480, virt_start: 0, page_cnt: 39, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203252224, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203256320, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203268608, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203280896, virt_start: 0, page_cnt: 7, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203309568, virt_start: 0, page_cnt: 4, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203325952, virt_start: 0, page_cnt: 14, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203383296, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203387392, virt_start: 0, page_cnt: 11, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203432448, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203440640, virt_start: 0, page_cnt: 13, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203493888, virt_start: 0, page_cnt: 5, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203514368, virt_start: 0, page_cnt: 13, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203567616, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203579904, virt_start: 0, page_cnt: 12, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203629056, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203633152, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203645440, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203653632, virt_start: 0, page_cnt: 8, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203686400, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203698688, virt_start: 0, page_cnt: 6, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203723264, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203731456, virt_start: 0, page_cnt: 11, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203776512, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203788800, virt_start: 0, page_cnt: 15, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203850240, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203858432, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203866624, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203874816, virt_start: 0, page_cnt: 20, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203956736, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3203960832, virt_start: 0, page_cnt: 8, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3203993600, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3204001792, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3204005888, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3204009984, virt_start: 0, page_cnt: 20, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3204091904, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3204100096, virt_start: 0, page_cnt: 8, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3204132864, virt_start: 0, page_cnt: 8, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3204165632, virt_start: 0, page_cnt: 4, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3204182016, virt_start: 0, page_cnt: 4, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3204198400, virt_start: 0, page_cnt: 16, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3204263936, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3204272128, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3204276224, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3204280320, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3204292608, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3204304896, virt_start: 0, page_cnt: 35, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3204448256, virt_start: 0, page_cnt: 513, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206549504, virt_start: 0, page_cnt: 12, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3206598656, virt_start: 0, page_cnt: 8, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206631424, virt_start: 0, page_cnt: 11, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3206676480, virt_start: 0, page_cnt: 5, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206696960, virt_start: 0, page_cnt: 24, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3206795264, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206803456, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3206807552, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206815744, virt_start: 0, page_cnt: 9, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3206852608, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206860800, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3206864896, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206873088, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3206877184, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206881280, virt_start: 0, page_cnt: 4, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3206897664, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3206905856, virt_start: 0, page_cnt: 23, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3207000064, virt_start: 0, page_cnt: 1045, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3211280384, virt_start: 0, page_cnt: 8, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3211313152, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3211325440, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3211329536, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3211333632, virt_start: 0, page_cnt: 10, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3211374592, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3211382784, virt_start: 0, page_cnt: 2, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3211390976, virt_start: 0, page_cnt: 1, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3211395072, virt_start: 0, page_cnt: 3, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3211407360, virt_start: 0, page_cnt: 586, attr: 15 }
MemoryDescriptor { ty: RuntimeServicesData, phys_start: 3213807616, virt_start: 0, page_cnt: 256, attr: 9223372036854775823 }
MemoryDescriptor { ty: RuntimeServicesCode, phys_start: 3214856192, virt_start: 0, page_cnt: 256, attr: 9223372036854775823 }
MemoryDescriptor { ty: Reserved, phys_start: 3215904768, virt_start: 0, page_cnt: 128, attr: 15 }
MemoryDescriptor { ty: AcpiReclaim, phys_start: 3216429056, virt_start: 0, page_cnt: 18, attr: 15 }
MemoryDescriptor { ty: AcpiNonVolatile, phys_start: 3216502784, virt_start: 0, page_cnt: 128, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3217027072, virt_start: 0, page_cnt: 513, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 3219128320, virt_start: 0, page_cnt: 136, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3219685376, virt_start: 0, page_cnt: 32, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3219816448, virt_start: 0, page_cnt: 35, attr: 15 }
MemoryDescriptor { ty: BootServicesData, phys_start: 3219959808, virt_start: 0, page_cnt: 17, attr: 15 }
MemoryDescriptor { ty: BootServicesCode, phys_start: 3220029440, virt_start: 0, page_cnt: 24, attr: 15 }
MemoryDescriptor { ty: RuntimeServicesData, phys_start: 3220127744, virt_start: 0, page_cnt: 132, attr: 9223372036854775823 }
MemoryDescriptor { ty: AcpiNonVolatile, phys_start: 3220668416, virt_start: 0, page_cnt: 136, attr: 15 }
MemoryDescriptor { ty: Conventional, phys_start: 4294967296, virt_start: 0, page_cnt: 262144, attr: 15 }
MemoryDescriptor { ty: Reserved, phys_start: 4278173696, virt_start: 0, page_cnt: 4, attr: 0 }

1~3行目に着目してもらいたい。

1: MemoryDescriptor { ty: BootServicesCode, phys_start: 0, virt_start: 0, page_cnt: 1, attr: 15 }
2: MemoryDescriptor { ty: Conventional, phys_start: 4096, virt_start: 0, page_cnt: 159, attr: 15 }
3: MemoryDescriptor { ty: LoaderData, phys_start: 1048576, virt_start: 0, page_cnt: 909, attr: 15 }

2番目の領域、Conventionalのpage_cntは159、つまり領域のサイズとしては159 * 4,096 = 651,264バイトになる。開始アドレスが4,096とすると終了アドレスは4,096 + 651,264 = 655,360になる。

ところが、その次の3番目の領域の開始アドレスを見ると1048,576とあり、2番目の終了アドレスから393,216バイト分差がある。ここが躓きポイントであり、私が1年以上気付かなかった自作OSのメモリ破壊バグの原因である(実はみかん本にはこれについての言及が存在する)。

Memory Mapに存在しない領域をどう扱うか

Memory Mapに存在しない領域、先の例では2番目の領域と3番目の領域の間の393,216バイトのことだが、このような領域は空き領域として自由に読み書きできるように扱ってはいけない。

メモリ破壊バグについて

私の自作OSでは、ヒープアロケータ初期化以前のメモリ管理として、4KiBごとの領域をビットマップで管理するビットマップアロケータを実装している。Memory Mapを見るとOSが自由に扱える領域はConventional、BootServicesCode / Data(中身のデータの退避などをしたあとで)であるが、当初のビットマップアロケータは「全てのビットマップを空き領域としてマップしてから、自由に扱えない領域を使用済みとしてマップする」という実装になっていた。つまり、Memory Mapに存在しない領域は空き領域という扱いになっており、そこに何らかのデータが書き込まれた瞬間、メモリ破壊によってOSがクラッシュした。スタック関連のデータが破壊されている感触があったが、詳細は不明。

謎のクラッシュは大抵はメモリ破壊バグ(戒め)