UEFI.源码分析.DXE的内存服务.第一部分.初始化

Posted 木艮氵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UEFI.源码分析.DXE的内存服务.第一部分.初始化相关的知识,希望对你有一定的参考价值。

  • 源码EDK2:Tianocore
  • UEFI源码分析系列第二篇,DXE阶段的内存服务
  • 第一部分,内存服务的初始化过程
  • DXE阶段源码目录MdeModulePkg/Core/Dxe
  • 源码版本为UDK2017
  • 目前最新版2018代码在/Dxe/Mem/下多了HeapGuard.c这个文件,看名称应该是用来守护堆操作防止异常的。在UDK2017中并没有这个特性,所以我们的分析按照UDK2017的代码来。
  • 关于HeapGuard的讨论将列为单独一部分,敬请期待。

内存服务的初始化

在DxeMain中调用以下函数来初始化内存服务

/** /Dxe/DxeMain/DxeMain.c **/
269   //                                                                           
270   // Initialize Memory Services                                                
271   //                                                                           
272   CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength); 

该函数位于/Dxe/Gcd/Gcd.c

/** /Dxe/Gcd/Gcd.c **/
2054 EFI_STATUS                                     
2055 CoreInitializeMemoryServices (                 
2056   IN  VOID                  **HobStart,        
2057   OUT EFI_PHYSICAL_ADDRESS  *MemoryBaseAddress,
2058   OUT UINT64                *MemoryLength      
2059   )                                            
2060                                               
/** 进行内存服务初始化操作 **/
2295   *MemoryBaseAddress = BaseAddress;
2296   *MemoryLength      = Length;     
2297                                    
2298   return EFI_SUCCESS;              
2299  

1)转换HOB数据

1)把指向HOB数据的指针HobStart 转换成HOB格式的数据,本质就是把地址传给相应结构体的变量

HOB数据结构定义于/MdePkg/Include/Pi/PiHob.h

操作HOB数据的方法由库/MdePkg/Library/DxeHobLib 提供,该库的头文件位于/MdePkg/Include/Library/HobLib.h , 头文件中包含来几个操作HOB数据的宏定义,如GET_HOB_TYPE 宏来获取HOB类型。

/** /Dxe/Gcd/Gcd.c **/
2079   //                                                      
2080   // Point at the first HOB.  This must be the PHIT HOB.  
2081   //                                                      
2082   Hob.Raw = *HobStart;                                    
2083   ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);    

注意到变量Hob的类型是EFI_PEI_HOB_POINTERS,本质上是一个union类型的数据结构。

使用union最大的好处是提高源码的可读性和间接性。利用该类型中所有域的取值均一样的特点,在不同的使用方法下,可以使用不同的变量名字,一方面可以省去强制类型转换的麻烦,另一方面可以直接体现出当前的使用需求。

/** /MdePkg/Include/Pi/PiHob.h **/
458 ///                                                             
459 /// Union of all the possible HOB Types.                        
460 ///                                                             
461 typedef union                                                  
462   EFI_HOB_GENERIC_HEADER              *Header;                  
463   EFI_HOB_HANDOFF_INFO_TABLE          *HandoffInformationTable; 
464   EFI_HOB_MEMORY_ALLOCATION           *MemoryAllocation;        
465   EFI_HOB_MEMORY_ALLOCATION_BSP_STORE *MemoryAllocationBspStore;
466   EFI_HOB_MEMORY_ALLOCATION_STACK     *MemoryAllocationStack;   
467   EFI_HOB_MEMORY_ALLOCATION_MODULE    *MemoryAllocationModule;  
468   EFI_HOB_RESOURCE_DESCRIPTOR         *ResourceDescriptor;      
469   EFI_HOB_GUID_TYPE                   *Guid;                    
470   EFI_HOB_FIRMWARE_VOLUME             *FirmwareVolume;          
471   EFI_HOB_FIRMWARE_VOLUME2            *FirmwareVolume2;         
472   EFI_HOB_CPU                         *Cpu;                     
473   EFI_HOB_MEMORY_POOL                 *Pool;                    
474   EFI_HOB_UEFI_CAPSULE                *Capsule;                 
475   UINT8                               *Raw;                     
476  EFI_PEI_HOB_POINTERS;

2)初始化内存池

2)初始化内存池

/** /Dxe/Gcd/Gcd.c **/
2077   //                                                                   
2078   // Initialize the spin locks and maps in the memory services.        
2079   // Also fill in the memory services into the EFI Boot Services Table 
2080   //                                                                   
2081   CoreInitializePool ();

