本文主要是介绍ACPI之 系统地址映射接口,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目前有三种方法将内存映射告诉OSPM,
1 . 通过 BIOS INT 15.
2. UEFI 通过GetMemoryMap() boot service 告诉OS loader, 然后OS loader 告诉OSPM.
3. 如果内存资源被动态的增加或删除,我们可以通过定义在ACPI 名字空间里的内存设备去表达出来。
ACPI 定义了五种范围: AdddressRangeMemory, AddressRangeACPI, AddressRangeNVS,
AddressRangeUnusable, AddressRangeReserved.
value | Mnemonic 助记符 | Description |
1 | AddressRangeMemory | 这一段内存是可以供操作系统使用的 |
2 | AddressRangeReserved | 这一段内存已经被用了,或者保留起来的,不被OS的memory manager去分配 |
3 | AddressRangeACPI | 当OS 读过ACPI 表之后,就可使用的一段范围 |
4 | AddressRangeNVS | ACPI NVS 内存,这一段内存已经被用了或者保留起来,是不能被OS去用的 |
5 | AddressRangeUnusuable | 这是一段不能有的地址,因为检测到了错误 |
6 | AddressRangeDisabled | 一段没有被enabled的地址, 也是ospm 不可以用的 |
其他 | Undefined | 未定义,保留或者将来用。 |
BIOS 用AddressRangeReserved 把某些地址屏蔽起来,不给可编程器件去用,出于下列这些原因:
1 这段地址包含了system BIOS.
2 The address range contains RAM in use by the ROM.
3. 这段地址被memory-mapped device 使用了
4. 出于其他任何一种原因,不适合给standard device 作为memory space 用
5. 这一段地址范围位于NVRAM device里面,往这些设备去读写,不一定成功
5. The address range is within an NVRAM device where reads and writes to memory locations are
no longer successful, that is, the deice was worn out.
UEFI GetMemoryMap() Boot Service Function
EFI 使用 GetMemoryMap() boot services 这个函数将内存资源的情况告诉OS loader, 后续OS loader 一定要将这个信息传给OSPM.
GetMemoryMap 这个函数只存在于boot service 这段时间,boot time service 和 run time service 之间的界限在于ExitBootServices() 函数的执行。
GetMemoryMap() 返回一个数组,里面放着内存描述符。 这些内存描述符定义了所有安装在板子上的RAM.
每一个描述符,有这么一个成员,去标示(dictate) OS 应该怎么对待这段区域。
/**This function returns a copy of the current memory map. The map is an array ofmemory descriptors, each of which describes a contiguous block of memory.@param MemoryMapSize A pointer to the size, in bytes, of theMemoryMap buffer. On input, this is the size ofthe buffer allocated by the caller. On output,it is the size of the buffer returned by thefirmware if the buffer was large enough, or thesize of the buffer needed to contain the map ifthe buffer was too small.@param MemoryMap A pointer to the buffer in which firmware placesthe current memory map.@param MapKey A pointer to the location in which firmwarereturns the key for the current memory map.@param DescriptorSize A pointer to the location in which firmwarereturns the size, in bytes, of an individualEFI_MEMORY_DESCRIPTOR.@param DescriptorVersion A pointer to the location in which firmwarereturns the version number associated with theEFI_MEMORY_DESCRIPTOR.@retval EFI_SUCCESS The memory map was returned in the MemoryMapbuffer.@retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The currentbuffer size needed to hold the memory map isreturned in MemoryMapSize.@retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.**/
EFI_STATUS
EFIAPI
CoreGetMemoryMap (IN OUT UINTN *MemoryMapSize,IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,OUT UINTN *MapKey,OUT UINTN *DescriptorSize,OUT UINT32 *DescriptorVersion)
{EFI_STATUS Status;UINTN Size;UINTN BufferSize;UINTN NumberOfEntries;LIST_ENTRY *Link;MEMORY_MAP *Entry;EFI_GCD_MAP_ENTRY *GcdMapEntry;EFI_MEMORY_TYPE Type;EFI_MEMORY_DESCRIPTOR *MemoryMapStart;//// Make sure the parameters are valid//if (MemoryMapSize == NULL) {return EFI_INVALID_PARAMETER;}CoreAcquireGcdMemoryLock ();//// Count the number of Reserved and runtime MMIO entries// And, count the number of Persistent entries.//NumberOfEntries = 0;for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) || (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {NumberOfEntries ++;}}Size = sizeof (EFI_MEMORY_DESCRIPTOR);//// Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will// prevent people from having pointer math bugs in their code.// now you have to use *DescriptorSize to make things work.//Size += sizeof(UINT64) - (Size % sizeof (UINT64));if (DescriptorSize != NULL) {*DescriptorSize = Size;}if (DescriptorVersion != NULL) {*DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION;}CoreAcquireMemoryLock ();//// Compute the buffer size needed to fit the entire map//BufferSize = Size * NumberOfEntries;for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {BufferSize += Size;}if (*MemoryMapSize < BufferSize) {Status = EFI_BUFFER_TOO_SMALL;goto Done;}if (MemoryMap == NULL) {Status = EFI_INVALID_PARAMETER;goto Done;}//// Build the map//ZeroMem (MemoryMap, BufferSize);MemoryMapStart = MemoryMap;for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) {Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE);ASSERT (Entry->VirtualStart == 0);//// Convert internal map into an EFI_MEMORY_DESCRIPTOR//MemoryMap->Type = Entry->Type;MemoryMap->PhysicalStart = Entry->Start;MemoryMap->VirtualStart = Entry->VirtualStart;MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT);//// If the memory type is EfiConventionalMemory, then determine if the range is part of a// memory type bin and needs to be converted to the same memory type as the rest of the// memory type bin in order to minimize EFI Memory Map changes across reboots. This// improves the chances for a successful S4 resume in the presence of minor page allocation// differences across reboots.//if (MemoryMap->Type == EfiConventionalMemory) {for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) {if (mMemoryTypeStatistics[Type].Special &&mMemoryTypeStatistics[Type].NumberOfPages > 0 &&Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress &&Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) {MemoryMap->Type = Type;}}}MemoryMap->Attribute = Entry->Attribute;if (MemoryMap->Type < EfiMaxMemoryType) {if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) {MemoryMap->Attribute |= EFI_MEMORY_RUNTIME;}}//// Check to see if the new Memory Map Descriptor can be merged with an // existing descriptor if they are adjacent and have the same attributes//MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);}for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) {GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) ||((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME))) {// // Create EFI_MEMORY_DESCRIPTOR for every Reserved and runtime MMIO GCD entries//MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;MemoryMap->VirtualStart = 0;MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO;if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) {MemoryMap->Type = EfiReservedMemoryType;} else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) {MemoryMap->Type = EfiMemoryMappedIOPortSpace;} else {MemoryMap->Type = EfiMemoryMappedIO;}}//// Check to see if the new Memory Map Descriptor can be merged with an // existing descriptor if they are adjacent and have the same attributes//MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);}if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypePersistentMemory) {// // Create EFI_MEMORY_DESCRIPTOR for every Persistent GCD entries//MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress;MemoryMap->VirtualStart = 0;MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT);MemoryMap->Attribute = GcdMapEntry->Attributes | EFI_MEMORY_NV;MemoryMap->Type = EfiPersistentMemory;//// Check to see if the new Memory Map Descriptor can be merged with an // existing descriptor if they are adjacent and have the same attributes//MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);}}//// Compute the size of the buffer actually used after all memory map descriptor merge operations//BufferSize = ((UINT8 *)MemoryMap - (UINT8 *)MemoryMapStart);Status = EFI_SUCCESS;Done://// Update the map key finally//if (MapKey != NULL) {*MapKey = mMemoryMapKey;}CoreReleaseMemoryLock ();CoreReleaseGcdMemoryLock ();*MemoryMapSize = BufferSize;return Status;
}
这篇关于ACPI之 系统地址映射接口的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!