Memory Management (DXE) 代码简析

关于代码分析,这次先来CoreInitializeMemoryServces (DxeMain.c)
这个函数是DXE 阶段初始化内存相关的第一个函数,先来理清这个函数,主要做了以下三件事情:

1 初始化Pool 内存分配相关的数据结构
2 通过查找Hob ,找到能容纳DxeCore 的内存地址
3 通过CoreAddMemoryDescriptor 函数给接下来内存分配的services 做准备工作

这里主要介绍1, 3 两个点的内容。

CoreInitializePool

  UINTN  Type;
  UINTN  Index;

  for (Type=0; Type < EfiMaxMemoryType; Type++) {
    mPoolHead[Type].Signature  = 0;
    mPoolHead[Type].Used       = 0;
    mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;
    for (Index=0; Index < MAX_POOL_LIST; Index++) {
      InitializeListHead (&mPoolHead[Type].FreeList[Index]);
    }
  }

这个关于Pool 初始化函数非常简单,我们的Pool 根据内存的类型和大小大概长下面的样子。
Memory Management (DXE) 代码简析_第1张图片

Pool 首先是按照类型划分,然后每个类型又按定好的块的大小划分。这个函数主要就是初始化这个结构的链表。


CoreAddMemoryDescriptor
这个函数是相对来说比较复杂,也是非常重要的,如果看过之前的文章那么接下来分析这个函数就会简单很多。 这个函数其实这样的,比如管理内存Allocate 的管理员,它手里刚开始什么都没有,然后通过CoreAddMemoryDescriptor 就是给这个管理员分配一块某个类型某个大小的内存块。在CoreInitializeMemoryServices 里调用CoreAddMemoryDescriptor 就是为了接下来分配内存用的,但是我们之前也提过,系统给每个管理员分配内存也得找GCD 申请,但是第一次这个时候GCD 管理部门还没成立,就是内存分配管理员先用着,等GCD 初始化好,之后再去登记一下,就是先上车后买票。因为它够复杂,我们先简要介绍一下它具体功能都有什么:

  • 初始化gMemMap 信息并且登记这次增加的内存块信息主要通过 CoreAddRange, 和 CoreFreeMemoryMapStack 两个函数
  • 中间一堆for 循环那里主要是关于前几篇介绍的,为了S4 resume 的时候reserved type 内存不变和减少内存碎片,我们会在code 里画出一个一个内存块,称之为各种类型的bin file。我们可以看到一堆for 循环里首先先申请各个类型内存的bin ,然后又释放了,申请之后释放有两个目的1. 记录各个类型memory bin 的起始地址和大小,信息记录在mMemoryTypeStatistics 等到之后要分配相关类型内存的时候首先去查找mMemoryTypeStatistics 信息记录的地址,就在那个地址区间去分配,如果记录的区间不够,那么才去另外的地址区间起给这个类型分配。2 . 测试一下目前system 给内存管理员分配的内存是否有足够大小的空间去容纳那些code 里保留的内存类型bin 档。

大概就是完成上面的事情。 关于第一点,我们看如下的代码。

  544   CoreAcquireMemoryLock ();
  545   End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;
  546   CoreAddRange (Type, Start, End, Attribute);
  547   CoreFreeMemoryMapStack ();
  548   CoreReleaseMemoryLock ();

CoreAddRange:
主要就是增加一个Entry,这个Entry 有这个memory rang 的各种属性信息,然后通过链表,链到gMemMap 里,其中的while 循环里,就是合并两个Entry 如果这两个Entry 代表的内存块是连续的,属性是一样的,就可以合并。因为记录内存块的Entry 也需要空间,这里的做法是先存在了DxeCore 的空间里取名为mMapStack, 之后我们会看到code 里会在另外分配一块空间专门存放所有Entry 的空间。mMapStack 还有一个参数是mMapDepth 它是管理mMapStack 深度的,因为在释放mMapStack 的函数里会有另外的CoreAddRange,也就是递归调用,所以会有一个参数mMapDepth记录目前mMapStack 里有多少Entry 需要释放。执行之后如下图:
Memory Management (DXE) 代码简析_第2张图片

CoreFreeMemoryMapStack:

这个函数就是释放mMapStack的Entry,然后另外分配一大块专门记录Entry 的空间用链表mFreeMemoryMapEntry 来管理。它也会把mMapStack 里的Entry 内容复制到mFreeMemoryMapEntry 的Entry 里,然后把mFreeMemoryMapEntry 里的Entry 链到gMemoryMap 里。因为会发生递归调用,所以这个函数里弄了一个锁mFreeMapStack。然后紧接着一个while 循环根据mMapStack 递归的层数把所有的Entry 释放掉。关于这个函数,我们首先看里面调用AllocateMemoryMapEntry函数。AllocateMemoryMapEntry 这个函数就是在上图(0x6000 0000 — 0x6FFF FFFF )这个区间块里分配一块空间出来专门用来记录Entry 信息的。这里也不具体解释里面代码了,还是看图吧,当我们AllocateMemoryMapEntry 执行之后图片如下:
Memory Management (DXE) 代码简析_第3张图片
接下来就是把mMapStack 里的Entry里的内容复制到(0x6FFF F000 — 0x6FFF FFFF)里的Entry。并且把gMemoryMap 链表指向(0x6FFF F000 – 0x6FFF FFFF)里的Entry里。如下图:
Memory Management (DXE) 代码简析_第4张图片

接下来就是一堆For循环的代码,这个上面内容已经简单的提到过,具体分析留到后来分析AllocatePool 和 AllocatePage 时候再介绍吧。

你可能感兴趣的:(Memory Management (DXE) 代码简析)