這個 api 用來取得記憶體配置資訊, 雖然有關的 api 只有 GetMemoryMap(), 但因為記憶體不同的分類而顯得複雜。除了需要知道這些記憶體的分類的開頭位址和大小, 也要知道他們可以被如何利用。
而 GetMemoryMap() 本身也不是很容易使用的函式。
uefi runtime service 可以在進入 os 之後繼續提供服務, 所以需要知道 runtime service 的記憶體位址, 在進入 os 之後, map 出來讓 os 繼續使用。
如果需要在 os 中呼叫 runtime service, 參考以下 uefi spec 2.7.pdf 節錄的要點 (沒有完全列出) 2.3.4 x64 Platforms For an operating system to use any UEFI runtime services, it must:
Preserve all memory in the memory map marked as runtime code and runtime data
Call the runtime service functions, with the following conditions:
In long mode, in 64-bit mode
Paging enabled
All selectors set to be flat with virtual = physical address. If the UEFI OS loader or OS
used SetVirtualAddressMap() to relocate the runtime services in a virtual address space, then this condition does not have to be met. See description of SetVirtualAddressMap() for details of memory map after this function has been called.
NumberOfPages: Number of 4 KiB pages in the memory region. NumberOfPages must not be 0, and must not be any value that would represent a memory page with a start address, either physical or virtual, above 0xfffffffffffff000
有這 2 個屬性:
UINT32 Type;
UINT64 Attribute;
ExitBootServices() 之後, EfiBootServicesCode, EfiBootServicesData 就不是給 boot service 用的, 可以拿來自由運用。
Attribute 有一個 EFI_MEMORY_RUNTIME
EFI_MEMORY_RUNTIME Runtime memory attribute: The memory region needs to be given a virtual mapping by the operating system when SetVirtualAddressMap() is called (described in Section 8.4)
以下提供一個範例程式:
這個資訊需要傳給 os kernel, 這樣 os kernel 才會知道記憶體的分佈範圍。
list 1 是 uefi shell memmap 指令列出的, list 2 是 get_memmap.c 程式的輸出, 我用以下指令將 ouput 存檔。
根據 UEFI_Spec_2_7.pdf 2.3.4, uefi 開機之後在呼叫 ExitBootServices() 之前, x64 cpu 處於以下模式:
2.3.4 x64 PlatformsAll functions are called with the C language calling convention. See Section 2.3.4.2 for more detail.
During boot services time the processor is in the following execution mode:
• Uniprocessor
• In long mode, in 64-bit mode
• Paging enabled
• 128 KiB, or more, of available stack space• The stack must be 16-byte aligned. Stack may be marked as non-executable in identity mapped page tables.
• CR0.EM must be zero
• CR0.TS must be zero• Direction flag in EFLAGs clear
• 4 KiB, or more, of available stack space
• The stack must be 16-byte aligned
以上是簡短摘錄, 詳細請參閱 2.3.4, cpu 已經進入 long mode, 使用 page, 一核心, 所以 gdt 已經被設定了, 在 qemu 中, 是以下的內容:
crt0-efi-x86_64.o: A CRT0 (C runtime initialization code) that provides an entry point that UEFI firmware will call when launching the application, which will in turn call the "efi_main" function that the developer writes.
libgnuefi.a: A library containing a single function (_relocate) that is used by the CRT0.
elf_x86_64_efi.lds: A linker script used to link UEFI applications.
efi.h and other headers: Convenience headers that provide structures, typedefs, and constants improve readability when accessing the System Table and other UEFI resources.
libefi.a: A library containing convenience functions like CRC computation, string length calculation, and easy text printing.
我也知道為什麼 global object ctor 沒有被正常喚起, 因為沒做任何事情, 本來就不會被正常喚起, 手動呼叫 GLOBAL_XX function 算是正常用法。
以下原文:
edk2 並沒有支援用 c++ 來開發 uefi 程式, 我真是不敢相信還有這麼原始的開發環境, 竟然不支援 c++。我可是 c++ 愛好者, 不能用自己喜歡的語言開發程式, 感覺很不爽。
c++ 的好處我說過好幾次了 (疑! 我根本沒說過!!), c 我也是可以寫的, 為什麼堅持用 c++ 呢? 還真的說不上原因, 大概是網路上很多的討論都對 c++ 很不好, 什麼 XX 比不上 C, YY 比不上 JAVA, 這些言論更讓我對 c++ 抱不平, 決定要多多推廣 c++, 我又不善嘴炮言詞, 只好用程式碼來證明 c++ 的能耐。