arm64 |
您所在的位置:网站首页 › 重启代码panic › arm64 |
ARM64-reboot流程
文章目录
ARM64-reboot流程1. 用户态reboot 执行流程2. 内核系统调用3. PSCI 电源状态协调接口3.1 kernel发起的`PSCI`复位3.2 TrustZone的异常处理
1. 用户态reboot 执行流程
当命令行输入reboot命令时,busybox会vfork一个子进程,调用reboot函数: 此时,reboot函数进入到libc,libc里面封装了Linux的系统调用: 这样就进入到了Linux的系统调用部分的代码:校验是否有root权限后,校验输入的参数,参数都对之后,执行到kernel_restart()函数。 kernel_restart()函数先通知reboot通知链上注册的回调,将设备关闭;然后将当前进程迁移到reboot的CPU上;执行相关的系统核心的shutdown回调,然后调用machine_restart()函数。 kernel_restart_prepare()通知reboot阻塞通知链上注册的回调,当前的ARM64代码上没有注册相关的回调block,禁止内核再调用用户态的帮助程序,接着关闭所有设备。 device_shutdown()设备关闭的过程是遍历全局变量devices_kset里面的所有设备,并从链表中删除,执行相关的shuntdown回调函数。 将当前进程迁移到reboot的CPU上的大概过程如下: 最后的machine_restart()先关闭本地中断,让其他核停止后,执行对应的arm_pm_restart()函数。 PSCI全程是Power State Coordination Interface,翻译叫电源状态协调接口,是ARM定义的电源管理接口规范,可以在官网上下载到相关资料,比如Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf文档,下面的部分截图可能会来自这个文档。 先看一下这个PSCI的初始化流程,在kernel的setup_arch启动时,扫描设备树节点信息关于psci部分,根据compatible来匹配到psci_0_2_init()函数,然后进入psci_probe()函数,并在psci_0_2_set_functions()函数中设置相关的函数指针: start_kernel() -> setup_arch() -> psci_dt_init() -> psci_0_2_init() -> psci_probe() -> psci_0_2_set_functions()设备树里面的信息如下里标记的版本是psci-0.2,method是使用smc。 当前设备启动时,扫描设备树相关信息时打印的PSCI相关的信息如下: psci: probing for conduit method from DT. psci: PSCIv1.0 detected in firmware. psci: Using standard PSCI v0.2 function IDs psci: MIGRATE_INFO_TYPE not supported.psci_dt_init()函数如下,根据不同的compatible来匹配不同的init函数。 psci_0_2_set_functions()函数如下: 在上面machine_restart()函数最后,调用了arm_pm_restart(),在psci_0_2_set_functions()被赋值成psci_sys_reset()函数。 3.1 kernel发起的PSCI复位psci_sys_reset()函数调用invoke_psci_fn函数指针,并输入PSCI_0_2_FN_SYSTEM_RESET参数。 先看PSCI_0_2_FN_SYSTEM_RESET,是定义的一些列的宏: 这个宏来源于手册,这个值在ARM和ARM64上定义是一样的,有的定义会不一样。 比如下面的CPU_ON定义: 再回过头看invoke_psci_fn函数,这个也是在初始化过程中赋值的,这里解析设备树配置的method是smc: invoke_psci_fn被设置为__invoke_psci_fn_smc函数: 将PSCI_0_2_FN_SYSTEM_RESET(0x84000009)输入到function_id后,调用arm_smccc_smc: smccc返回的资源结构体: arm_smccc_smc是一个宏,调用的是汇编编写的__arm_smccc_smc函数,函数的声明如下: SMCCC宏如下,smc指令触发一个安全监视器异常后,将栈上的数据存到x0~x3上,回头看__invoke_psci_fn_smc函数实际是返回x0的结果。 smc指令是arm-v8手册中定义的一个指令,这个安全监视器触发一个异常,然后进入到EL3。 当前芯片用户态程序和OS都是aarch64的,从ARM-v8手册上看,EL0是APP程序运行的级别,EL1是OS运行级别,EL2是虚拟机监视器运行级别,调用的指令是HVC,最后才是安全监视器运行的级别EL3,调用的指令是SMC。(关于这个ARM-TrustZone的内容没有了解,如果有了解的话看这些代码应该会轻松些。) 几个指令的差异: SVC:超级用户调用SVC指令,一般是指操作系统HVC:虚拟机监视器调用HVC指令SMC:安全监视器调用SMC指令在查阅相关资料是,从ARMv8中的异常向量介绍博客上可以看到最后一段: 在支持Trustzone的ARRMv8中,当在non-secure world或者secure world中触发了smc或者hvc指令时都属于产生sync类型的异常。根据产生该异常是否会导致EL的迁移从异常向量表中确定最终用于处理该异常的handle。 既然这样,就看一下arm-trusted-firmware的代码。 当前编译命令: make PLAT=hi3559av100 SPD=none BL33=../arch/arm64/boot/uImage CCI_UP=0 DEBUG=1 BL33_SEC=0 HISILICON=1 fip编译使用的lds文件是arm-trusted-firmware/bl31/bl31.ld.S,开头就可以看到入口是bl31_entrypoint: ENTRY(bl31_entrypoint)在bl31_entrypoint入口函数中,有多处设置_exception_vectors为runtime_exceptions函数的,比如下面这个地方: 在arm-trusted-firmware/bl31/aarch64/runtime_exceptions.S代码中,可以看到与博客作者说的sync类型异常,当前平台架构是aarch64的,看一下smc_handler64这个处理。 smc_handler64里找rt_svc_desc_t结构体类型里面的handle处理函数,而这些处理函数在rt_svc_descs节中,__RT_SVC_DESCS_START__在arm-trusted-firmware/bl31/bl31.ld.S文件中可以看到是rt_svc_descs节开始的位置。 rt_svc_descs节存放的内容是通过DECLARE_RT_SVC宏来定义的: 代码中有使用这个宏的地方目前只看到一处: 这里就看一下这个std_svc_smc_handler,可以看到会调用psci_smc_handler函数。 而在psci_smc_handler函数中,就可以看到上面传入的psci传入的PSCI_SYSTEM_RESET指令 在psci_system_reset进去就打印psci相关的打印,然后调用system_reset回调。 先看一下打印信息: 再和设备重启时的日志进行对比,发现是一致的。 紧接着到system_reset回调,这里指向hisi_system_reset函数: 然后再指向sys_system_reset函数: 最后是写一个寄存器~~~。 很简单,但实际上流程就走到你发昏;你以为复位很复杂,但实际上最后只是写了一个寄存器。妙不可言? |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |