概要
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がクラッシュした。スタック関連のデータが破壊されている感触があったが、詳細は不明。
謎のクラッシュは大抵はメモリ破壊バグ(戒め)