OS 也好或者UEFI Firmware 也好,都有各自的应用领域,为了更好的完成自己的角色,就会用适合自己的策略方法。由于UEFI Firmware 是现代化软件,所以有些思想和目前主流软件思想有类似的地方,所以有人会去对UEFI Firmware 和 OS 做比较。比较是可以的,但是首先得非常准确你比较的内容的应用场景,技术限制,等等。举例Firmware 就是你房子装修前的那种毛坯房,它会把水,电,你要的基本资源给你弄好,具体怎么装修设计是户主os 的事情。毛坯房和装修好的房子是有联系和相似之处的。
UEFI 内存的管理策略
因为OS 有要求,S4 resume 返回的时候是要从disk 里把内存里的一些内容恢复回来,所以os 要firmware 汇报memory 的时候有些内容是不能变的,如果变的话S4 resume fail. 那么有哪些地址段不能变呢?
- Reserved memory
- ACPI NVS
- ACPI Reclaim
- Runtime data
- RUntime code
上述地址是os 规定S4回来不能变动的。那么UEFI firmware 给出的策略就是简单讲给上述memory 类型各分配一个大块它们给出的名字是bin. 如下图。
此图截取Intel white paper BIOS memory map.
看图要看仔细,对这个图去看code,你就会发现code 这么写是有原因的,当然这个图就当一个参考。首先各家IBV 会根据板子设计不同自己预留各个reserved memory 的大小和类型,有的BIN 档里会有BS data/code,理由就是尽量都在这个bin 里分配,减少内存碎片。下面简单介绍一下大致流程:
- PEI MRC 会根据各个reserved memory 的信息建立一个Hob。
- DXE 阶段在Dxe Core 的初始化memory services 的时候获得这个Hob,然后根据Hob 里的信息(默认值)去给相关类型的bin 档分配内存。
- 当firmware 里其他代码要分配内存资源的时候这个时候优先去这个相对应的bin里去分配内存。
- 其实这个时候firmware还会维护一个全局一个表,这个表放在了system table 上名字是Efi memory type information 它记录了firmware 本次实际使用各个内存的信息。
- bds阶段的ready to boot event 里会有一个function
(BdsSetMemoryTypeInformationVariable)
在这个function 里它会把实际各个内存的使用的大小和之前默认系统分配的时候进行比对,如果发现实际使用的各个memory type 小于默认的,那么继续开机,如果发现实际使用的memory type size大于默认设置的size 则会调用reset system function ,当下一次reset 的时候firmware 会根据上一次实际的使用情况去设置相应memory type 的bin 档大小。
此图截取Intel white paper BIOS memory map.
上图也许自己看明白,在把流程想通,再去看代码就不是那么晦涩了。
记录(以下是个人的记录内容):
- GetPlatformMemorySize ()/Memory.c 里构建 memory information hob
- CoreInitializeMemoryServices ()/DxeMain.c 里记录各个memory type bin 档的大小并确定分配时候的基地信息放在mMemoryTypeStatistics 表里。
- BdsSetMemoryTypeInformationVariable()/BdsMisc.c 里比较当前实际内存使用情况和默认设置内存类型的大小,如果默认保留的大小能满足实际使用情况,那么直接开机,反之reset system 并且把在下一次设置memory bin 档大小为上一次实际使用的内存的大小。