ACPI之 系统地址映射接口

2023-10-10 20:18

本文主要是介绍ACPI之 系统地址映射接口,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目前有三种方法将内存映射告诉OSPM,

1 . 通过 BIOS INT 15.

2. UEFI 通过GetMemoryMap()  boot service 告诉OS loader, 然后OS loader 告诉OSPM.

3. 如果内存资源被动态的增加或删除,我们可以通过定义在ACPI 名字空间里的内存设备去表达出来。


ACPI 定义了五种范围: AdddressRangeMemory, AddressRangeACPI, AddressRangeNVS, 

AddressRangeUnusable, AddressRangeReserved.


valueMnemonic  助记符Description
1AddressRangeMemory这一段内存是可以供操作系统使用的
2AddressRangeReserved这一段内存已经被用了,或者保留起来的,不被OS的memory manager去分配
3AddressRangeACPI当OS 读过ACPI 表之后,就可使用的一段范围
4AddressRangeNVSACPI NVS 内存,这一段内存已经被用了或者保留起来,是不能被OS去用的
5AddressRangeUnusuable这是一段不能有的地址,因为检测到了错误
6AddressRangeDisabled一段没有被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之 系统地址映射接口的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/182822

相关文章

基于C++的UDP网络通信系统设计与实现详解

《基于C++的UDP网络通信系统设计与实现详解》在网络编程领域,UDP作为一种无连接的传输层协议,以其高效、低延迟的特性在实时性要求高的应用场景中占据重要地位,下面我们就来看看如何从零开始构建一个完整... 目录前言一、UDP服务器UdpServer.hpp1.1 基本框架设计1.2 初始化函数Init详解

requests处理token鉴权接口和jsonpath使用方式

《requests处理token鉴权接口和jsonpath使用方式》文章介绍了如何使用requests库进行token鉴权接口的处理,包括登录提取token并保存,还详述了如何使用jsonpath表达... 目录requests处理token鉴权接口和jsonpath使用json数据提取工具总结reques

python调用dubbo接口的实现步骤

《python调用dubbo接口的实现步骤》本文主要介绍了python调用dubbo接口的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录 ​​其他实现方式与注意事项​​ ​​高级技巧与集成​​用 python 提供 Dubbo 接口

C++简单日志系统实现代码示例

《C++简单日志系统实现代码示例》日志系统是成熟软件中的一个重要组成部分,其记录软件的使用和运行行为,方便事后进行故障分析、数据统计等,:本文主要介绍C++简单日志系统实现的相关资料,文中通过代码... 目录前言Util.hppLevel.hppLogMsg.hppFormat.hppSink.hppBuf

Java中接口和抽象类的异同以及具体的使用场景

《Java中接口和抽象类的异同以及具体的使用场景》文章主要介绍了Java中接口(Interface)和抽象类(AbstractClass)的区别和联系,包括相同点和不同点,以及它们在实际开发中的具体使... 目录一、接口和抽象类的 “相同点”二、接口和抽象类的 “核心区别”关键区别详解(避免踩坑)三、具体使

linux系统中java的cacerts的优先级详解

《linux系统中java的cacerts的优先级详解》文章讲解了Java信任库(cacerts)的优先级与管理方式,指出JDK自带的cacerts默认优先级更高,系统级cacerts需手动同步或显式... 目录Java 默认使用哪个?如何检查当前使用的信任库?简要了解Java的信任库总结了解 Java 信

MySQL中C接口的实现

《MySQL中C接口的实现》本节内容介绍使用C/C++访问数据库,包括对数据库的增删查改操作,主要是学习一些接口的调用,具有一定的参考价值,感兴趣的可以了解一下... 目录准备mysql库使用mysql库编译文件官方API文档对象的创建和关闭链接数据库下达sql指令select语句前言:本节内容介绍使用C/

Oracle数据库在windows系统上重启步骤

《Oracle数据库在windows系统上重启步骤》有时候在服务中重启了oracle之后,数据库并不能正常访问,下面:本文主要介绍Oracle数据库在windows系统上重启的相关资料,文中通过代... oracle数据库在Windows上重启的方法我这里是使用oracle自带的sqlplus工具实现的方

基于Go语言开发一个 IP 归属地查询接口工具

《基于Go语言开发一个IP归属地查询接口工具》在日常开发中,IP地址归属地查询是一个常见需求,本文将带大家使用Go语言快速开发一个IP归属地查询接口服务,有需要的小伙伴可以了解下... 目录功能目标技术栈项目结构核心代码(main.go)使用方法扩展功能总结在日常开发中,IP 地址归属地查询是一个常见需求:

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2