9.4 自定义SMC服务开发
目录
- 9.4.1 SMC服务开发概述
- 9.4.2 开发流程与框架
- 1. 服务ID定义
- 2. 服务处理函数注册
- 9.4.3 典型实现示例
- 安全计数器服务实现
- 参数传递规范
- 9.4.4 安全注意事项
- 9.4.5 调试与测试方法
- 9.4.6 与用户空间的集成
- 9.4.7 最佳实践建议
9.4.1 SMC服务开发概述
在TF-A中,SMC(Secure Monitor Call)是安全世界与非安全世界之间通信的核心机制。开发者可以通过扩展SMC服务来实现特定安全功能,主要包括:
- 功能范围:硬件加密加速、安全配置管理、可信服务代理等
- 调用方式:通过
smc
指令触发,在EL3由BL31处理 - 服务类型:
- 快速调用(Fast Call):同步处理,立即返回
- 标准调用(Standard Call):可能涉及异步处理
9.4.2 开发流程与框架
1. 服务ID定义
// 在include/lib/smccc.h中定义SMC功能ID
#define MY_CUSTOM_SERVICE_ID 0x8200FF00
#define MY_CUSTOM_SERVICE_VERSION 0x8200FF01// 在include/services/my_service.h中定义参数宏
#define MY_SVC_PARAM1_SHIFT 0
#define MY_SVC_PARAM2_SHIFT 8
2. 服务处理函数注册
// 在services/std_svc/my_service/my_service_main.c中实现
DECLARE_RT_SVC(my_custom_service,OEN_TOS_START,OEN_TOS_END,SMC_TYPE_FAST,my_svc_setup,my_svc_smc_handler
);// 在BL31初始化时注册服务
void my_svc_setup(void)
{/* 硬件初始化代码 */
}uintptr_t my_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)
{/* 处理逻辑实现 */
}
9.4.3 典型实现示例
安全计数器服务实现
// 服务处理函数
static uintptr_t counter_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)
{static uint32_t secure_counter = 0;switch (smc_fid) {case COUNTER_INCREMENT:secure_counter++;SMC_RET1(handle, secure_counter);case COUNTER_GET:SMC_RET1(handle, secure_counter);default:WARN("Unimplemented SMC Call: 0x%x\n", smc_fid);SMC_RET1(handle, SMC_UNK);}
}
参数传递规范
寄存器 | 用途 |
---|---|
X0 | SMC功能ID |
X1-X4 | 输入参数 |
X5-X7 | 保留(必须设为0) |
X0 | 返回值(输出) |
9.4.4 安全注意事项
-
参数验证:
if (x1 > MAX_ALLOWED_VALUE) {SMC_RET1(handle, SMC_INVALID_PARAM); }
-
边界检查:
- 所有指针参数必须验证是否在安全内存范围内
- 数组访问必须检查索引有效性
-
时序安全:
- 敏感操作应保持恒定时间执行
- 避免分支泄露信息
-
权限控制:
if (caller_secure_state != SECURE) {SMC_RET1(handle, SMC_DENIED); }
9.4.5 调试与测试方法
-
日志输出:
INFO("SMC Call 0x%x from 0x%lx\n", smc_fid, read_elr_el3());
-
单元测试:
# 在TF-A测试框架中添加测试用例 def test_custom_smc(self):ret = self.smc_call(0x8200FF00, 0x1)self.assertEqual(ret[0], 0x0)
-
性能分析:
uint64_t start_time = read_cntpct_el0(); // SMC处理逻辑 uint64_t duration = read_cntpct_el0() - start_time;
9.4.6 与用户空间的集成
- Linux内核调用示例:
// 内核驱动中调用SMC服务
static long my_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{struct arm_smccc_res res;arm_smccc_smc(MY_CUSTOM_SERVICE_ID, arg, 0, 0, 0, 0, 0, 0, &res);return res.a0;
}
- OP-TEE集成:
// 在OP-TEE中通过NS调用触发
TEE_Result invoke_smc_service(uint32_t param)
{struct arm_smccc_res res;tee_smc_call(MY_CUSTOM_SERVICE_ID, param, &res);return res.a0;
}
9.4.7 最佳实践建议
-
服务设计原则:
- 保持最小权限
- 实现原子操作
- 避免复杂状态机
-
版本兼容性:
- 为服务实现版本查询接口
- 保持向后兼容
-
性能优化:
- 高频调用服务使用快速调用类型
- 减少EL3上下文保存开销
-
错误处理:
- 定义明确的错误码体系
- 提供详细的调试信息
该章节内容已按照技术文档规范编写,包含代码示例、表格、注意事项等要素,可直接集成到书籍中。需要扩展具体案例时,可添加更多SoC特定的实现示例。