ARM64 Trust Firmware [五]
本章介绍 ATF 中的 Runtime Service 是如何定义和被调用的。
要了解 SMC,必须从 SMC 指令本身开始,其指令如下图:

指令格式为:SMC #<imm>,从官方文档了解到该指令只能在 EL1 以及更高的异常等级上调用,用户空间 EL0 是无法直接调用该指令的。
同时根据 ARM 官方文档关于 SMCCC 的描述如下:

可以知道 SMC 可以根据不同的 OEN(Owning Entity Number)区分不同分服务的功能,当注册具体了 SMC runtime service 时,需要为对应的 service 指定正确的 OEN 范围。
这里比较抽象,我们来举个例子就明白了,比如我在 Hypervisor 中介绍的关于虚拟机管理器通过 SMC 系统调用去 ATF 通过 PSCI 协议拉起从核,其中启动从核的 PSIC 的 function id 为:PSCI_CPU_ON_AARCH64(0xc4000003),不考虑后面跟的参数,也就是最终调用了:
smc #0xc4000003
按照其 32bit 划分:
- bit[31] = 1:Fast call;
- bit[32] = 0:SMC64 call convention;
- bit[29 : 24] = 4:Standard service call;
- bit[15 : 0] = 3:该类型的 call type 下的 function number;
我们对 runtime service 进行了如下的定义和分类:
- ARM Architecture Calls:获取 smcc 版本,arch features 等;
- CPU Service Calls:提供针对该平台的 CPU 实现特定服务的接口;
- SIP Service Calls:System IP 的驱动;
- OEM Service Calls:OEM 服务的接口;
- Standard Secure Service:PSCI call 就属于这个服务类型;
- ... ...
Runtime Service 的注册:
BL31 通过宏定义 DECLARE_RT_SVC 注册一个服务:
比如 Standard Service 的注册:
/* Register Standard Service Calls as runtime service */
DECLARE_RT_SVC(std_svc,OEN_STD_START,OEN_STD_END,SMC_TYPE_FAST,std_svc_setup,std_svc_smc_handler
);
比如 SIP Service 的注册:
/* Define a runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(arm_sip_svc,OEN_SIP_START,OEN_SIP_END,SMC_TYPE_FAST,arm_sip_setup,arm_sip_handler
);
在注册处理 SMC 命令服务时,DECLARE_RT_SVC 空定义定义了一个结构体__svc_desc_##_name,并将其放到了 OS 镜像的一个特殊的段.rt_svc_descs 中,其中__RT_SVC_DESCS_START__ 和__RT_SVC_DESCS_END__ 是该断的起始地址和结束地址,并且可以通过地址范围计算出服务的数量 RT_SVC_DECS_NUM:
/** Convenience macros to declare a service descriptor*/
#define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch) \static const rt_svc_desc_t __svc_desc_ ## _name \__section(".rt_svc_descs") __used = { \.start_oen = (_start), \.end_oen = (_end), \.call_type = (_type), \.name = #_name, \.init = (_setup), \.handle = (_smch) \}#define RT_SVC_DESCS \. = ALIGN(STRUCT_ALIGN); \__RT_SVC_DESCS_START__ = .; \KEEP(*(.rt_svc_descs)) \__RT_SVC_DESCS_END__ = .;
Runtime Service 的启动:
void __init runtime_svc_init(void)
{int rc = 0;uint8_t index, start_idx, end_idx;rt_svc_desc_t *rt_svc_descs;/* Assert the number of descriptors detected are less than maximum indices */assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) &&(RT_SVC_DECS_NUM < MAX_RT_SVCS));/* If no runtime services are implemented then simply bail out */if (RT_SVC_DECS_NUM == 0U)return;/* Initialise internal variables to invalid state */(void)memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices));rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START;for (index = 0U; index < RT_SVC_DECS_NUM; index++) {rt_svc_desc_t *service = &rt_svc_descs[index];/** An invalid descriptor is an error condition since it is* difficult to predict the system behaviour in the absence* of this service.*/rc = validate_rt_svc_desc(service);if (rc != 0) {ERROR("Invalid runtime service descriptor %p\n",(void *) service);panic();}/** The runtime service may have separate rt_svc_desc_t* for its fast smc and yielding smc. Since the service itself* need to be initialized only once, only one of them will have* an initialisation routine defined. Call the initialisation* routine for this runtime service, if it is defined.*/if (service->init != NULL) {rc = service->init();if (rc != 0) {ERROR("Error initializing runtime service %s\n",service->name);continue;}}/** Fill the indices corresponding to the start and end* owning entity numbers with the index of the* descriptor which will handle the SMCs for this owning* entity range.*/start_idx = (uint8_t)get_unique_oen(service->start_oen,service->call_type);end_idx = (uint8_t)get_unique_oen(service->end_oen,service->call_type);assert(start_idx <= end_idx);assert(end_idx < MAX_RT_SVCS);for (; start_idx <= end_idx; start_idx++)rt_svc_descs_indices[start_idx] = index;}
}
- 先通过RT_SVC_DESCS_START 和RT_SVC_DESCS_END 之间的大小,计算出当前的服务数量RT_SVC_DECS_NUM;
- 从RT_SVC_DESCS_START 位置开始遍历所有服务,拿到其结构体地址service;
- 通过validate_rt_svc_desc 对该服务的参数进行校验;
- 通过 service->init 初始化该服务,当然有些服务可能不需要 init setup;
- 初始化rt_svc_descs_indices 表;
在 EL1/EL2 发起 SMC 调用时,smc_fid 作为第一个参数传递给 ATF,ATF 需要根据 smc_fid 定位到是哪种 service。由于 service 有两种 type 组成,每种 type 的 oen 最多有 64 个,所以 type 和 oen 的组合会有 128 中可能。为了加快查找 service 类别,ATF 在初始化 runtime service 时会维护一个表,我们用如下两个服务作为例子:
DECLARE_RT_SVC(arm_sip_svc,OEN_SIP_START, == 2OEN_SIP_END, == 2SMC_TYPE_FAST, == 1arm_sip_setup,arm_sip_handler
);start_idx = SMC_TYPE_FAST << 6 | OEN_SIP_START = 66
end_idx = SMC_TYPE_FAST << 6 | OEN_SIP_END = 66DECLARE_RT_SVC(tos_svc,OEN_TOS_START, == 50OEN_TOS_END, == 63SMC_TYPE_YIELD, == 0tos_svc_setup,tos_svc_smc_handler
);start_idx = SMC_TYPE_YIELD << 6 | OEN_TOS_START = 50
end_idx = SMC_TYPE_YIELD << 6 | OEN_TOS_END = 63

