前言

最近遇到一个待机问题,系统一直无法正常suspend,跟了一下代码,发现在PSCI的最后阶段返回了一个错误码。这篇文章我们是延续上一篇《Linux系统的suspend流程分析》,继续揭开psci的神秘面纱。

正文

从《Linux系统的suspend流程分析》一文我们可以看到,suspend的最后会调用到下面的函数

static int psci_cpu_suspend(u32 state, unsigned long entry_point)
{int err;u32 fn;fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; /* 对应到ATF(arm trusted firmware)的CPU_SUSPEND函数 */err = invoke_psci_fn(fn, state, entry_point, 0);  /* 调用CPU_SUSPEND函数 */return psci_to_linux_errno(err); /* 返回错误码 */
}

psci_cpu_suspend第一个参数state,对应的是DTS文件中的“arm,psci-suspend-param”值:

        idle-states {entry-method = "arm,psci";SYSTEM_SLEEP_0: system-sleep-0 {compatible = "arm,idle-state";arm,psci-suspend-param = <0x0020000>; /* 对应power state */local-timer-stop;entry-latency-us = <0x3fffffff>;exit-latency-us = <0x40000000>;min-residency-us = <0xffffffff>;};};

正常情况下,invoke_psci_fn返回的是PSCI_RET_SUCCESS,如下所示。但是我遇到的问题却返回了PSCI_RET_INVALID_PARAMS。

static int psci_to_linux_errno(int errno)
{switch (errno) {case PSCI_RET_SUCCESS:return 0;case PSCI_RET_NOT_SUPPORTED:return -EOPNOTSUPP;case PSCI_RET_INVALID_PARAMS:case PSCI_RET_INVALID_ADDRESS:return -EINVAL;case PSCI_RET_DENIED:return -EPERM;};return -EINVAL;
}

为了解释为什么返回了PSCI_RET_INVALID_PARAMS,我们继续跟一下suspend流程。psci_function_id[PSCI_FN_CPU_SUSPEND]对应的回调函数如下:

static void __init psci_0_2_set_functions(void)
{...psci_function_id[PSCI_FN_CPU_SUSPEND] =PSCI_FN_NATIVE(0_2, CPU_SUSPEND);psci_ops.cpu_suspend = psci_cpu_suspend;...
}

PSCI_FN_NATIVE的宏定义如下

#ifdef CONFIG_64BIT
#define PSCI_FN_NATIVE(version, name)    PSCI_##version##_FN64_##name
#else
#define PSCI_FN_NATIVE(version, name)    PSCI_##version##_FN_##name
#endif

因为我的是64位的,所以最后映射为:PSCI_0_2_FN64_CPU_SUSPEND。它的定义在include\uapi\linux\psci.h找到了原形。

/* PSCI v0.2 interface */
#define PSCI_0_2_FN_BASE            0x84000000
#define PSCI_0_2_64BIT                0x40000000#define PSCI_0_2_FN64_BASE            \(PSCI_0_2_FN_BASE + PSCI_0_2_64BIT)#define PSCI_0_2_FN64(n)            (PSCI_0_2_FN64_BASE + (n))#define PSCI_0_2_FN64_CPU_SUSPEND        PSCI_0_2_FN64(1)

最终我们可以得到:

psci_function_id[PSCI_FN_CPU_SUSPEND] = 0xC4000001

如果不了解PSCI规范的人,可以会对这个地址值很疑惑,我们可以看一下PSCI规范中的定义:

Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf

说白了,就是规定了0xC4000001这个值对应的是arm trusted firmware中的CPU_SUSPEND。可能很多人也不明白什么是ATF,可以参考下面的链接:
https://blog.csdn.net/shuaifengyun/article/details/72468109