该函数的实现位于/Dxe/Mem/Pool.c

/** /Dxe/Mem/Pool.c **/
118 VOID                                                        
119 CoreInitializePool (                                        
120   VOID                                                      
121   )                                                         
122                                                            
123   UINTN  Type;                                              
124   UINTN  Index;                                             
125                                                             
126   for (Type=0; Type < EfiMaxMemoryType; Type++)            
127     mPoolHead[Type].Signature  = 0;                         
128     mPoolHead[Type].Used       = 0;                         
129     mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE) Type;    
130     for (Index=0; Index < MAX_POOL_LIST; Index++)          
131       InitializeListHead (&mPoolHead[Type].FreeList[Index]);
132                                                            
133                                                            
134                                                                                                                       

做的事情很简单,就是把全局变量mPoolHead 初始化,Pool 数据结构的定义也在Pool.c文件中。

/** /Dxe/Mem/Pool.c **/
 71 #define POOL_SIGNATURE  SIGNATURE_32('p','l','s','t') 
 72 typedef struct                                       
 73     INTN             Signature;                       
 74     UINTN            Used;                            
 75     EFI_MEMORY_TYPE  MemoryType;                      
 76     LIST_ENTRY       FreeList[MAX_POOL_LIST];         
 77     LIST_ENTRY       Link;                            
 78  POOL;                                               
 79                                                       
 80 //                                                    
 81 // Pool header for each memory type.                  
 82 //                                                    
 83 POOL            mPoolHead[EfiMaxMemoryType];          

全局变量mPoolHead对每种内存类型EFI_MEMORY_TYPE均有一组FreeList来维护可用的内存空间。

内存类型是以枚举类型定义于/MdePkg/Include/Uefi/UefiMultiPhase.h中。

/** /MdePkg/Include/Uefi/UefiMultiPhase.h **/
 19 ///                                                                                   
 20 /// Enumeration of memory types introduced in UEFI.                                   
 21 ///                                                                                   
 22 typedef enum                                                                         
 23   ///                                                                                 
 24   /// Not used.                                                                       
 25   ///                                                                                 
 26   EfiReservedMemoryType,                                                              
 27   ///                                                                                 
 28   /// The code portions of a loaded application.                                      
 29   /// (Note that UEFI OS loaders are UEFI applications.)                              
 30   ///                                                                                 
 31   EfiLoaderCode,                                                                      
 32   ///                                                                                 
 33   /// The data portions of a loaded application and the default data allocation       
 34   /// type used by an application to allocate pool memory.                            
 35   ///                                                                                 
 36   EfiLoaderData,                                                                      
 37   ///                                                                                 
 38   /// The code portions of a loaded Boot Services Driver.                             
 39   ///                                                                                 
 40   EfiBootServicesCode,                                                                
 41   ///                                                                                 
 42   /// The data portions of a loaded Boot Serves Driver, and the default data          
 43   /// allocation type used by a Boot Services Driver to allocate pool memory.         
 44   ///                                                                                 
 45   EfiBootServicesData,                                                                
 46   ///                                                                                 
 47   /// The code portions of a loaded Runtime Services Driver.                          
 48   ///                                                                                 
 49   EfiRuntimeServicesCode,                                                             
 50   ///                                                                                 
 51   /// The data portions of a loaded Runtime Services Driver and the default           
 52   /// data allocation type used by a Runtime Services Driver to allocate pool memory. 
 53   ///                                                                                 
 54   EfiRuntimeServicesData,                                                             
 55   ///                                                                                 
 56   /// Free (unallocated) memory.                                                      
 57   ///                                                                                 
 58   EfiConventionalMemory,                                                              
 59   ///                                                                                 
 60   /// Memory in which errors have been detected.                                      
 61   ///                                                                                          
 62   EfiUnusableMemory,                                                                           
 63   ///                                                                                          
 64   /// Memory that holds the ACPI tables.                                                       
 65   ///                                                                                          
 66   EfiACPIReclaimMemory,                                                                        
 67   ///                                                                                          
 68   /// Address space reserved for use by the firmware.                                          
 69   ///                                                                                          
 70   EfiACPIMemoryNVS,                                                                            
 71   ///                                                                                          
 72   /// Used by system firmware to request that a memory-mapped IO region                        
 73   /// be mapped by the OS to a virtual address so it can be accessed by EFI runtime services.  
 74   ///                                                                                          
 75   EfiMemoryMappedIO,                                                                           
 76   ///                                                                                          
 77   /// System memory-mapped IO region that is used to translate memory                          
 78   /// cycles to IO cycles by the processor.                                                    
 79   ///                                                                                          
 80   EfiMemoryMappedIOPortSpace,                                                                  
 81   ///                                                                                          
 82   /// Address space reserved by the firmware for code that is part of the processor.           
 83   ///                                                                                          
 84   EfiPalCode,                                                                                  
 85   ///                                                                                          
 86   /// A memory region that operates as EfiConventionalMemory,                                  
 87   /// however it happens to also support byte-addressable non-volatility.                      
 88   ///                                                                                          
 89   EfiPersistentMemory,                                                                         
 90   EfiMaxMemoryType                                                                             
 91  EFI_MEMORY_TYPE;                                                                             

