当前位置: 首页 > article >正文

Secure boot入门-2fip包加载image流程

本小节从代码的角度去看下代码环境准备还是参考之前的文章ATF入门-1qmeu搭建ARM全套源码学习环境不用开发板免费学习ARM。secure boot在arm上需要用到fip包这里以bl1加载bl2为例bl2.bin是在fip.bin里面进行打包的。参考之前的文章ATF入门-3BL2启动流程分析 2.4.3中bl2镜像加载章节bl1_load_bl2函数为例进行说明。本篇文章从代码角度深挖到底进行分析bl2的加载流程纯干货实操分享欢迎下载代码进行加log打印调试上手试一试还是那句“纸上得来终觉浅须知此事需躬行”。1 使用fip.bin代码修改makearm-tfDEBUG1make-fqemu_v8.mk run-only代码下载运行不再详述了。修改atf的代码后执行上面的命令就可以运行起来。但是里面有这个打印如之前文章ATF入门-3BL2启动流程分析中说的BL2的镜像直接使用的bl2.bin而不是从fip包里面获取的这里的原因就是fip包的内容读取失败了没有进行内存映射fip包的头校验也失败了最后直接从文件获取了。首先我们来看下**是否有fip.bin**在目录说明我们编译已经生成了fip.bin既然bl2.bin都可以从文件里面读。那么我们仿照bl2.bin也搞一下。首先是在out目录里面建立软连接ln-s/home/XXX/optee/build/../trusted-firmware-a/build/qemu/debug/fip.bin fip.bin我们使用hexdump看下这个fip.bin的内容上面我们说报错Firmware Image Package header check failed.\n的地方校验代码如下/* This is used as a signature to validate the blob header */#define TOC_HEADER_NAME 0xAA640001static inline int is_valid_header(fip_toc_header_t *header){if((header-nameTOC_HEADER_NAME)(header-serial_number!0)){return1;}else{return0;}}可见我们找到的fip.bin的文件头标识是对的。那么怎么才能可以使用fip.bin我们修改代码int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec){const struct plat_io_policy *policyget_io_policy(image_id);int result;if(image_id0){returnget_alt_image_source(image_id, dev_handle, image_spec);}resultpolicy-check(policy-image_spec);if(result0){INFO($$$$plat_get_image_source check success\n);*image_specpolicy-image_spec;*dev_handle*(policy-dev_handle);}else{INFO(Trying alternative IO\n);resultget_alt_image_source(image_id, dev_handle, image_spec);}returnresult;}get_alt_image_source就是从文件里面直接去读取fip.bin的。get_alt_image_source–》open_semihosting–》get_alt_image_source–》get_io_file_spec–》sh_file_spec#define FIP_IMAGE_NAME fip.binstatic const io_file_spec_t sh_file_spec[]{[FIP_IMAGE_ID]{.pathFIP_IMAGE_NAME, .modeFOPEN_MODE_RB},2. bl1_load_bl2过程函数解析2.1 bl1_load_bl2bl1_load_bl2 bl1_plat_get_image_desc bl1_plat_handle_pre_image_load load_auth_image bl1_plat_handle_post_image_load主要就是load_auth_image去load bl2的bin文件。load_auth_image–》load_imageload_image plat_get_image_source io_open io_read io_close去获取镜像的资源在哪里plat_get_image_source在qemu平台上在plat/qemu/common/qemu_io_storage.c中定义plat_get_image_source get_io_policy policy-check()get_alt_image_sourceget_io_policy获取策略入参是BL2的image id就是1策略的定义如下/* Firmware Image Package */#define FIP_IMAGE_ID U(0)/* Trusted Boot Firmware BL2 */#define BL2_IMAGE_ID U(1)/* By default, ARM platforms load images from the FIP */ static const struct plat_io_policy policies[]{[FIP_IMAGE_ID]{memmap_dev_handle,(uintptr_t)fip_block_spec, open_memmap},[BL2_IMAGE_ID]{fip_dev_handle,(uintptr_t)bl2_uuid_spec, open_fip},policy-check()对于BL2_IMAGE_ID来说就是open_fip()函数open_fip–》io_dev_init–》fip_dev_init2.2 fip_dev_init读取fipfip_dev_init plat_get_image_source io_open io_read io_closeplat_get_image_source()在plat/qemu/common/qemu_io_storage.c中实现,这时候是第二次进入这个函数了,这次的image id是0,对应的policy是[FIP_IMAGE_ID]{memmap_dev_handle,(uintptr_t)fip_block_spec, open_memmap},这个policy有问题读不出来fip的内容因为对于头文件校验失败fip_dev_init–》io_read–》is_valid_headertypedef struct fip_toc_header{uint32_t name;uint32_t serial_number;uint64_t flags;}fip_toc_header_t;static inline int is_valid_header(fip_toc_header_t *header){if((header-nameTOC_HEADER_NAME)(header-serial_number!0)){return1;}else{return0;}}我们直接使用get_alt_image_source来在plat_get_image_source()函数里面添加int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec){const struct plat_io_policy *policyget_io_policy(image_id);int result;if(image_id0){returnget_alt_image_source(image_id, dev_handle, image_spec);}这样读出来fip.bin再回到load_image函数里面执行io_open/io_read/io_close操作把bl2.bin从fip.bin里面成功加载到内存中。2.3 从fip读取bl2.binio_open–》fip_file_openstatic int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity){const io_uuid_spec_t *uuid_spec(io_uuid_spec_t *)spec;resultio_open(backend_dev_handle, backend_image_spec,backend_handle);/* Seek past the FIP header into the Table of Contents */ resultio_seek(backend_handle, IO_SEEK_SET,(signed long long)sizeof(fip_toc_header_t));do{resultio_read(backend_handle,(uintptr_t)current_fip_file.entry, sizeof(current_fip_file.entry),bytes_read);if(result0){if(compare_uuids(current_fip_file.entry.uuid,uuid_spec-uuid)0){found_file1;}}else{WARN(Failed to read FIP (%i)\n, result);goto fip_file_open_close;}}while((found_file0)(compare_uuids(current_fip_file.entry.uuid,uuid_null)!0));spec是从policy里面获取到的从上面代码里面看从fip包里面找bl2.bin是需要借助这个变量进行比对的bl2_uuid_spec定义为static const io_uuid_spec_t bl2_uuid_spec{.uuidUUID_TRUSTED_BOOT_FIRMWARE_BL2,};#define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \{{0x5f, 0xf9, 0xec, 0x0b},{0x4d, 0x22},{0x3e, 0x4d}, 0xa5, 0x44,{0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a}}关于fip包的操作都在drivers/io/io_fip.c文件里面。fip包的格式如下------------------|ToC Header||----------------||ToC Entry0||----------------||ToC Entry1||----------------||ToC End Marker||----------------||||Data0||||----------------||||Data1|||------------------下面我们详细看下怎么读取里面的内容首先就是获取fip.bin的内存地址到backend_handle。backend_dev_handle和backend_image_spec是在打开fip.bin的时候调用fip_dev_init函数的时候拿到的全局变量这里直接使用。resultio_open(backend_dev_handle, backend_image_spec,backend_handle);然后定位去掉fip文件的头ToC Header也就是结构体fip_toc_header_tresultio_seek(backend_handle, IO_SEEK_SET,(signed long long)sizeof(fip_toc_header_t));typedef struct fip_toc_header{uint32_t name;uint32_t serial_number;uint64_t flags;}fip_toc_header_t;之后就是ToC Entry 0这里我们循环读取到current_fip_file.entry变量中resultio_read(backend_handle,(uintptr_t)current_fip_file.entry, sizeof(current_fip_file.entry),bytes_read);然后跟我们传入的bl2的uuid_spec-uuid进行比较if(compare_uuids(current_fip_file.entry.uuid,uuid_spec-uuid)0){found_file1;}typedef struct fip_toc_entry{uuid_t uuid;uint64_t offset_address;uint64_t size;uint64_t flags;}fip_toc_entry_t;typedef struct uuid uuid_t;struct uuid{uint8_t time_low[4];uint8_t time_mid[2];uint8_t time_hi_and_version[2];uint8_t clock_seq_hi_and_reserved;uint8_t clock_seq_low;uint8_t node[_UUID_NODE_LEN];};可见uuid是一个有6个元素的结构体跟include/tools_share/firmware_image_package.h中的定义一致#define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \{{0x5f, 0xf9, 0xec, 0x0b},{0x4d, 0x22},{0x3e, 0x4d}, 0xa5, 0x44,{0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a}}对比好uuid就可以拿到struct fip_toc_entry结构体的第二个元素offset_address的值和size的值。这里只是找到fip.bin中bl2.bin的位置了**读到内存中**是发生在load_image–》plat_get_image_source–》io_read–》fip_file_readstatic int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read){fip_file_state_t *fp;fp(fip_file_state_t *)entity-info;/* Seek to the positioninthe FIP where the payload lives */ file_offsetfp-entry.offset_address fp-file_pos;resultio_seek(backend_handle, IO_SEEK_SET,(signed long long)file_offset);传入是是结构体io_entity_t里面entity-info才是fip_file_state_t嵌套关系如下typedef struct io_entity{struct io_dev_info *dev_handle;uintptr_t info;}io_entity_t;typedef struct{unsigned int file_pos;fip_toc_entry_t entry;}fip_file_state_t;typedef struct fip_toc_entry{uuid_t uuid;uint64_t offset_address;uint64_t size;uint64_t flags;}fip_toc_entry_t;那么这个是怎么获取的读之前是先打开的load_image–》plat_get_image_source–》io_open–》fip_file_openstatic int load_image(unsigned int image_id, image_info_t *image_data){uintptr_t image_handle;io_resultio_open(dev_handle, image_spec,image_handle);static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity){if(found_file1){/* All fine. Update entity info withfilestate and return. Set * thefileposition to0. Thecurrent_fip_file.entryholds * the base and size of the file. */ current_fip_file.file_pos0;entity-info(uintptr_t)current_fip_file;}可见fip_file_open中找到uuid对应的bl2.bin后就把entity的info赋值了。下图是笔者调试的一些打印调试的时候如果一下启动到linux里面打印非常的多我们可以让起到我们想研究的地方就停下来调用如下代码就可以了void __dead2 plat_error_handler(int err){while(1)wfi();}后记上面的分析是从fip包里面读取bl2.bin镜像对于secure boot来说有两点1.信任链2.加解密。这里bl1加载bl2有了信任链但是这里缺少一个流程那就是加解密。下一个文章我们再详细介绍这里先把fip包搞明白。最近一忙起来点抽空看这个代码就比较费劲老是看了一会就忘记之前看到那个流程了。后来感觉需要画一个流程图帮助记忆这样下一次再看的时候很快就能顺起来就这样断断续续看了一周才看完老铁们不容易啊赶紧收藏研究比自己看代码事半功倍。“啥都懂一点啥都不精通干啥都能干干啥啥不是专业入门劝退堪称程序员杂家”。欢迎各位有自己公众号的留言申请转载纯干货持续更新欢迎分享给朋友、点赞、收藏、在看、划线和评论交流“那路谈OS与SoC嵌入式软件”欢迎关注个人文章汇总https://thatway1989.github.io

相关文章:

Secure boot入门-2fip包加载image流程

本小节从代码的角度去看下,代码环境准备还是参考之前的文章:ATF入门-1qmeu搭建ARM全套源码学习环境,不用开发板免费学习ARM。 secure boot在arm上需要用到fip包,这里以bl1加载bl2为例,bl2.bin是在fip.bin里面进行打包…...

Secure boot入门-1基本概念和框架

Secure boot说是为了防止黑客篡改系统,窃取你的数据。但是你的数据一般值得黑客窃取么,我想更重要的原因是商业利益:防止水货和自己偷偷升级不给服务费占据垄断地位,防止黑客二次加工卖钱,防止搞破坏产品不能用。 所以…...

uboot入门-6移植要点

本篇作为结尾先对之前的文章进行下汇总: uboot入门-1简介和运行 uboot入门-2Makefile和编译 uboot-3链接脚本和第一阶段启动 uboot入门-4命令行和驱动管理 uboot入门-5linux启动前夜 uboot入门-6移植要点–本篇 对于uboot移植需要先搞清楚下面几个概念&#…...

哔哩下载姬:B站视频下载工具的专业解决方案与技术应用指南

哔哩下载姬:B站视频下载工具的专业解决方案与技术应用指南 【免费下载链接】downkyi 哔哩下载姬downkyi,哔哩哔哩网站视频下载工具,支持批量下载,支持8K、HDR、杜比视界,提供工具箱(音视频提取、去水印等&a…...

K8s 1.36 新特性深度解析:服务网格与零信任集成(生产级配置)

K8s 1.36 新特性深度解析:服务网格与零信任集成(生产级配置) 前言:K8s 1.36 被称为“云原生安全网络里程碑”版本,核心突破集中在「服务网格原生化」和「零信任落地」两大板块——彻底解决了过去服务网格“资源占用高、…...

丹青幻境使用技巧:批量生成、种子控制、作品管理全攻略

丹青幻境使用技巧:批量生成、种子控制、作品管理全攻略 1. 丹青幻境核心功能概览 丹青幻境(Z-Image Atelier)是一款融合东方美学与先进AI技术的数字艺术创作工具。它基于Z-Image架构和Cosplay LoRA技术构建,为创作者提供了独特的…...

开箱即用!霜儿-汉服-造相Z-Turbo镜像部署及初体验报告

开箱即用!霜儿-汉服-造相Z-Turbo镜像部署及初体验报告 1. 镜像概述与核心价值 霜儿-汉服-造相Z-Turbo是一款专为古风汉服人像生成优化的AI模型镜像。基于Z-Image-Turbo架构并融合定制LoRA技术,它能将文字描述快速转化为精美的汉服少女图像。这个开箱即…...

智慧树刷课插件:3步实现自动化学习,告别手动刷课烦恼

智慧树刷课插件:3步实现自动化学习,告别手动刷课烦恼 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 还在为智慧树平台的网课学习而烦恼吗&…...

Hitboxer SOCD清理器架构解析:游戏按键重映射系统的深度优化

Hitboxer SOCD清理器架构解析:游戏按键重映射系统的深度优化 【免费下载链接】socd Key remapper for epic gamers 项目地址: https://gitcode.com/gh_mirrors/so/socd 在竞技游戏领域,操作精度往往决定胜负。传统键盘输入在同时按下相反方向键时…...

BKIN 完整链路评估

BKIN 完整链路评估(基于当前代码) 1. 结论摘要 当前工程已形成“硬件秒级切断 + 软件锁存 + 状态机收敛”的 BKIN 保护闭环。 硬件链路由 TIM0 BKIN 直接触发 BRK,会在硬件侧优先拉低主输出使能(MOE 关闭),具备最高优先级。 软件链路通过 TIMER0_BRK_IRQHandler 和 prot…...

Meta:AIRA2系统突破AI科研Agent瓶颈

📖标题:AIRA_2: Overcoming Bottlenecks in AI Research Agents 🌐来源:arXiv, 2603.26499v1 🌟摘要 现有的研究已经确定了人工智能研究代理中的三个结构性性能瓶颈:(1)同步单GPU执行…...

AI知识库集问答

框架图架构图(模块视角)当前真实生效路径(精简图)“知识库”模块,当前实现可以概括为:文档管理 上下文拼接式问答(非RAG检索库),主问答链路是 单智能体调用 DeepSeek。先…...

3步精通安卓虚拟定位:FakeLocation实现应用级位置模拟的终极指南

3步精通安卓虚拟定位:FakeLocation实现应用级位置模拟的终极指南 【免费下载链接】FakeLocation Xposed module to mock locations per app. 项目地址: https://gitcode.com/gh_mirrors/fak/FakeLocation 在数字时代,位置信息已成为个人隐私的最后…...

终极NS-USBLoader使用指南:三分钟掌握Switch文件传输与RCM注入

终极NS-USBLoader使用指南:三分钟掌握Switch文件传输与RCM注入 【免费下载链接】ns-usbloader Awoo Installer and GoldLeaf uploader of the NSPs (and other files), RCM payload injector, application for split/merge files. 项目地址: https://gitcode.com/…...

医疗用气电混合连接器:实现安全性与稳定性平衡的实用技巧

想必从事医疗设备开发的各位都有同感:如今的设备变得越来越复杂。尤其是在需要同时传输气体和电信号的场合,可以说一个小小的连接器就能左右整个设备的可靠性。请不要低估这个"配角"的作用。一旦出现问题,轻则导致设备错误或停机&a…...

NVIDIA Profile Inspector终极指南:解锁显卡隐藏设置,轻松提升游戏性能

NVIDIA Profile Inspector终极指南:解锁显卡隐藏设置,轻松提升游戏性能 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector NVIDIA Profile Inspector是一款功能强大的显卡配置工具&…...

ViGEmBus终极指南:在Windows上免费实现完美虚拟手柄映射

ViGEmBus终极指南:在Windows上免费实现完美虚拟手柄映射 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus ViGEmBus是一款专业的Windows内核级虚拟…...

如何在Windows上解决游戏控制器兼容性问题:ViGEmBus虚拟驱动完全指南

如何在Windows上解决游戏控制器兼容性问题:ViGEmBus虚拟驱动完全指南 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 还在为Windows游戏控制器不…...

矽力杰 Silergy SY7066 同步升压转换器 规格书 佰祥电子

突破便携式设备低输入供电、大电流驱动、小型化集成痛点!SY7066:6A 峰值电流 同步整流升压的五大核心优势便携式单节锂电与双节电池供电设备普遍面临低输入电压下难以稳定启动、大电流输出工况转换效率偏低、芯片体积过大无法适配超薄便携产品设计三大行…...

华硕无畏Pro14 K6400ZC 原厂Win11 21H2系统分享下载

华硕无畏Pro14 K6400ZC配备了一键恢复功能,方便用户在系统异常或更换硬盘后轻松恢复出厂设置。该功能支持Windows 11 21H2家庭版系统,并通过原厂工厂文件和隐藏恢复分区实现。用户只需准备一个20G以上的U盘,按照提供的安装教程操作即可完成系…...

华硕ROG 超神2s G703 G7AI G703VI 原厂Win10系统分享下载

华硕ROG超神2s系列笔记本(包括G703、G7AI、G703VI型号)预装了Windows 10家庭版系统,并提供了一键恢复功能,便于用户在系统异常或更换硬盘后快速恢复出厂设置。若该功能失效,用户可使用原厂提供的工厂文件通过U盘进行恢…...

华硕灵耀X双屏Pro UX8402Z 原厂Win11 22H2系统分享下载

华硕灵耀X双屏Pro UX8402Z配备了一键恢复功能,即使系统出现异常或更换硬盘后,也能通过原厂工厂文件轻松恢复至出厂状态。该功能支持UX8402ZA和UX8402ZE型号,预装Windows 11 22H2家庭版。用户只需准备相应工具并按照安装教程操作即可。这一便捷…...

MySQL 自增列的分布式实现

MySQL自增列的分布式实现:突破单机限制的解决方案 在分布式系统中,MySQL自增列的单机实现面临严峻挑战。传统的自增ID依赖于单机序列,难以满足高并发、高可用的分布式场景需求。如何实现全局唯一、有序递增的ID,成为架构设计的关…...

OBS多平台直播插件:如何一次性解决多平台直播的三大痛点

OBS多平台直播插件:如何一次性解决多平台直播的三大痛点 【免费下载链接】obs-multi-rtmp OBS複数サイト同時配信プラグイン 项目地址: https://gitcode.com/gh_mirrors/ob/obs-multi-rtmp 你是否曾经为了在不同直播平台同步直播而手忙脚乱?你是否…...

Java 后端完整成长路线(含项目)

下面这份路线是我按真实公司后端成长路径给你设计的,不是培训班那种“技术名词堆砌版”,而是一步一步把你从“会写 Java”带到“能做后端项目”。我会分 阶段 目标 你该干什么 典型产出 来讲。一、你的专属起点定位(先对齐)✅ …...

FlowState Lab在农业科技的应用:基于环境时序数据的作物生长预测

FlowState Lab在农业科技的应用:基于环境时序数据的作物生长预测 1. 农业科技的新机遇 最近几年,农业领域正在经历一场数字化转型。传统"靠天吃饭"的种植方式逐渐被数据驱动的精准农业所取代。在这个过程中,如何利用农田里产生的…...

双膜气柜:生物质燃气存储的柔性恒压方案

在绿色发展与循环经济成为主流的当下,沼气等生物质燃气的高效、安全储存,是打通废弃物处理与清洁能源利用的关键纽带。双膜气柜作为柔性储气解决方案,凭借恒压稳定、防腐耐用、低维护等优势,已广泛应用于市政污水处理、农业沼气工…...

2026会话存档是什么?新版会话存档有什么功能?

一.概述会话内容存档产品——乐聊会话助手plus是由贵州遐宇科技服务有限公司与企业微信合作产品。此产品是基于企业微信会话存档API接口进行二次开发的监管系统,2024年1月登记为软件作品正式发行。该系统提供企业会话内容存档管理、超时回复提醒、员工客户互动过程合…...

基于RVC模型的实时合唱系统:单人模拟多人合唱效果

基于RVC模型的实时合唱系统:单人模拟多人合唱效果 你有没有想过,一个人也能唱出气势磅礴的合唱效果?以前这可能需要一个录音棚和一群专业歌手,但现在,借助AI技术,一个人、一台电脑就能轻松实现。今天要聊的…...

大模型提取结构化JSON——生产级

目录 输出结构化符合预期的Json Phase 1: 提示工程约束 (Prompt Engineering) Phase 2: 原生协议控制 (Native Protocol Control) 深入浅出:如何用 Function Calling 提取结构化数据 第一步:把“提取动作”包装成一个“函数说明 (Schema)” 第二步:向大模型发起对话请…...