Memory Management (DXE) 实例分析

来源:互联网 发布:宋松淘宝模特 编辑:程序博客网 时间:2024/06/16 14:13

这篇通过实例分析AllocatePages() 来对之前的知识点进行巩固加深并且串联起来。
先来看一下UEFI 下AllocatePages的定义

typedefEFI_STATUS(EFIAPI *EFI_ALLOCATE_PAGES) (IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,IN OUT EFI_PHYSICAL_ADDRESS*Memory);

简单解释一下这里只介绍 第一个参数Type就可以了。
EFI_ALLOCATE_TYPE 分为3种:

  • AllocateAnyPages
  • AllocateMaxAddress
  • AllocateAddress

AllocateAnyPages: 就是分配内存的时候有内存管理器 去找一个可以分配的地址,那么分配内存的位置是由内存管理器 指定,这时候传进去的第四个参数会被忽略。

AllocateMaxAddress: 这个类型是告诉内存管理器我指定一个地址,你给我分配的地址不能超过第四参数传进去的地址

AllocateAddress: 这个类型是告诉内存管理器,你要给我一块地址,位置通过第四个参数指定。这个类型一些特殊情况下使用,因为这个类型容易造成内存碎片。

AllocatePages 函数主要调用CoreInternalAllocatePages 去分配内存,下面就可以大概分析一下CoreInternalAllocatePages

这个CoreInternalAllocatePages 主体是按照刚刚介绍的三种类型去划分的大概如下:

  MaxAddress = MAX_ADDRESS;  if (Type == AllocateMaxAddress)    MaxAddress = *Memory;  if (Type != AllocateAddress) {    Start = FindFreePages (MaxAddress, NumberOfPages, MemoryType, Alignment);  }  Status = CoreConvertPages (Start, NumberOfPages, MemoryType);

上面是把CoreInternalAllocatePages 抽出来拿掉一些其他的判断信息,主要就是先把大体思想弄明白,细节地方只能自己研究。

FindFreePages
这几行代码的意思是如果没有指定分配内存的地址,那么内存分配器就会去看看自己仓库里有没有满足用户要分配的内存大小的块。当然找也是有条件的,条件就是看看有没有MaxAddress, 如果找到就拿出来,找不到就算了。

CoreConvertPages
这个就是开始分配的函数

恩,在具体分析FindFreePages 和 CoreCovertPages,我们先来看看下面的图,看图有助于建立一个模型,看代码就没有障碍了。

举例,我们现在内存管理器仓库里有一块内存(0x6000 0000 - 0x6FFFF FFFF), 现在应用程序申请了一块指定地址是0x6100 0000 ,大小是1M 的内存块,类型是BootServicesData. 图片是gMemoryMap 的变化。
这里写图片描述
这个图片大概就是CoreConvertPages 函数做的事情。

现在来简单分析一下FindFreePages, 还记得之前博客有介绍为了保证S4 resume 的时候内存有些reserve 的地址是不能变得,UEFI 采用了简单直接的方法就是预先按照类型分配不同大小的bin档,以后APP或者driver 分配内存的时候优先在bin 里去分配。那么FindFreePages就是做这件事情。

FindFreePages:  //  // Attempt to find free pages in the preferred bin based on the requested memory type  //  if ((UINT32)NewType < EfiMaxMemoryType && MaxAddress >= mMemoryTypeStatistics[NewType].MaximumAddress) {    Start = CoreFindFreePagesI (              mMemoryTypeStatistics[NewType].MaximumAddress,               mMemoryTypeStatistics[NewType].BaseAddress,               NoPages,               NewType,               Alignment              );    if (Start != 0) {      return Start;    }  }

抽取其中片段,首先找到FreePage 会去preferred bin 里去找,那么预先分配preferred bin 的大小和base 是存放在mMemoryTypeStatistics 里的,mMemoryTypeStatistics 初始化时在CoreAddMemoryDescriptor里之前讲过哪一堆for 循环里。如果在preferred bin 里没有找到,那么还有一个default bin 里去分配,如果还是失败那只能在其他地方去分配,这样一来,和之前讲过的一样,预先定义的bin 不够容纳实际driver或App 申请的内存,要在bds 里重新启动一下,然后把预先定义的preferred bin 大小扩展成上一次的实际内存使用的大小。

关于CoreConvertPages 做的事情就是如上图片看到的,首先会找到自己空闲内存的块,如果包含要分配的内存块,就找到了。然后会重新整理内存块。这段代码其实是很核心的,但是用博客去介绍,我自己看过别人博客如果贴代码过多,我就看不下去了,只要明白大概思想,代码自己去看。关于内存管理这方面,个人是看过之后,用各种工具,主要还是source level debug 去把每个段代码基本都追了,前后大概花了一个多星期。其中很多地方比如锁,互斥的flag ,函数递归调用,mMapStack 的用处,只有自己追一遍就明白了。我就不写了,太多了。

0 0