3)获取内存类型信息

3) 获取HOB中关于内存类型的数据信息,如果存在,则拷贝到全局变量gMemoryTypeInformation中。

/** /Dxe/Gcd/Gcd.c **/
2115   //                                                                                                   
2116   // See if a Memory Type Information HOB is available                                                 
2117   //                                                                                                   
2118   GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);                                          
2119   if (GuidHob != NULL)                                                                                
2120     EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);                                            
2121     DataSize                 = GET_GUID_HOB_DATA_SIZE (GuidHob);                                       
2122     if (EfiMemoryTypeInformation != NULL && DataSize > 0 && DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION)) 
2123       CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);                           
2124                                   
2125                                   

全局变量gMemoryTypeInformation定义于/Dxe/Mem/Page.c中。

/** /Dxe/Mem/Page.c **/
  75 EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = 
  76    EfiReservedMemoryType,      0 ,
  77    EfiLoaderCode,              0 ,
  78    EfiLoaderData,              0 ,
  79    EfiBootServicesCode,        0 ,
  80    EfiBootServicesData,        0 ,
  81    EfiRuntimeServicesCode,     0 ,
  82    EfiRuntimeServicesData,     0 ,
  83    EfiConventionalMemory,      0 ,
  84    EfiUnusableMemory,          0 ,
  85    EfiACPIReclaimMemory,       0 ,
  86    EfiACPIMemoryNVS,           0 ,
  87    EfiMemoryMappedIO,          0 ,
  88    EfiMemoryMappedIOPortSpace, 0 ,
  89    EfiPalCode,                 0 ,
  90    EfiPersistentMemory,        0 ,
  91    EfiMaxMemoryType,           0  
  92 ; 

类型EFI_MEMORY_TYPE_INFORMATION则定义于/MdeModulePkg/Include/Guid/MemoryTpyeInformation.h中。

该类型EFI_MEMORY_TYPE_INFORMATION是对内存类型所占用页数的一个统计。注意到HOB数据是由PEI阶段传递而来,所有PEI阶段应该把每种内存类型所需的页数算好后存入HOB传递给DXE。

DXE找到该HOB后便拷贝出来到全局变量gMemoryTypeInformation中。

/* /MdeModulePkg/Include/Guid/MemoryTpyeInformation.h **/
 21 #ifndef __MEMORY_TYPE_INFORMATION_GUID_H__
 22 #define __MEMORY_TYPE_INFORMATION_GUID_H__
 23 
 24 #define EFI_MEMORY_TYPE_INFORMATION_GUID \\
 25    0x4c19049f,0x4137,0x4dd3,  0x9c,0x10,0x8b,0x97,0xa8,0x3f,0xfd,0xfa  
 26 
 27 #define EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME L"MemoryTypeInformation"
 28 
 29 extern EFI_GUID gEfiMemoryTypeInformationGuid;
 30 
 31 typedef struct 
 32   UINT32  Type;             ///< EFI memory type defined in UEFI specification.
 33   UINT32  NumberOfPages;    ///< The pages of this type memory.
 34  EFI_MEMORY_TYPE_INFORMATION;

4)计算所需资源大小

4) 计算所需的内存资源

/** /Dxe/Gcd/Gcd.c **/
2127   //
2128   // Include the total memory bin size needed to make sure memory bin could be allocated successfully.
2129   //
2130   MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();

其中MINIMUM_INITIAL_MEMORY_SIZE定义于本文件

/** /Dxe/Gcd/Gcd.c **/
  20 #define MINIMUM_INITIAL_MEMORY_SIZE 0x10000

函数CalculateTotalMemoryBinSizeNeeded也定义于本文件,其遍历全局变量gMemoryTypeInformation来计算所需的内存资源数。