现在armv8架构的待机流程已经非常复杂,涉及的知识点也很多,简单的说我这次的待机过程,就是通过SMC(secure monitor call),从EL1(kernel) -> EL3(secure monitor)。玩过在armv8-a板子上跑Linux系统的同学应该都知道,现在烧录的uboot会包括BL1、BL2、BL31、BL32和BL33几个阶段,我们可能会比较熟悉BL33这个阶段,因为就是在这个阶段引导Linux系统的。而从上面链接的内容可知,我所说的待机就是通过smc指令,触发在bl1中设定的smc异常来将cpu权限交给bl31并跳转到bl31中执行。

回到我们的问题,0xC4000001这个值对应的函数就是在BL31阶段,所以我们需要进入到这个阶段的代码中看。但是很可惜,我这个平台并没有提供除BL33之外的其它BLx阶段的源码。我在网上找了一个其它平台的代码,虽然不能完全对应的上,但是也能知道个大概。

/******************************************************************************** PSCI top level handler for servicing SMCs.******************************************************************************/
uint64_t psci_smc_handler(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void *cookie,void *handle,uint64_t flags)
{if (is_caller_secure(flags))SMC_RET1(handle, SMC_UNK);/* Check the fid against the capabilities */if (!(psci_caps & define_psci_cap(smc_fid)))SMC_RET1(handle, SMC_UNK);if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {/* 32-bit PSCI function, clear top parameter bits */...} else {/* 64-bit PSCI function */switch (smc_fid) {case PSCI_CPU_SUSPEND_AARCH64:  /* 对应我们的CPU_SUSPEND */SMC_RET1(handle, psci_cpu_suspend(x1, x2, x3));...}}WARN("Unimplemented PSCI Call: 0x%x \n", smc_fid);SMC_RET1(handle, SMC_UNK);
}

接着调用

int psci_cpu_suspend(unsigned int power_state,unsigned long entrypoint,unsigned long context_id)
{.../* Check SBZ bits in power state are zero */if (psci_validate_power_state(power_state))return PSCI_E_INVALID_PARAMS;...
}

其中,

#define psci_validate_power_state(pstate) (pstate & PSTATE_VALID_MASK)#define PSTATE_VALID_MASK     0xFCFE0000

所以我们发现,因为 0x0020000 & 0xFCFE0000 = 0x0020000,所以返回了PSCI_E_INVALID_PARAMS,也就对应上我一开始提到的问题,返回了PSCI_RET_INVALID_PARAMS错误码。

那为什么要和0xFCFE0000这个值进行与操作,从PSCI规范我们可以看到,对于32bit的power state参数,它对每一位都是做了严格要求的:

bit filed                    description
31:26                        reserved.must be zero
25:24                        power level
23:17                        reserved.must be zero
16                           state type
15:0                         state ID

因为我们的arm,psci-suspend-param值占用了保留位,所以这是不合法的。

结语

最后的分析原因,可能不一定就是从那个位置返回,不过我们旨在是了解整个流程,到这里我们就结束了这系列的文章。