SMC 的处理流程:
根据 bl31/aarch64/runtime_exceptions.S 中异常向量表 runtime_exceptions 的定义,当 EL1/EL2 发起 SMC 调用后,会触发sync_exception_aarch64,并在最终的 smc_handler64 处理中跳转到相应的服务处理函数中:
runtime_exceptions-->sync_exception_aarch64-->handle_sync_exception-->sync_handler64
sync_handler64 中根据参数 1 中 smc_fid 的 type 和 oen 得到 desc_index,由rt_svc_descs_indices[desc_index] 可以得到 svc_index,再 由rt_svc_descs[svc_index] 就可以得到对应 runtime service 描述符的指针rt_svc_desc_t,最后调用其 handler 处理函数:
and x16, x0, #(FUNCID_SVE_HINT_MASK << FUNCID_SVE_HINT_SHIFT)orr x7, x7, x16bic x0, x0, #(FUNCID_SVE_HINT_MASK << FUNCID_SVE_HINT_SHIFT)/* Get the unique owning entity number */ubfx x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTHubfx x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTHorr x16, x16, x15, lsl #FUNCID_OEN_WIDTH/* Load descriptor index from array of indices */adrp x14, rt_svc_descs_indicesadd x14, x14, :lo12:rt_svc_descs_indicesldrb w15, [x14, x16]/* Any index greater than 127 is invalid. Check bit 7. */tbnz w15, 7, smc_unknown/** Get the descriptor using the index* x11 = (base + off), w15 = index** handler = (base + off) + (index << log2(size))*/adr_l x11, (__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE)lsl w10, w15, #RT_SVC_SIZE_LOG2ldr x15, [x11, w10, uxtw]/** Call the Secure Monitor Call handler and then drop directly into* el3_exit() which will program any remaining architectural state* prior to issuing the ERET to the desired lower EL.*/
#if DEBUGcbz x15, rt_svc_fw_critical_error
#endifblr x15
以 psci 为例,由于 psci 属于 standard service,所以会调用std_svc_smc_handler,在std_svc_smc_handler 中再根据smc_fid 区分不同的细分服务,然后调用psci_smc_handler 去处理 psci 协议:
static uintptr_t std_svc_smc_handler(uint32_t smc_fid,u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void *cookie,void *handle,u_register_t flags)
{if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {/* 32-bit SMC function, clear top parameter bits */x1 &= UINT32_MAX;x2 &= UINT32_MAX;x3 &= UINT32_MAX;x4 &= UINT32_MAX;}/** Dispatch PSCI calls to PSCI SMC handler and return its return* value*/if (is_psci_fid(smc_fid)) {uint64_t ret;ret = psci_smc_handler(smc_fid, x1, x2, x3, x4,cookie, handle, flags);...
}
相关文章:
ARM64 Trust Firmware [五]
本章介绍 ATF 中的 Runtime Service 是如何定义和被调用的。 要了解 SMC,必须从 SMC 指令本身开始,其指令如下图: 指令格式为:SMC #<imm>,从官方文档了解到该指令只能在 EL1 以及更高的异常等级上调用ÿ…...
rkipc main.c 中 rk_param_init函数分析
rk_param_init函数 这个函数是用来读取配置文件进行参数配置 这个函数在 luckfox-pico/project/app/rk_smart_door/smart_door/common/uvc/param/param.c 中 这个函数在main函数中被调用 //通过-c 配置文件路径 把配置文件传进来 case c:rkipc_ini_path_ optarg;//调用&am…...
正确清理C盘空间
一.系统清理 正确清理C盘空间主要是删除不需要的文件和应用程序,以释放磁盘空间。以下是一些常用的方法: 删除临时文件:在Windows搜索框中输入“%temp%”,打开临时文件夹,将其中的文件全部删除。 清理回收站…...
http代理IP怎么实现?如何解决代理IP访问不了问题?
HTTP代理是一种网络服务,它充当客户端和目标服务器之间的中介。当客户端发送请求时,请求首先发送到代理服务器,然后由代理服务器转发到目标服务器。同样,目标服务器的响应也会先发送到代理服务器,再由代理服务器返回给…...
【Gin-Web】Bluebell社区项目梳理5:投票功能分析与实现
本文目录 一、投票功能投票流程实现代码redis投票 一、投票功能 投票流程 首先我们要明确,就是 谁(哪个用户:userID) 给 哪个帖子(postID) 投了 什么票(赞成票or反对票)。 赞成票…...
多人协同创作gitea
多人协同创作gitea 在多台设备上协同使用Gitea,主要是通过网络访问Gitea服务器上的仓库来进行代码管理和协作。以下是一些关键步骤和建议,帮助你在多台设备上高效地使用Gitea进行协作: 1. 确保Gitea服务可访问 首先,你需要确保…...
Java 大视界 -- Java 大数据未来十年的技术蓝图与发展愿景(95)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
idea连接gitee完整教程
文章目录 idea连接gitee(使用idea远程兼容gitee) 使用idea远程兼容gitee并反向创建仓库和分支...
问卷数据分析|SPSS实操之相关分析
皮尔逊还是斯皮尔曼的选取主要看数据的分布 当数据满足正态分布且具有线性关系时,用皮尔逊相关系数 当有一个不满住时,用斯皮尔曼相关系数 1. 选择分析--相关--双变量 2. 将Z1-Y2加入到变量中,选择皮尔逊 3. 此处为结果,可看我案…...
汽配出库软件助力企业数字化转型,佳易王汽配出入库管理系统操作教程
一、概述 本实例以佳易王汽配出入库管理系统V17.1版本为例说明,其他版本可参考本实例。试用版软件资源可到文章最后了解,下载的文件为压缩包文件,请使用免费版的解压工具解压即可试用。 软件特点: 1、软件为绿色免安装版&#…...
二叉树(中等题)
1、先序,中序遍历确定二叉树 105 方法一、 前提 ① 必须不能有重复元素② 只有先序+中序和后序+中序才能实现唯一树 思考要点: 不要想着用for循环,递归一定更好解决输入是vector,递归就得考虑传入索…...
Versal - 基础6(Linux 开发 AIE-ML + 自动化脚本解析)
目录 1. 简介 2. 步骤解析 2.1 概览 2.1.1 步骤依赖关系 2.1.2 总目录结构 2.2 Vitis XPFM 2.2.1 Dir 2.2.2 Makefile 2.2.3 vitis_pfm.py 2.3 Kernels 2.3.1 Dir 2.3.2 Makefile 2.3.3 config 文件 2.4 AIE_app 2.4.1 Dir 2.4.2 Makefile 2.4.3 aie 要点 2.…...
什么是矩阵账号?如何高效运营tiktok矩阵账号
…...
tortoiseSVN 如何克隆项目到本地
导入项目成功,如下图:...
趣解PostGet请求的原理、应用场景及区别
趣解Post&Get请求的原理、应用场景及区别 POST 和 GET 的「身份之谜」:快递员与侦探的终极对决 一、角色设定:快递员(POST) vs 侦探(GET) GET(侦探): 任务ÿ…...
在PHP Web开发中,实现异步处理有几种常见方式的优缺点,以及最佳实践推荐方法
1. 消息队列 使用消息队列(如RabbitMQ、Beanstalkd、Redis)将任务放入队列,由后台进程异步处理。 优点: 任务持久化,系统崩溃后任务不丢失。 支持分布式处理,扩展性强。 实现步骤: 安装消息…...
深入解析过滤器模式:数据筛选与处理的高效工具
过滤器模式:数据筛选与处理的高效工具 在软件开发的复杂领域中,数据的筛选与处理是常见的任务。过滤器模式作为一种实用的设计模式,为解决这类问题提供了有效的解决方案。它允许开发者根据不同的标准对一组对象进行过滤操作,从而…...
DeepSeek R1/V3满血版——在线体验与API调用
前言:在人工智能的大模型发展进程中,每一次新模型的亮相都宛如一颗投入湖面的石子,激起层层波澜。如今,DeepSeek R1/V3 满血版强势登场,为大模型应用领域带来了全新的活力与变革。 本文不但介绍在线体验 DeepSeek R1/…...
排序链表--字节跳动
少年的书桌上没有虚度的光阴 题目描述 请你对链表进行排序 思路分析 核心思想:归并排序 有三个部分 链表排序实现 1. merge 函数 21.见 合并两个有序链表, 首先创建一个虚拟头节点 newhead,并使用指针 tail 来构建合并后的链表。 通过…...
Python爬虫-批量爬取股票数据猫各股票代码
前言 本文是该专栏的第47篇,后面会持续分享python爬虫干货知识,记得关注。 本文笔者以股票数据猫为例子,基于Python爬虫,批量获取各股票代码数据。 具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。废话不多说,下面跟着笔者直接往下看正文详细内容。(附…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