/** /Dxe/Gcd/Gcd.c **/
2020 UINT64
2021 CalculateTotalMemoryBinSizeNeeded (
2022   VOID
2023   )
2024 
2025   UINTN     Index;
2026   UINT64    TotalSize;
2027
2028   //
2029   // Loop through each memory type in the order specified by the gMemoryTypeInformation[] array
2030   //
2031   TotalSize = 0;
2032   for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) 
2033     TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);
2034   
2035
2036   return TotalSize;
2037 

5)根据HOB寻找可用内存资源

5) 遍历所有的HOB数据,来获取可用的内存资源信息

/** /Dxe/Gcd/Gcd.c **/
2135   Found  = FALSE;
2136   for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) 

判断该HOB的类型,若不是EFI_HOB_TYPE_RESOURCE_DESCRIPTOR则跳过。

2140     if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) 
2141       continue;                                                  
2142                                                                 

如果是资源描述的HOB数据,则进一步判断是否是系统内存的资源描述,并且保证该内存区域是测试过的内存区域。

2147     ResourceHob = Hob.ResourceDescriptor;                                                      
2148     if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)                              
2149       continue;                                                                                
2150                                                                                               
2151     if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) 
2152       continue;                                                                                
2153                                                                                               

进一步判断该内存区域是否包含了HOB信息头所描述的空闲内存区域。

HOB数据的最开始是一个信息头数据结构,即EFI_HOB_HANDOFF_INFO_TABLE,其指明了PEI阶段堆的内存空间的地址范围。

本次循环所寻找的HOB资源,其描述的内存空间需要包含HOB信息头所描述的可用内存资源

2103   PhitHob = Hob.HandoffInformationTable;

2158     if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart)                              
2159       continue;                                                                                  
2160                                                                                                 
2161     if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) 
2162       continue;                                                                                  
2163                                                                                                 

找到则保存该HOB数据

2168     PhitResourceHob = ResourceHob;                                                      
2169     Found = TRUE;                                                                       

计算并比较不同可用区域的大小是否满足4)中的最小需求

2171     //                                                                                                      
2172     // Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB                   
2173     //                                                                                                      
2174     Attributes  = PhitResourceHob->ResourceAttribute;                                                       
2175     BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);                                                 
2176     Length      = PageAlignLength  (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);
2177     if (Length < MinimalMemorySizeNeeded)                                                                  
2178       //                                                                                                    
2179       // If that range is not large enough to intialize the DXE Core, then                                  
2180       // Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop                           
2181       //                                                                                                    
2182       BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);                                        
2183       Length      = PageAlignLength  (PhitHob->EfiFreeMemoryTop - BaseAddress);                             
2184       if (Length < MinimalMemorySizeNeeded)                                                                
2185         //                                                                                                  
2186         // If that range is not large enough to intialize the DXE Core, then                                
2187         // Compute range between the start of the Resource Descriptor HOB and the start of the HOB List     
2188         //                                                                                                  
2189         BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);                                        
2190         Length      = PageAlignLength  ((UINT64)((UINTN)*HobStart - BaseAddress));                          
2191                                                                                                            
2192                                                                                                            
2193     break;                                                                                                  

这边需要详细解释HOB数据的位置以及PEI阶段的堆空间,才有可能完全理解这段代码的含义。


6)若找不到则继续寻找

6) 若5)中找到的可用内存空间仍旧不满足最小的内存需求,则继续寻找其他空间

2207   if (Length < MinimalMemorySizeNeeded)   
/** 寻找其他内存空间 **/
2266    

首先获取到地址上限

2074   EFI_PHYSICAL_ADDRESS               HighAddress;

2213     HighAddress = MAX_ADDRESS;

MAX_ADDRESS定义于MdePkg/Include/$arch/ProcessorBind.h文件中。

搜索可以采用grep命令快速定位到寻找的内容,不过如果对源码结构比较熟悉,或想凭自己的理解摸索一下,建议直接到文件目录中寻找。往往我是没什么别的办法来才使用这个命令。