一个suspend的问题分析相关推荐

  1. 一个简单函数的反汇编分析

    利用visual studio的反汇编功能,可以看到函数调用的汇编语言. 一个简单函数的反汇编分析 int __stdcall add(int a, int b, int c) { 00FD13C0  ...

  2. 从一个OutOfMemoryError 学会了分析Java内存泄漏问题

    从一个OutOfMemoryError 学会了分析Java内存泄漏问题 以前都是好好的,最近出现了 oom. 问题 开始是: java.lang.OutOfMemoryError: Java heap ...

  3. 构建meteor应用程序_我如何在一个月内构建一个复杂的文本分析应用程序

    构建meteor应用程序 by Jeffrey Flynt 由Jeffrey Flynt 我如何在一个月内构建一个复杂的文本分析应用程序 (How I built a complex text ana ...

  4. 基于SSH2做一个24小时订单分析表格

    基于SSH2做一个24小时订单分析表格 以下为要实现的最终效果截图: ps:没有时间优化前段页面样式,对前段美化有要求的小伙伴可以自行引用BOOtStrap.esayUi 或者 layUi 自行优化. ...

  5. 实现一个avs2码流分析工具

    最近在做avs2编码器项目,但是却没有成熟的码流分析工具,于是抽空学习了QT,业余时间写了一个avs2码流分析工具. 软件的界面如下: 图1.avs2码流分析仪界面 UI的左边框为NAL列表或者语法元 ...

  6. windbg抓一个windows蓝屏分析

    前言 一直以来挺稳定,但还是小概率事件意外出现某machine突然蓝屏了.查看windows事件查看器提示计算机已经从检测错误后重新启动.检测错误: 0x0000009f (0x00000000000 ...

  7. 战胜主导设计:一个整合性的分析框架

    文章目录 一.引言 二.相关文献回顾 三.主导设计形成后的新进入企业的SWOT分析 (一)NE的优势分析 (二)NE的劣势分析 (三)NE的机会分析 (四)NE的威胁分析 四.结论 五.参考文献 一. ...

  8. 手写一个原神祈愿分析工具

    手写一个原神祈愿分析工具 之前一直通过游创工坊来进行祈愿抽卡数据分析,但是广告太多,而且担心auth_key泄露,于是自己花了一天时间动手实现了个数据分析工具,数据永久保存在本地,没有信息泄露风险,话 ...

  9. [基因课学习笔记]一个简单的基因家族分析

    工作背景 探究在芝麻.大豆以及拟南芥中FAD4-like基因家族进化关系,并使其可视化(进化树) 操作环境及软件的准备 虚拟机应用:VMware Workstation pro 17 虚拟机操作系统: ...

最新文章

  1. pandas基于时序数据计算模型预测推理需要的统计数据(累计时间、长度变化、变化率、方差、均值、最大、最小等):范围内的统计量、变化率、获得数据集最后的几条数据的统计量、变化率、获得范围内的统计量
  2. 飞花的糖果_JAVA
  3. 成功解决AttributeError: module ‘tensorflow‘ has no attribute ‘placeholder‘
  4. IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boo
  5. VTK:隐式布尔值demo用法实战
  6. dbcp_c3p0连接mysql8.0.13
  7. 批量提取文件创建时间_批量采集新浪微博用户内容
  8. feign post 传递空值_听我讲完GET、POST原理,面试官给我倒了杯卡布奇诺
  9. Android:SharedPreferences详解+示例
  10. 远程连接SQL Server数据库
  11. Java 集合 之 Set
  12. JAVA判断数组最大值
  13. python资源分配算法_DRL based Resource Allocation Framework
  14. 解决Mac文件乱码问题
  15. kitti pkl可视化,KITTI数据集格式说明
  16. 免费织梦CMS文章采集器之采集聚合
  17. 【新版】掩日免杀windows Defender
  18. 机械制图与计算机绘图实训报告前言,机械制图论文2000字_机械制图总结以及心得2000字_大一机械制图结课论文...
  19. Fastdfs预留空间问题排查分析
  20. cdn刷新api_阿里云cdn刷新api

热门文章

  1. Commonjs和Esmodule
  2. 更懂业务的数智平台,应对数智化转型的“千变万化”
  3. 搜狗王小川说输入法的未来是自动问答,那么这个技术究竟发展得怎么样了?...
  4. html表单ui图片,别人的UI表单为什么设计这么漂亮?
  5. ggsave保存图片报错Error in x$theme : $ operator not defined for this S4 class
  6. NTP校时器(NTP网络校时器-NTP校时系统)
  7. 计算机硬盘是内存储器还是外存储器,计算机的内存储器比外存储器很多朋友觉得自己攒机是一件麻烦的事...
  8. tensorflow2视力表E字符(学习笔记)--制作自己的数据集
  9. resnet网络特征提取过程可视化
  10. js声明函数的几种方式