Cstyle的UEFI导读:PEI Image Service

本文介绍了UEFI BIOS固件在XIP模式下的执行环境,特别是如何在PEI阶段通过PEI Core的Image Service将代码从Flash读取到RAM中,并在RAM中执行。固件的各个段在不同阶段的状态、如何初始化RAM以及如何使用PeiImageRead函数进行内存拷贝等关键点进行了阐述。

===================================================================== 

固件C字营·版权所有·欢迎转载
敬请关注微信公众号:“固件C字营”
敬请关注QQ群:1052307
敬请关注优快云博客:Cstyle_0x007

图片

===================================================================== 

        所谓”固件“原始的定义是被固化的软件。历史上存储固件的介质有很多类似EEROM、Flash等,目前在UEFI固件领域基本都是用的NorFlash,它最大的特点是支持XIP也即片上执行。UEFI BIOS固件基本都是使用SPI接口的NorFlash来存储。目标二进制固件文件通常包括代码段(code)、只读数据段(RO Data)、已初始化读写数据段(RW Data)、BSS段、堆、栈、以及其他的资源段。固件在XIP阶段的代码在链接的时候,链接地址与存储地址是相同的都会是0x00000000,在C代码开始之前通过crt0库把读写数据段(RW Data)拷贝到可读可写的内存、在内存中创建并初始化BSS段,堆、栈,C代码提供基本的运行环境。下表是固件在XIP执行的时候每一个段的状态,RO Data不需要写因此不需要拷贝到RAM当中,同理在RAM没有准备好之前即使是读写数据段也是只读的,再有就是堆段与栈段在内存没有准备好之前也是不可用。

资源类型

状态

固化阶段

初始化阶段

运行阶段

代码段(Code)

存储在flash

存储在flash

存储在flash

只读数据段(RO Data)

存储在flash

存储在flash

存储在flash

读写数据段(RW Data)

存储在flash

拷贝到RAM

在RAM中读写

未初始化数据段(BSS)

存储在flash

在RAM中创建并清零

在RAM中读写

堆(heap)

存储在flash

在RAM中创建并清零

在RAM中读写

栈(stack)

存储在flash

在RAM中创建并清零

在RAM中读写

在X86当中,SEC阶段及PEI阶段的第一阶段都是XIP模式,也就意味着:

  1. 代码是直接在flash上XIP执行
  2. 早期内存不可用
  3. 堆、栈都不可用,无法通过栈来作为调用栈使用
  4. C语言代码不可执行
  5. 全局的非静态变量(读写数据段)不可写

之前介绍过UEFI BIOS是99%的C代码加1%的汇编代码组成的,那么C代码是如何跑起来的呢?主要是通过以下几个方式来提供C语言运行环境。

  1. 早期使用寄存器作为汇编及汇编与C直接的调用栈
  2. 使用CAR来作为零时RAM,这样就等同于拥有了一块很小的RAM
  3. 在#2的基础上调用MRC初始化DDR-RAM
  4. 把固件拷贝到DDR-RAM
  5. 切换堆、栈及PC指针到新的RAM地址
  6. 至此,拥有完整的执行环境

在MdeModulePkg\Core\Pei\Image\Image.c函数PeiImageRead ()提供了从flash读取固件到RAM的服务,使用在SEC阶段传递给的EFI_SEC_PEI_HAND_OFF数据中有包含几个重要信息如:BFV地址及容量,零时RAM地址及容量,PEI阶段可用RAM地址及容量,栈地址及容量,细节可以参考《UEFI内核导读》的“SEC Core简介”相关章节。

/**

Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.

The function is used for XIP code to have optimized memory copy.

@param FileHandle - The handle to the PE/COFF file

@param FileOffset - The offset, in bytes, into the file to read

@param ReadSize - The number of bytes to read from the file starting at FileOffset

@param Buffer - A pointer to the buffer to read the data into.

@return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset

**/

EFI_STATUS EFIAPI PeiImageRead (

IN VOID *FileHandle,

IN UINTN FileOffset,

IN UINTN *ReadSize,

OUT VOID *Buffer

)

{

CHAR8 *Destination8;

CHAR8 *Source8;

Destination8 = Buffer;

Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);

if (Destination8 != Source8) {

CopyMem (Destination8, Source8, *ReadSize);

}

return EFI_SUCCESS;

}

综上述代码可见:

  1. PEI Core及部分PEIM在PEI第一阶段被复制到RAM当中,PEI第二阶段代码在RAM中被执行。
  2. 使用内存拷贝的方法,在X86架构中使用的是MOV类指令,而不是IN/OUT类似的IO指令。
  3. PEI Core的Image service基于PeiImageRead()从flash的读取BFV内的FFS文件并从中查找PE/TE格式可执行文件,relocates到永久DDR RAM当中以备PEI第二阶段执行,或读取查找其他类型文件。

参考代码实现:

\MdeModulePkg\Core\Pei\Image\Image.c

\MdeModulePkg\Core\Dxe\Image\Image.c

转载请注明出处,或可关注微信公众号:固件C字营

===================================================================== 

固件C字营·版权所有·欢迎转载
敬请关注微信公众号:“固件C字营”
敬请关注QQ群:1052307
敬请关注优快云博客:Cstyle_0x007

图片

===================================================================== 

@微信公众号《固件C字营》不定期更新状态,关注&订阅公众号不迷路。

完整PDF版整理中,可以在优快云下载频道搜索”UEFI内核导读“下载样张......

随着国家十四五新战略规划的推出,众多国内企业都参与到国产芯片替代浪潮中来,可以预测未来越多的国产芯片会被设计、生产和使用在我们日常所使用的电子产品中,国产芯片拥有巨大的市场前景。 目前国产芯片采用的体系架构主要有X86、ARM、MIPS、RISC V、PowerPC、Alpha等。我们知道电子产品正常工作必须要有操作系统和各种应用软件,没有操作系统和应用软件的芯片就是一堆废铁,而大多数人并不知道的是没有系统固件来加载操作系统的电脑亦是一堆废铁, UEFI就是由UEFI行业协会提出和维护一种行业标准的系统固件,它支持目前市面上的大多数芯片体系结构和操作系统,随着标准的不断演进相信越来越多的体系结构的芯片和操作系统会被支持。 笔者从事BIOS开发已有十余年的时间,见证了Legacy BIOS辉煌与隐退,也有幸了参与了新世纪初系统固件从Legacy BIOS往UEFI BIOS的迁移的全过程。科技行业风起云涌新技术新架构日新月异,每每回望不禁感慨我辈可谓是“眼见着他起高楼,眼见着他宴宾客”的那一波BIOS人。曾经系统固件江湖还是Legacy BIOS的天下,BIOS人使用汇编语言编码、通过中断来与操作系统沟通。自UEFI框架被广泛使以来开我们的发环境从纯汇编变成了99%的C语言加1%的汇编语言的模式,开发效率大大的加强了。 虽然UEFI框架大大加快了开发效率,但是由于系统固件开发属于比较偏门和专业的领域,学习和入门门槛比较高,现有的BIOS工程师又分布在大大小小的各个公司内部缺乏有效沟通和交流,同时BIOS源码又属于敏感和机密数据受到各种NDA限制,市面上对UEFI框架介绍的资料少之又少,因此笔者从2000左右开始就陆续以Cstyle_0x007为ID在https://blog.youkuaiyun.com/CStyle_0x007发布一系列博文,现已有数十篇原创文章。刚开始的想法是把博文当作工作笔记方便自己随时查阅,后来慢慢发展成了与业内外感兴趣的朋友的沟通交流的平台。 随手写的博文难免有错误与纰漏为了避免误导大众,准备把博文重新整理在纠正谬误同时也会补充一些新的内容,尽量做到所写的每句话都是无误的,也欢迎有兴趣的朋友踊跃提出意见和建议。组建了微信公众号,目的在于方便有兴趣的朋友一起交流,名初步定为“固件C”,其中“固件”泛指一切固化的软件,这里主要指UEFI BIOS系统固件,“C”泛指“China“,我们可以把这里当作大家沟通交流的地,我们会不定时发布一些行业资讯、工作、学习心得,感兴趣扫描下面二维码就可以加入,也可以发邮件到CstyleFirmWareCamp@outlook.com投稿分享你的想法。 本文取名《UEFI内核导读》这里的UEFI专指“UEFI BIOS”,全文专注于对UEFI内核的梳理与分享,同时兼顾对X86系统固件生态中常用的工程技术的介绍,主要包含以下内容:UEFI启动流程以及各个阶段主要完成的任务及参考的实现方式导读UEFI及PI规范中的常见Protocol的实现与使用技巧UEFI固件生态中常见外设、总线、行业标准的协议内容及使用方法 雄关漫道真如铁,而今迈步从头越,系统固件雄起之路道阻且长,相信我们的BIOS人一定可以为国产芯片的起飞助力、为系统固件团队的壮大贡献自己的一份微薄之力,为每一个不畏艰难、不惧寂寞坚守在工作岗位的BIOS人加油,好样的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值