~/edk2 (UDK2017*) $ grep "#define MAX_ADDRESS" -Rn
MdePkg/Include/AArch64/ProcessorBind.h:94:#define MAX_ADDRESS   0xFFFFFFFFFFFFFFFFULL
MdePkg/Include/Arm/ProcessorBind.h:100:#define MAX_ADDRESS  0xFFFFFFFF
MdePkg/Include/Ipf/ProcessorBind.h:237:#define MAX_ADDRESS   0xFFFFFFFFFFFFFFFFULL
MdePkg/Include/Ia32/ProcessorBind.h:247:#define MAX_ADDRESS   0xFFFFFFFF
MdePkg/Include/Ebc/ProcessorBind.h:104:#define MAX_ADDRESS   ((UINTN) ~0)
MdePkg/Include/X64/ProcessorBind.h:261:#define MAX_ADDRESS   0xFFFFFFFFFFFFFFFFULL
grep: EmulatorPkg/Unix/Host/X11IncludeHack: 没有那个文件或目录
BaseTools/Source/C/Include/AArch64/ProcessorBind.h:96:#define MAX_ADDRESS  0xFFFFFFFFFFFFFFFF
BaseTools/Source/C/Include/Arm/ProcessorBind.h:94:#define MAX_ADDRESS  0xFFFFFFFF
BaseTools/Source/C/Include/Ia32/ProcessorBind.h:137:#define MAX_ADDRESS   0xFFFFFFFF
BaseTools/Source/C/Include/X64/ProcessorBind.h:156:#define MAX_ADDRESS   0xFFFFFFFFFFFFFFFFULL

遍历HOB数据,跳过5)中所找到的HOB,跳过不是资源描述的,跳过不是描述系统内存资源的,跳过内存资源是没有经过测试的

但是不要求包含HOB信息头描述的可用内存区域了

2214     for (Hob.Raw = *HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) 

2218       if (Hob.ResourceDescriptor == PhitResourceHob) 
2219         continue;                                     
2220                                                      

2224       if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) 
2225         continue;                                                  
2226                                                                   

2231       ResourceHob = Hob.ResourceDescriptor;                                                                
2232       if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY)                                        
2233         continue;                                                                                          
2234                                                                                                           
2235       if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES)           
2236         continue;                                                                                          
2237              

跳过最高地址超过了上限的HOB数据

2238       if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS) 
2239         continue;                                                                                          
2240                                                                                                           

跳过所描述地址空间低于 上一个遍历的HOB数据的地址空间 的HOB数据,for循环的最后会修改HighAddress的值。

2238       if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ADDRESS) 
2239         continue;                                                                                          
2240       

2264       HighAddress = ResourceHob->PhysicalStart; 
2265      // end for

跳过不满足空间需求的

2252       TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);                                            
2253       TestedMemoryLength      = PageAlignLength  (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);
2254       if (TestedMemoryLength < MinimalMemorySizeNeeded)                                                                  
2255         continue;                                                                                                         
2256       

好的,我们找到了

2261       BaseAddress = TestedMemoryBaseAddress;        
2262       Length      = TestedMemoryLength;             
2263       Attributes  = ResourceHob->ResourceAttribute; 

输出到DEBUG信息中,表示很开心 :)

2268   DEBUG ((EFI_D_INFO, "CoreInitializeMemoryServices:\\n"));
2269   DEBUG ((EFI_D_INFO, "  BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\\n", BaseAddress, Length, MinimalMemorySizeNeeded));

assert一下,表示很有信心:)如果到这里还找不到,那就没法继续了

2274   ASSERT (Length >= MinimalMemorySizeNeeded);

7)转换内存属性到掩码形式

7) 把内存资源的属性Atrributes转换成Memory Capabilities掩码

2276   //                                                                                                                   
2277   // Convert the Resource HOB Attributes to an EFI Memory Capabilities mask                                            
2278   //                                                                                                                   
2279   if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE)                    
2280     Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
2281    else                                                                                                              
2282     Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
2283   

8)添加内存资源描述符,建立内存服务

8) 使用该内存区域建立最初的内存资源,之后内存服务已经完全可用了

2285   //
2286   // Declare the very first memory region, so the EFI Memory Services are available.
2287   //
2288   CoreAddMemoryDescriptor (
2289     EfiConventionalMemory,
2290     BaseAddress,
2291     RShiftU64 (Length, EFI_PAGE_SHIFT),
2292     Capabilities
2293     );

函数CoreAddMemoryDescriptor位于/Dxe/Mem/Page.c中。

/** /Dxe/Mem/Page.c **/
 530 VOID                                     
 531 CoreAddMemoryDescriptor (                
 532   IN EFI_MEMORY_TYPE       Type,         
 533   IN EFI_PHYSICAL_ADDRESS  Start,        
 534   IN UINT64                NumberOfPages,
 535   IN UINT64                Attribute     
 536   )                                      
 537  
 /** 建立内存服务 **/
 679  

