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

相关文章

SpringBoot实现RSA+AES自动接口解密的实战指南

《SpringBoot实现RSA+AES自动接口解密的实战指南》在当今数据泄露频发的网络环境中,接口安全已成为开发者不可忽视的核心议题,RSA+AES混合加密方案因其安全性高、性能优越而被广泛采用,本... 目录一、项目依赖与环境准备1.1 Maven依赖配置1.2 密钥生成与配置二、加密工具类实现2.1

使用Python的requests库调用API接口的详细步骤

《使用Python的requests库调用API接口的详细步骤》使用Python的requests库调用API接口是开发中最常用的方式之一,它简化了HTTP请求的处理流程,以下是详细步骤和实战示例,涵... 目录一、准备工作:安装 requests 库二、基本调用流程(以 RESTful API 为例)1.

在Linux系统上连接GitHub的方法步骤(适用2025年)

《在Linux系统上连接GitHub的方法步骤(适用2025年)》在2025年,使用Linux系统连接GitHub的推荐方式是通过SSH(SecureShell)协议进行身份验证,这种方式不仅安全,还... 目录步骤一:检查并安装 Git步骤二:生成 SSH 密钥步骤三:将 SSH 公钥添加到 github

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

Linux系统之lvcreate命令使用解读

《Linux系统之lvcreate命令使用解读》lvcreate是LVM中创建逻辑卷的核心命令,支持线性、条带化、RAID、镜像、快照、瘦池和缓存池等多种类型,实现灵活存储资源管理,需注意空间分配、R... 目录lvcreate命令详解一、命令概述二、语法格式三、核心功能四、选项详解五、使用示例1. 创建逻

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

linux重启命令有哪些? 7个实用的Linux系统重启命令汇总

《linux重启命令有哪些?7个实用的Linux系统重启命令汇总》Linux系统提供了多种重启命令,常用的包括shutdown-r、reboot、init6等,不同命令适用于不同场景,本文将详细... 在管理和维护 linux 服务器时,完成系统更新、故障排查或日常维护后,重启系统往往是必不可少的步骤。本文

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例