arm linux内核 电源,ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现...

Linux电源管理(6)_Generic

PM之Suspend功能一文中的下图。

本文主要分析平台相关的CPU睡眠和唤醒,即下电和上电流程,以及ARM底层汇编代码实现。

内核版本:3.1.0 CPU:ARM Cortex-A7

a4c26d1e5885305701be709a3d33442f.png

1 平台相关函数执行流程

上图最后调入suspend_ops->enter,这是个平台相关的函数。

平台相关的cpu

suspend_enter函数:

如果有中断挂起,则直接返回;

读取设备的idle状态;

设置CPU0的热跳转寄存器,睡眠唤醒后,跳转到这个地址

允许cpu0睡眠

不屏蔽SCU断电、自断电功能

不屏蔽CPU自断电功能,当CPU进入WFI状态,CPU自动断电

改变CPU的频率、电压输出

调用cpu_suspend函数

恢复CPU的频率、电压输出

屏蔽自断电功能

屏蔽SCU断电、自断电功能

不允许CPU0睡眠

a4c26d1e5885305701be709a3d33442f.png

cpu_suspend函数调用流程图

2 睡眠过程详细分析

cpu_suspend:(arch/arm/kernel/suspend.c)

int

cpu_suspend(unsigned long arg, int (*fn)(unsigned

long))

函数携带两个参数,第二个参数是函数指针(参数是unsigned

long型的,返回值是int型的),第一个参数就是前面的函数指针被调用时需要的参数,故为unsigned

long型的

if

(!idmap_pgd) //非常有意思的一个变量,稍后再解释

return -EINVAL;

调用 __cpu_suspend

__cpu_suspend:(arch/arm/kernel/sleep.S)

携带的参数就是调用cpu_suspend函数时传入的参数。

R0(unsigned long

arg,实际上是个地址,地址存放的类型是suspend_args,是个参数,供R1函数调用时使用)

R1(睡眠函数,执行时需要的参数就是R0)

#define

cpu_suspend_size __glue(CPU_NAME,_suspend_size)

arch/arm/include/asm/glue-proc.h

#define

__glue(name,fn) ____glue(name,fn) arch/arm/include/asm/glue.h

#define

____glue(name,fn) name##fn

define CPU_NAME

cpu_v7

.equ cpu_v7_suspend_size, 4 * 8(arch/arm/mm/proc.v7.S)

故 cpu_suspend_size

== cpu_v7_suspend_size

入栈R4-R11,LR

没有定义MULTI_CPU,R4赋值cpu_suspend_size,为32

R5就是入栈后堆栈的地址,图中的1处

R4加上12

然后将堆栈地址减去(32+12),就是让开11个寄存器的值,图中的3处

入栈R0,R1

R0赋值堆栈地址加上8,图中的3处

R1赋值R4,就是44

R2赋值R5,就是图中的1处

R3赋值临时栈地址,文件下面定义了数个(看内核配置了多少个CPU来定)unsigned

long 型的地址空间

定义了多核,根据CPU的ID,获取当前CPU的临时栈地址

跳转到__cpu_suspend_save

__cpu_suspend_save:(arch/arm/kernel/suspend.c)

R3即当前CPU的临时栈地址,存入R0的值(物理的地址),图中的3处

以R0为基地址,入栈idmap_pgd的物理地址、入栈当前的堆栈(图中的1处,是个虚拟地址)、入栈唤醒函数(

cpu_do_resume 的物理地址)

cpu_do_suspend(glue-proc.h),-> cpu_v7_do_suspend

(arch/arm/mm/proc.v7.S)携带的参数R0就是刚入完3个寄存器后的堆栈地址

入栈R4-R10,LR;

以传入的参数R0为栈基地址,入栈R4、R5(PID、线程ID)

入栈R6-R11(域ID,页表基地址寄存器1、页表控制寄存器、系统控制寄存器、辅助寄存器、协处理器访问控制寄存器),加上上面的2个正好是8个;

弹出R4-R10,PC;

刷新cache、二级cache,保证数据确实写到了内存,栈空间也是内存的一部分

LR赋值cpu_suspend_abort

弹出r0,PC

,就是跳转到上面的fn函数指针处

若这个fn函数执行过程中返回了,则调转到lr处,就是cpu_suspend_abort

cpu_suspend_abort:

此时的SP就是图中的3处,弹出到R1,R2,R3。

判断R0的值,若不是0,则将其赋值1

堆栈SP赋值R2的值,图中的1处

堆栈弹出R4-R11,PC。实际是返回到cpu_suspend函数中,调用__cpu_suspend函数的地方。

fn函数执行过程,若最终执行成功,则执行wfi指令,CPU顺利下电

清除Icache,刷dcache。

关闭SMP位

关闭对应的CCI端口

然后进入WFI睡眠,低功耗状态

如果中间出现了差错,则直接返回1后,接着下面的cpu_suspend_abort执行,仍然能够返回到cpu_suspend函数,其中__cpu_suspend函数的返回值强行变为了1

3 唤醒过程详细分析

低功耗模式被唤醒后,跳转到唤醒地址

设置SVC模式,关闭IRQ、FIQ

使能对应的CCI端口

清除SMP位,清除跳转预测等,开启I

cache

跳转到cpu_resume的物理地址

cpu_resume:

获取当前CPU的临时栈地址,保存到R0中,图中的3处

设置SVC模式,关闭I、F

以R0为基地址,弹出R1、SP、PC,R1就是 idmap_pgd

跳转到cpu_do_resume,就是cpu_v7_do_resume

cpu_v7_do_resume

清除TLB、I cache、上下文ID<

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值