检查是否页对齐

/** /Dxe/Mem/Page.c **/
 543   if ((Start & EFI_PAGE_MASK) != 0) 
 544     return; 
 545     

检查内存类型的合法性

/** /Dxe/Mem/Page.c **/
 547   if (Type >= EfiMaxMemoryType && Type < MEMORY_TYPE_OEM_RESERVED_MIN) 
 548     return; 
 549     

内存类型的范围描述在/Dxe/Mem/Imem.h

/** /Dxe/Mem/Imem.h **/
 18 //                                                            
 19 // +---------------------------------------------------+      
 20 // | 0..(EfiMaxMemoryType - 1)    - Normal memory type |      
 21 // +---------------------------------------------------+      
 22 // | EfiMaxMemoryType..0x6FFFFFFF - Invalid            |      
 23 // +---------------------------------------------------+      
 24 // | 0x70000000..0x7FFFFFFF       - OEM reserved       |      
 25 // +---------------------------------------------------+      
 26 // | 0x80000000..0xFFFFFFFF       - OS reserved        |      
 27 // +---------------------------------------------------+      
 28 //                                                            
 29 #define MEMORY_TYPE_OS_RESERVED_MIN                 0x80000000
 30 #define MEMORY_TYPE_OS_RESERVED_MAX                 0xFFFFFFFF
 31 #define MEMORY_TYPE_OEM_RESERVED_MIN                0x70000000
 32 #define MEMORY_TYPE_OEM_RESERVED_MAX                0x7FFFFFFF

随后开始真正的建立内存服务。

/** /Dxe/Mem/Page.c **/
 550   CoreAcquireMemoryLock ();                                    
 551   End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1; 
 552   CoreAddRange (Type, Start, End, Attribute);                  
 553   CoreFreeMemoryMapStack ();                                   
 554   CoreReleaseMemoryLock ();

明明以为到这里就开始建立了,结果却又跳转到一个函数。

实际上复杂的系统中这种情况很常见,真正干实际事情的代码隐藏在层层调用之中。这是因为往往需要有大量的检查工作,而且如果所有代码都放在一个函数里实现,通常会显得很臃肿。

Lock机制在这里就不详细讲了,最底层的实现是禁中断。这是因为UEFI系统只用了一个处理器核。详细会在异步事件机制中分析。

CoreAddRange将在后面操作内存的接口函数中详细描述。

/** /Dxe/Mem/Page.c **/
 569   if (mMemoryTypeInformationInitialized)  
 570     return;                                
 571                                           

内存服务建立后,我们需要使用MemoryTypeInformation信息来进行测试。全局变量mMemoryTypeInformationInitialized用于标记是否完成来内存测试工作,在本函数的结尾会标记为TRUE,若在某次申请测试时出错则会直接返回,从而该标记不会被置为真。

在前文的3)中从HOB中获取的内存类型信息,描述了各种类型的内存所需要的页数,随后在4)中我们据此计算出了最小的内存空间需求。之后的5)和6)均是在这最小的内存空间需求下寻找合适的内存空间。

首先我们遍历所有的内存类型信息

/** /Dxe/Mem/Page.c **/
 577   for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++)  
 581     Type = (EFI_MEMORY_TYPE) (gMemoryTypeInformation[Index].Type);                   
 582     if ((UINT32)Type > EfiMaxMemoryType)                                            
 583       continue;
 584     

如果某个内存类型所需要的页数不为零,则申请这么多页大小的空间。CoreAllocatePages会在后面详述。

/** /Dxe/Mem/Page.c **/
 585     if (gMemoryTypeInformation[Index].NumberOfPages != 0)    
 589       Status = CoreAllocatePages (                            
 590                  AllocateAnyPages,                            
 591                  Type,                                        
 592                  gMemoryTypeInformation[Index].NumberOfPages, 
 593        

以上是关于UEFI.源码分析.DXE的内存服务.第一部分.初始化的主要内容,如果未能解决你的问题,请参考以下文章

UEFI.源码分析.DXE的异步事件服务.第一部分.事件驱动

UEFI.源码分析.DXE的异步事件服务.第一部分.事件驱动

UEFI.源码分析.DXE的异步事件服务.第二部分.任务优先级

UEFI.源码分析.DXE的异步事件服务.第二部分.任务优先级

UEFI.源码分析.DXE的异步事件服务.第三部分.定时器与时钟中断

UEFI.源码分析.DXE的异步事件服务.第三部分.定时器与时钟中断