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 以及更高的异常等级上调用ÿ…...
Excel核心函数VLOOKUP全解析:从入门到精通
一、函数概述 VLOOKUP是Excel中最重要且使用频率最高的查找函数之一,全称为Vertical Lookup(垂直查找)。该函数主要用于在数据表的首列查找特定值,并返回该行中指定列的对应值。根据微软官方统计,超过80%的Excel用户在…...
KTransformers如何通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度?
KTransformers通过内核级优化、多GPU并行策略和稀疏注意力等技术显著加速大语言模型的推理速度,具体体现在以下几个方面: 内核级优化: KTransformers采用了高效的内核级优化技术,包括对Transformer模型中的关键操作进行优化。例如…...
审计级别未启用扩展模式导致查询 DBA_AUDIT_TRAIL 时 SQL_TEXT 列为空
如果查询 DBA_AUDIT_TRAIL 时发现 SQL_TEXT 列为空,但其他字段(如 OS_USERNAME、USERNAME、TIMESTAMP 等)有数据,可能是由于以下原因之一。以下是可能的原因及解决方法: 1. 审计级别未启用扩展模式 默认情况下&#x…...
微信小程序项目 video 组件失效问题,无法播放本地视频
问题与处理策略 问题描述 <video src"../../assets/video/test-video.mp4" controls style"width: 100%; height: 300px;"></video>在微信小程序项目中,上述 video 组件失效,视频无法加载,无法播放本地视频…...
若依-@Excel新增注解numberFormat
Excel注解中原本的scale会四舍五入小数,导致进度丢失 想要的效果 显示的时候保留两个小数真正的数值是保留之前的数值 还原过程 若以中有一個專門的工具类,用来处理excel的 找到EXCEL导出方法exportExcel()找到writeSheet,写表格的方法找到填充数据的方法…...
网络安全行业有哪些公司
只是简单做一下网络安全公司梳理,不作点评,下列排名不分先后。 一、常见的网络安全公司 1、天融信 天融信(002212.SZ)创始于1995年,是上市公司中成立最早的网络安全企业,亲历中国网络安全产业的发展历程…...
存储区域网络(SAN)管理
存储区域网络(Storage Area Network,SAN)采用网状通道(Fibre Channel ,简称FC)技术,通过FC交换机连接存储阵列和服务器主机,建立专用于数据存储的区域网络。SAN提供了一种与现有LAN连…...
如何使用Spark SQL进行复杂的数据查询和分析
使用Spark SQL进行复杂的数据查询和分析是一个涉及多个步骤和技术的过程。以下是如何使用Spark SQL进行复杂数据查询和分析的详细指南: 一、准备阶段 环境搭建: 确保已经安装并配置好了Apache Spark环境。准备好数据源,可以是CSV文件、JSON…...
sass报错:[sass] Undefined variable. @import升级@use语法注意事项
今天创建vue3项目,迁移老项目代码,使用sass的时候发现import语法已经废弃,官方推荐使用use替换。 这里我踩了一个坑找半天的问题,原因是sass升级到1.85之后 定义变量前加上 - 就是表示变量私有,即使使用use导出 在新的…...
使用 SDKMAN! 在 Mac(包括 ARM 架构的 M1/M2 芯片)安装适配 Java 8 的 Maven
文章目录 1、安装 SDKMAN!2、安装 Maven:2.1、maven 3.9.62.2、maven 3.8.1 好的,这是使用 SDKMAN! 安装适配 Java 8 的 Maven 的步骤: 1、安装 SDKMAN! 前提条件: 安装 SDKMAN!: 如果你的系统上没有安装 SDKMAN!,请按照以下说明进行安装: c…...
anythingllm服务器部署+ollama+deepseek+实现本地知识库问答
一、docker安装anythingllm 1、拉取镜像 docker pull mintplexlabs/anythingllm:latest 2、创建db目录和配置文件并运行 anythingLLM 容器 export STORAGE_LOCATION/data/ai/wjh_team/anythingllm && \mkdir -p $STORAGE_LOCATION && \touch "$STORAG…...
深度学习04 数据增强、调整学习率
目录 数据增强 常用的数据增强方法 调整学习率 学习率 调整学习率 调整学习率的方法 有序调整 等间隔调整 多间隔调整 指数衰减 余弦退火 自适应调整 自定义调整 数据增强 数据增强是通过对训练数据进行各种变换(如旋转、翻转、裁剪等)&am…...
2023年全国职业院校技能大赛GZ073网络系统管理赛项赛题第10套模块A:网络构建
有问题请留言或主页私信咨询 2023年全国职业院校技能大赛 GZ073网络系统管理赛项 赛题第10套 模块A:网络构建 **目 **录 任务清单 (一)基础配置 (二)有线网络配置 (三)无线…...
2023年河北省职业院校技能大赛网络系统管理赛项样题解法
有问题请留言或主页私信咨询 配置文件有部分测试时的冗余配置无视即可。 解法只有大致解法,并不完整。请参考配置,自己补全 基础配置 1.所有交换机和无线控制器开启SSH服务,用户名密码分别为admin、admin1234;密码为明文类…...
vite+vue3开发uni-app时低版本浏览器不支持es6语法的问题排坑笔记
重要提示:请首先完整阅读完文章内容后再操作,以免不必要的时间浪费!切记!!!在使用vitevue3开发uni-app项目时,存在低版本浏览器不兼容es6语法的问题,如“?.” “??” 等。为了方便…...
Linux系统编程基础详解
Linux 系统详解 大纲 引言 Linux 的定义Linux 的历史与发展本文结构概述 Linux 的基本概念 Linux 的架构 内核与用户空间系统调用 Linux 的文件系统 文件与目录结构权限管理 Linux 的进程管理 进程与线程进程调度 Linux 的基本命令与操作 常用命令概述 文件与目录操作命令文…...
钉钉应用开发
一.开发调试工具认识与安装 选择微应用调试工具-RC版 微应用调试工具—RC版 - 钉钉开放平台(下载和使用说明) 案例 创建一个钉钉应用 开发工具和安装包 vscode 开发环境 预装node.js---- https://nodejs.org/zh-cn --npm是随Node.js一起安装的 在…...
打破限制!自定义 Hooks 如何提升 React 组件的灵活性
本周开发监控项目,我发现了很多的 React 类组件封装,发现出现了多次UI渲染的情况、代码辨识度也较差,对性能和维护都产生了挑战。这里多个场景的都是状态管理和逻辑复用需求,其实完全没有必要封装类组件。相反我通过引入 React 自…...
使用arthas测试接口响应时间
一、下载解压 git下载地址: https://github.com/alibaba/arthas/releases 二、启动和选择Java进程 java -jar arthas-boot.jar选择需要测试的java进程,我输入1然后回车 三、使用trace命令 trace 全路径 方法名 trace com.xxx.b2b.mall.goods.service…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
Visual Studio Code 扩展
Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后,命令 changeCase.commands 可预览转换效果 EmmyLua…...
RushDB开源程序 是现代应用程序和 AI 的即时数据库。建立在 Neo4j 之上
一、软件介绍 文末提供程序和源码下载 RushDB 改变了您处理图形数据的方式 — 不需要 Schema,不需要复杂的查询,只需推送数据即可。 二、Key Features ✨ 主要特点 Instant Setup: Be productive in seconds, not days 即时设置 :在几秒钟…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...
计算机系统结构复习-名词解释2
1.定向:在某条指令产生计算结果之前,其他指令并不真正立即需要该计算结果,如果能够将该计算结果从其产生的地方直接送到其他指令中需要它的地方,那么就可以避免停顿。 2.多级存储层次:由若干个采用不同实现技术的存储…...
RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...
