1 介绍
本文主要是在ARM架构的不同异常等级上工作的软件之间,提供一个标准的电源管理接口。这些软件,比如Linux
、Hypervisor
、安全Firmware
和可信OS之间必须能够实现互相操作。而这些软件可能由不同厂商提供,本标准就是为这些软件的集成提供便利。
这些PSCI接口有利于电源管理
代码通用化、模块化:
该接口规范不会包含动态电压频率调节(DVFS
)或设备电源管理(比如,GPU
等外设的管理).
该接口规范设计用来与硬件探测技术(如ACPI
和FDT
)等配合使用,并不是要取代ACPI
或FDT
。
本文描述了PSCI版本1.1
,1.0
和0.2
。对于0.2
,还提供了一个勘误更新。
本文包含以下内容:
下面这些文档包含与本文档相关的信息:
ATF
).支持电源管理的操作系统,能够动态改变CPU核的电源状态,根据进行负载均衡,努力降低功耗。电源管理技术主要分为两类:
clock-gated
、retention
、power-gated
状态。但是,该核对于OS而言还是可用的。Hotplug
热插拔:根据对算力的需求变化,而将CPU核置于离线、在线。离线时,OS负责将所有中断和线程从核上迁移走;当在线时,OS负责重新进行负载均衡。尽管由单个供应商提供嵌入式系统的软件可能更简单,但事实并非如此。为了安全,ARM将硬件架构划分为4个不同的异常级(EL
)以及2个安全状态,以便支持不同特权的软件分区。
下表是基于ARM架构的硬件平台上的软件划分:
AArch32 | AArch64 | 软件和供应商 |
---|---|---|
NS_EL0 (PL0) | NS_EL0 | 非特权应用,如APP |
NS_EL1 (PL1) | NS_EL1 | 富操作系统内核,如Linux、Windows、iOS |
NS_EL2 (PL2) | NS_EL2 | Hypervisor(Citrix、VMWare、OK-Labs) |
S_EL0 (PL0) | S_EL0 | 可信OS的应用 |
S_EL3 (PL1) | S_EL1 | 可信OS的内核(Trustonic) |
S_EL3 (PL1) | S_EL3 | 安全Monitor,执行安全固件(ATF) |
AArch32是ARMv8架构的32位执行状态,在ARMv8架构之前采用的执行状态。在ARMv7处理器中,异常级的概念是隐含的,相关文档也并未说明。那时候,虚拟化扩展提供
EL2
功能,安全扩展提供EL3
功能,安全状态由特权级(PL-Privilege Level
)标识异常的层次结构。更多信息,参考第3.2节。
因为不同供应商的不同操作系统都可运行在ARM系统上,电源管理就需要一个协作的方法。考虑到运行在EL1
上的类OS软件或运行在EL2
上的hypervisor
软件,一般处于非安全状态,如果想要进入idle
状态、给一个核上电或掉电、或复位或关闭系统,更高异常级的监控软件必须能够响应这种电源状态变化的请求。
同样,如果某个wakeup
事件改变了核的电源状态,那么这些监管软件需要执行诸如恢复上下文
之类的操作。PSCI提供了不同监管软件之间互操作和集成的标准接口定义。本文档会详细描述这类接口,以及在idle
、hotplug
、shutdown
和reset
情况下如何使用它们。
本文档定义了在不同监管软件之间协调电源管理的API。这种API允许监管软件请求给核上电、掉电,安全上下文的核间迁移(可信OS需要)。本文中,假设EL2
和EL3
都已经实现。
PSCI
具有下面的用途:
hotplug
热插拔;FDT
和ACPI
描述去支持电源管理代码的泛化。PSCI
不包括:外设电源管理
和 动态电压和频率调节(DVFS)
。
PSCI
不提供给监控软件电源状态表示。但是,可以和ACPI
或FDT
等硬件描述技术结合使用。
ARMv8架构明确提出了EL
的概念,也定义了安全状态下软件执行特权的层次结构。
ARMv7架构中,EL
概念是隐含在架构体系中的:
EL2
的功能(只存在非安全状态下)。EL3
功能,包含对两种安全状态的支持。控制是在Monitor
模式下完成的,该模式也只存在于安全状态下。ARMv7使用PL
(特权级)的概念描述软件执行的特权层级结构。因为Monitor
模式的存在,ARMv7的非安全状态和安全状态是非对称的,如下所述:
PL0
, 非特权,适用于User
模式PL1
, OS级特权
,适用于System
, FIQ
, IRQ
, Supervisor
, Abort
和Undefined
模式PL2
, hypervisor
特权,适用于Hyp
模式Secure PL0
, 非特权,仅适用于User
模式Secure PL1
, 可信OS和Monitor
级特权,适用于System
, FIQ
, IRQ
, Supervisor
, Abort
, Undefined
和Monitor
模式AArch32执行状态下,异常级和之前的运行模式对应关系如下:
EL0
: User
模式EL1
: System
, FIQ
, IRQ
, Supervisor
, Abort
和Undefined
模式EL2
: Hyp
模式Secure EL0
: User
模式EL3
: System
, FIQ
, IRQ
, Supervisor
, Abort
, Undefined
和Monitor
模式本文档中如果不特殊声明,则使用异常级别(EL
)的术语:
EL1
和EL0
就是指非安全EL1和EL0
,除非有特殊说明;ARM设备上可能有的软件栈,如下所示:
如图所示,非安全空间中的拥有特权的代码:
Rich-OS
内核:比如,Linux
或Windows
,运行在非安全EL1
。如果运行在Hypervisor
之上,则Rich-OS
内核作为hypervisor
的一个客户机运行。Hypervisor
:运行在EL2
,只有非安全状态(新ARMv8架构中,已经存在安全状态的hypervisor
)。安全空间中拥有特权的代码:
安全平台固件(SPF)
:
芯片或OEM厂商提供。也是系统启动阶段,运行的第一段程序。它提供的服务有,平台初始化
、可信OS的安装
、SMC调用的调度执行
。有些调用的目标可能是SPF
,另一些则可能是可信OS
。SPF
可以运行在EL3
,也可以运行在安全EL1
(但是,条件是EL3
运行在AArch64
状态)。ARM提供了一个开源的可信固件代码。可信OS
:
为normal
空间提供安全服务,即为安全应用提供一个运行时环境。在AArch32
状态下,可信OS
运行在安全EL3
,如果是AArch64
状态,运行在EL1
。PSCI规范主要关注安全、非安全世界之间的电源管理接口。它提供了发送电源管理请求的方法。所以,为了处理这些请求,SPF
必须包含PSCI实现。
另外,PSCI实现也可能需要在SPF
和可信OS之间建立通信。当然,它们之间的处理根据厂商不同而有所不同。
尽管,PSCI主要关注安全和非安全世界之间的电源管理请求,但是,也可以在Rich OS
和hypervisor
之间使用。
在不同的异常级别之间提供可以传送消息的通道(一般使用SMC
异常指令实现),这样才能提供相同的PSCI电源管理接口。具体参考SMCCC
。
许多可信OS不支持SMP。即使在多核平台上,也是运行在某个指定的核上。所以,期望发起SMC调用的核与可信OS运行的核是同一个。不支持多核,可以保证可信OS小而美,容易通过功能安全认证。
基于ARM架构的系统通常会包含一个电源控制器,或者电源管理电路,以便管理CPU核的电源。它会提供许多电源管理功能,比如将核
、簇
或者集群
转变为低功耗状态。在低功耗状态,核可以完全关掉,也可以不执行代码而处于静默状态。ARM 强烈推荐由安全空间控制电源状态的变化。否则,在进入低功耗状态之前,不能清除安全状态(包括安全cache的清零)。其它的电源管理,比如动态电源性能管理(通过调节电压和频率实现)不在本接口规范的范围内。
虚拟机可以分为两种类型
Type-1
: 有时候称为 native
或 bare metal
。通俗理解的话,就是hypervisor代码直接接管硬件,对上提供统一的虚拟隔离空间。所以,Guest OS
看到的都是虚拟设备。Type-2
: 有时候称为hosted
,或者托管类型hypervisor
。这类虚拟程序需要依赖一个主机OS,作为宿主。该Host OS
看到的是真实硬件,但是Guest OS
看到的是虚拟设备。这是一个泛泛的分类,可能会有许多变种。ARMv8架构允许在EL1
或EL2
运行一个Type-2
类型的hypervisor
,这更加模糊了类型-1
和类型-2
的差异。但是,对于电源管理来说,不论哪种类型的hypervisor
,都需要捕获这种PSCI调用。
从电源管理和虚拟化的角度来看的话,有两种类型的OSPM
:
Guest OS
中的OSPM
,它管理的是虚拟的,而不是物理电源状态。对于type-2 hypervisor
,物理OSPM
存在于主机OS中。电源管理策略由运行在EL1
的Rich OS
负责管理。物理OSPM就包含在这种Rich OS
中。在该层,直接拥有物理核的视角。下图的左边部分就是示例。
对于本文涉及的电源管理,type-2 hypervisor
的行为取决于调用者。如果调用者是Host OS
,hypervisor
允许调用直接穿透到安全平台固件(SPF
)。在这种情况下,hypervisor
只需执行必要的操作,比如保存powerdown
时的状态。然后,使用调用者传递过来的参数调用SPF
。如果没有特殊操作,hypervisor
甚至不会捕获来自Host OS
的调用,直接将其路由给SPF
。Guest OS
使用虚拟OSPM
,也是通过PSCI API
发出电源管理请求,但是发送的目标是虚拟核和虚拟电源状态。hypervisor
会捕获这些请求,然后将其发送到物理OSPM
。然后,由物理OSPM
决定是否请求真实的物理电源管理。对于虚拟机来说,电源管理到hypervisor
就结束了。
对于type-1 hypervisor
,电源管理策略通常是hypervisor
自身管理的。如上图右半部分所示。hypervisor
实现物理OSPM
模块。这种情况下,虚拟机拥有的是虚拟核。由hypervisor
决定虚拟机的虚拟电源状态是否请求物理电源控制,如果需要,则使用PSCI API
调用安全平台固件SPF
。同样,Guest OS
也使用PSCI API
接口将虚拟电源管理请求发送给hypervisor
。对于虚拟机来说,电源管理到hypervisor
就结束了。
在某些情况下,type-1 hypervisor
委托一个特权Guest OS
管理电源。这种情况下,物理OSPM
在特权Guest OS
中实现。大概的电源管理方法与type-2 hypervisor
类似。
当一个核处于idle
状态时,OSPM
将其置于低功耗状态。通常,选择进入不同的电源状态,会有不同的entry
和exit
延迟,也会有不同的功耗。想要进入哪种电源状态,依赖于核重新工作的时间。除了核之外,电源状态也可能依赖于SoC中的其它组件的活动。每种状态都由一组组件的状态共同决定,进入该状态时,这些组件通过时钟控制(clock-gated
)或电源控制(power-gated
)。这些状态有时候也描述为浅睡眠
或深度睡眠
。通常,文献描述使用X
标识深度睡眠,Y
标识浅睡眠:
X
状态应该是Y
状态的超集。X
状态比Y
状态更省电。从低功耗状态进入运行状态所需要的时间称为唤醒延迟
。通常,深度睡眠状态具有更长的唤醒延迟。
尽管空闲电源管理是由核上的线程行为引起的,但是OSPM
将硬件平台设置的状态,也可能会影响除CPU核之外的其它组件。比如,如果SoC
中的最后一个核进入idle
状态,OSPM
就可以考虑整个SoC
的电源状态了。此时的选择也会受系统中的其它组件影响,所以,应该在SPF
、hypervisor
、OS
之间协调电源管理。典型的例子是,当所有核,和其它请求者都处于空闲状态时,将系统置于一种状态,在这种状态下,将上下文保存在内存中(内存不断刷新中)。OSPM
必须提供必要的电源管理软件基础设施,确定能够对电源状态作出正确的选择。
在空闲管理中,当一个核被置于低功耗状态,它可能随时被唤醒事件激活,比如说中断。
ARM架构划分的电源状态有四种:
Run
CPU核上电,且可以正常运行的状态。Standby
CPU核上电。通过WFI
或WFE
指令进入该状态,由唤醒事件唤醒。此过程中,CPU核保持所有状态。也就是说,从standby
到run
状态,不会复位CPU核。CPU核的上下文都会被保持,唤醒即可访问这些内容。处于该核所在电源域的外部调试器(debugger
),能够访问debug
寄存器。换句话说,standby
状态不会影响调试器的使用。Retention
CPU核的状态,包括debug
设置等,保存在低功耗的保持寄存器中,这样允许CPU核至少可以关闭部分电源。从低功耗状态到运行态的转变,不用复位CPU核。低功耗转变到运行态时,原先保存的状态数据从保持寄存器中恢复。所以,从OS的角度来说,Retention
和Standby
状态没有什么差别,除了恢复时的入口地址,延迟和使用上的一些限制之外。但是,对于外部debugger
来说,就不一样了,外部debug
请求事件会被挂起,debug
寄存器无法访问。Powerdown
该状态下,CPU核会被掉电。软件需要保存所有的核状态数据。从掉电到恢复运行,需要:Powerdown
状态对上下文是破坏性的。不仅仅是CPU核的状态数据,如果是更深的休眠状态,可能包括GIC或者平台依赖的其它一些IP核也会掉电。所以,相关数据或状态必须保存。根据debug
和trace
电源域的组织架构,其上下文内容也有可能会丢失。所以,OS必须提供保存和恢复这些内容的机制。
对于OS来说,standby
和retention
都是一样的,除了debugger
之外。所以,后面我们使用standby
代表这两种状态。
ARM期望在具有最高特权的异常级别上,实现管理电源控制器的代码(通常就是ATF
)。那么就必须提供接口,以便OSPM
将CPU核置于低功耗状态的消息事件,从不同的异常级层层往下传递(假设越往下,异常级别越高)。而PSCI
就是这样的一种机制,将OSPM
的电源请求传递给下一个异常级EL
。
对于standby
状态,直接使用WFI
或WFE
指令即可进入。但是,更深层的standby
或retention
状态,则要求对电源控制器
进行编程,而PSCI
仅提供访问电源控制器的接口,并隐藏了与平台相关的代码。
对于Powerdown
状态,则要求提供每一级EL
下保存和恢复上下文的接口。而且,对于Powerdown
状态还要求一个return
地址。这地址是被唤醒时,OS期望的开始运行的地方。对于Powerdown
状态,CPU核从reset
复位向量(安全状态)开始运行。待完成初始化,则跳转到Powerdown
之前要求的那个返回地址
处开始执行。PSCI
提供了传递返回地址
和上下文
的参数。
多核系统中,不同的电源域
控制系统的不同部分。每一个电源域可能是一个或多个PE(CPU核
、协处理器
、GPU
),内存(Cache
、DRAM
),簇内、簇间一致性部件
等组成。
电源域中的每个组件的电源状态,都可以影响电源域中的其它组件。虽然,从物理上来说,电源域不是一个必须存在的层次结构。但是,从软件的角度来说,必须进行一个逻辑上的划分。如果想要改变电源域的电源状态,必须对其依赖项进行排序。比如,共享Cache
的电源域,以及使用共享Cache
的CPU核的电源域,它们之间的依赖关系。在这样一个系统中,为了保证数据的一致性,必须先关闭CPU核的电源,然后再关闭共享Cache
的电源。
上图展示了一个系统级的电源域的拓扑结构的示例。它拥有两个子电源域,每一个包含一个cluster簇,支持一组cluster电源状态。每一个cluster电源域,又包含两个子电源域,每一个包含一个CPU核,并额外支持一个电源状态。
从硬件的角度来看,一个系统被划分为多个单独或共享的电源域。每个电源域都可以表示为电源域拓扑树中的一个节点。兄弟电源域是互斥的。父电源域由子电源域共享。树中的各种级别(示例中的核、cluster簇和系统)称为电源级别
。较高的级别,更接近树的根(系统),较低的级别更接近树叶(核)。
上面拓扑结构中的各个节点都有自己的电源状态,我们称为局部电源状态
。当处于空闲核上的OS请求电源状态的改变时,不仅需要请求改变CPU核的局部电源状态,还需要请求改变父节点的电源状态。比如,上图的示例中,假设核1是簇0内最后进入空闲状态的,对于OS来说,就需要同时为簇0和核1请求电源状态改变。这种组合的电源状态我们就称为组合电源状态
。这种组合电源状态可不是随意组合的,而是电源等级越高的节点上,其电源状态越浅。换句话说,子节点进入休眠的程度应该大于等于父节点。规则如下:
Powerdown
),电源等级低的节点也必须掉电;Retention
),电源等级低的节点只能是保持或掉电;Standby
),电源等级低的节点只能是待机、保持或掉电;Run
),电源等级低的节点可以是任意状态。如下表所示:
系统级 | 簇级 | 核级 |
---|---|---|
Run | Run | Standby |
Run | Run | Retention |
Run | Run | Powerdown |
Run | Retention | Retention |
Run | Retention | Powerdown |
Run | Powerdown | Powerdown |
Retention | Retention | Retention |
Retention | Retention | Powerdown |
Retention | Powerdown | Powerdown |
Powerdown | Powerdown | Powerdown |
ARM系统通常是多核、或多簇的处理器。本文档使用亲和力的层次结构
描述CPU核和簇的架构关系。亲和力层次结构往往直接对应系统的电源拓扑,但这也不是绝对的。
高层的节点进入某种局部电源状态,必须与子节点的电源状态进行协调。比如说,想要使一个簇(cluster
)进入Powerdown
状态,那么该簇内所有的核也必须进入Powerdown
状态。实现方式就是,其它核都进入Powerdown
状态,最后一个核再把自己和簇置于Powerdown
状态。
对于这种对子节点的电源状态进行协调的方式,PSCI
支持两种:平台协调模式、OS发起模式。
ATF
等)负责协调电源状态。当某个核上没有任务时,OSPM为该核、以及所在簇请求允许范围内的最深休眠状态。因为该核的电源状态改变请求,可能影响其父节点,所以,PSCI实现者得根据簇内所有节点的情况选择最深的休眠状态。实际上,电源状态请求表达了两种限制:
PSCI实现就会根据这两个限制,为指定的节点内所有核,选择一个最深的电源状态。下表展示了OSPM请求不同的电源组合状态,而PSCI最终能够响应的状态。假设簇1一直处于掉电状态中。
通常情况下,电源状态越深,唤醒延迟越长。所以,我们假设保持状态比掉电状态具有更短的唤醒延迟。但是,事实并非如此。根据第2个限制,PSCI实现者必须满足每个核唤醒时间的请求。假设双核系统,具有3层系统状态,状态A、B、C,电源休眠程度A < B < C
,而唤醒延迟则是A < C < B
。如果核0选择状态B,而核1选择状态C,系统将会进入状态A。状态B和C,不能同时满足2个核的要求。
PSCI 1.0
之前的版本只支持平台协调模式。
PSCI 1.0
引入,这种模式将电源协调的权利交给了OS。这种模式下,只有节点内的最后一个核进入空闲状态,OSPM才会为该节点申请空闲状态。
相比平台协调方式,OS协调方式则是将怎么选择最合适的休眠节点交给了OS,PSCI实现者只需实现,给我什么请求,我就响应什么动作即可
。示例如下表所示:
如表所示,我们可以看到OS视角和PSCI实现的视角有些不同的地方(红色标记)。这是因为OS虽然请求了,但是PSCI实现还未响应导致的。在上电的时候也会发生,因为PSCI实现会比OS更早看到CPU核。为了实现OS协调方式,必须解决竞争问题
。
CPU热插拔的概念不需要再重复。但是,CPU热插拔
和空闲管理中的powerdown
还是有一些差异:
操作系统通常在主核上完成内核的引导过程,然后再启动辅核。所以,对于支持热插拔的系统来说,辅核的启动和hotplug的操作是相同的,可以提供一套接口。
对于运行在单核上的可信OS,移除该核可能不可行,除非把可信OS迁移到其它核上。
PSCI提供具有下列属性的接口:
per-CPU
数据结构保存这些值。监控软件,狭义上理解为操作系统的内核。
PSCI提供了接口,允许OS请求系统system shutdown
、system reset
和system suspend(suspend-to-RAM)
。芯片供应商应该提供这些函数的统一实现,它们与监控软件是独立的。没有提供suspend-to-disk
,这是因为它是系统关机的一种特殊情况。
这儿,system
的意思是从整台机器的视角看待问题。也就是说,不是单一关闭某个核或者簇那么简单。当然,运行在虚拟机中的客户机OS,如果调用这些接口不会发生物理状态的变化。
但是,如果没有hypervisor
,或者调用者是hypervisor
,则会导致电源状态的物理变化。即使调用者在物理机器上运行,术语系统可能也不是指整个物理机器。例如,假设一个高级服务器系统由多个单板组成,每个单板具有一个BMC (board management controller
),每个单板包含多个SoC。这样的系统可以在每个SoC上运行一个OS实例。在本例中,用于关闭系统的PSCI命令应用于单个SoC,而关闭整个单板需要通过管理接口访问BMC,而这个管理接口是调用操作系统或PSCI实现无法访问的。在本文档中,术语系统仅指对操作系统可见的机器视图。反映到本文档中,就是指一个SOC。
功能接口描述。这些API
描述不包含底层的SMC
或HVC
调用。但是,这些函数却都遵守SMCCC
调用规约。如果实现了EL2
却没有实现EL3
,则hypervisor
使用HVC
为运行在EL1
的Guest OS
提供调用支持。调用格式都是一样的。PSCI
函数只能由非安全空间发起调用(EL1
或EL2
)。
PSCI
实现的版本号。uint32 Function ID
: 0x8400 0000
uint32
:[31:16]
-主版本号;[15:0]
-次版本号;PSCI
函数,返回NOT_SUPPORTED
。powerdown
请求,调用者必须保存复位重新运行时所需要的状态。也就是说保存的上下文必须是调用者在发生powerdown
调用之前power_state
参数所指示的电源级别(power_level
字段)下所有可见的状态。(就是调用者自己保存自己的状态,被调用者不管)Cache
或一致性操作。PSCI
实现者完成(PSCI实现侧负责内存一致性)。powerdown
请求使用指定的entry point
地址返回。因为,powerdown
可能不能完成,比如因为中断挂起。也有可能因为与其它核的协调,真正进入的是浅睡眠模式(相比请求的休眠模式)。因此,PSCI
实现可能将请求的powerdown
状态降为standby
状态。如果降为standby
状态,PSCI
实现返回到PSCI
调用之后的指令,而不是指定的entry_point
入口地址。此时,返回码也是成功的。如果发生比较早的wakeup
事件,实现也是返回下一条指令,返回码也是成功的,也有可能成功的在指定的entry point
地址处返回。CPU_SUSPEND
调用传递的入口地址必须是调用者视角下的物理地址。INVALID_PARAMETERS
:如果发生下面的情况,就会返回该错误。INVALID_ADDRESS
如果传递的入口地址,PSCI实现者认为是非法的,就返回该值。
PSCI 1.0
之前使用INVALID_PARAMETERS
代替该值。OS
协调模式下,如果发生以下两种情况,就会返回DENIED
:
在OS
协调模式下,如果系统的状态和请求状态不一致,会返回INVALID_PARAMETERS
,不同之处在于:核
电源级别的拓扑节点请求低功耗电源状态powerdown
状态,但是,该系统节点中的另一个核处于retention
状态时,就会返回参数错误。)power_state
参数不正确。预期是与平台固件表(如ACPI
或FDT
一致)DENIED
情况中,不一致的核必须运行中。错误会出现在调用者和实现者两侧。INVALID_PARAMETERS
情况中,不一致的节点必须处于低功耗状态,不一致只能通过调用者(OS)的错误产生。核
电源级别的拓扑节点请求低功耗电源状态PSCI 1.0
之前的版本支持的形式。当使用这种格式时,PSCI_FEATURES
使用CPU_SUSPEND
功能ID返回的标志字段的bit[1]
位被设置为0
。
各比特位的意义:
保留,必须是0StateID
:
对于一个硬件平台,支持每个核、簇或整个系统固定组合状态。这些状态产生了一组合法的power_state
值。这些状态应该通过固件表(如ACPI
或FDT
)表示给OSPM
。为此,PSCI 1.0
引入了一个新的扩展StateID
格式。这种格式对于PSCI
的实现者来说更为灵活,方便开发者实现PSCI
,可以通过ACPI
或FDT
电源状态的描述进行改进。这样的情况下,原先的格式有些字段就多余了。
使用这种格式的时候,PSCI_FEATURES
函数的返回标志中的bit[1]
会被设为1
(传递CPU_SUSPEND
功能ID)。
注意:一种实现中不可能混用这两种格式。
下表是power_state
参数的位域(扩展StateID
格式)。
保留,必须是0
推荐的编码格式:参考前面。
StateID
示例编码
0
,表示standby
或retention
状态;1
,表示powerdown
状态。另外,还说明entry_point_address
和context_id
的值合法;Level 0
: 核Level 1
: 簇Level 2
: 系统PowerLevel
,定义的电源域级别,也就是表示是核,簇还是系统层电源请求。
PSCI 1.0
之前的版本称为AffinityLevel
。
但是电源域级别的命名,却是实现者定义的。一般情况下,按照如下方式命名:StateType
:状态类型StateID
:状态ID
对请求的组合电源状态进行标识。一般是实现者定义的。在OS协调模式下,StateID
必须能够表示哪个核是最后一个进入idle状态的。
这些信息必须体现在FDT
或ACPI
固件表中,以便在请求电源状态时,将这些信息添加到StateID
字段中。推荐编码格式可以参考第6.5小节。
核是电源等级中的最后一个• 0: Core Level• 1: Cluster Level• 2: System Level0x8400 0001
-SMC32
版本0xC400 0001
-SMC64
版本uint32 Function ID
:uint32 power_state
从PSCI 1.0
开始,支持两种格式。entry_point_address
唤醒时,程序继续执行的起始地址。可以是PA(物理地址)或IPA(中间物理地址)。context_id
该参数只对调用者有用。PSCI实现者只需保留一下该参数的备份即可。从掉电状态唤醒时,PSCI
将该值写入到R0
、W0
或X0
通用寄存器中,进入异常的程序会通过该寄存器将保存的上下文内容恢复。CPU_SUSPEND
调用之前,非安全空间必须遵守以下规则:
调用者必须处理可能的错误码:平台
协调者模式中,调用者通过power_state
参数传递的指定进入的电源状态,在语义上不是强制的。相反,它代表的是调用者容忍的最深的电源状态。此种情况下,是通过PSCI
实现真正进入的电源状态。为此,如果一个核没有调用CPU_ON
而上电,或者调用了CPU_OFF
而关闭的情况下,假定该核进入了最深的电源状态。
而在OS
协调模式中,调用者显式请求某个特定的电源状态,而不是让PSCI
实现决定。实现必须遵循请求,除非与实现当前的状态不一致。ARMv8-A
的Firmware Framework
。
因为某些原因,可信OS或SP可能不兼容某种特殊的状态。这种情况下,ARM建议:可信OS或SP使用自定义的机制与非安全空间通信,保证它的限制可以被非安全空间的代码考虑。Powerdown
状态要求清除Cache。PSCI实现者必须在掉电一个节点之前,为该节点中所有的Cache和正在最后关闭的那个核执行清除操作。另外,PSCI实现还需要在启动阶段执行对Cache的失效操作,除非这是硬件能够自动完成的。在相关处理器和互连IP的技术参考手册中可以看到,上电或掉电应该遵守的顺序。standby
状态返回时,对于调用者来说,CPU核的状态应该没有变化,除了定时器和由于唤醒中断造成的CPU interface的变化之外。对于核来说,standby
状态和使用WFI
指令没有什么不同。唯一的不同就是,调用SMC指令造成的寄存器变化。R0
或W0
返回的值是错误码。对于standby
状态,成功时返回SUCCESS
。对于powerdown
状态,如果成功不会返回,因为唤醒时,从传递的入口地址处开始执行。如果不成功,返回错误码,表明错误原因。int32
:SUCCESS
;INVALID_PARAMETERS
;INVALID_ADDRESS
;DENIED
;NOT_SUPPORTED
。hotplug
。只能使用CPU_ON
调用重新开启一个核。0x8400 0002
uint32 Function ID
:int32
:成功不会返回;否则返回DENIED
。CPU_OFF
关闭。[24:31]
: 必须是0[16:23]
: 匹配MPIDR.Aff2
位域[8:15]
: 匹配MPIDR.Aff1
位域[0:7]
: 匹配MPIDR.Aff0
位域[40:63]
: 必须是0[32:39]
: 匹配MPIDR.Aff3
位域[24:31]
: 必须是0[16:23]
: 匹配MPIDR.Aff2
位域[8:15]
: 匹配MPIDR.Aff1
位域[0:7]
: 匹配MPIDR.Aff0
位域0x8400 0003
-SMC32
版本0xC400 0003
-SMC64
版本uint32 Function ID
: 功能IDuint32/uint64 target_cpu
:目标核
MPIDR
寄存器的备份。如果是AArch32
:
如果是AArch64
:uint32/uint64 entry_point_address
:入口地址
当核返回到非安全异常级时必须执行的地址。SMC64
版本时,是64位的物理地址或中间物理地址;SMC32
版本时,是32位的物理地址或中间物理地址;uint32/uint64 context_id
:上下文地址
当核返回到非安全异常级时:SMC64
版本时,该值必须保存在X0
寄存器;SMC32
版本时,该值必须保存在R0
寄存器。需要把该地址的上下文内容恢复(堆栈、执行状态、中断状态等)。int32
:SUCCESS
,成功则返回该值;INVALID_PARAMETERS
,描述了一个无效的MPIDR
;INVALID_ADDRESS
,ATF
认为传递进来的入口地址非法;ALREADY_ON
,ATF
认为该核已经启动;ON_PENDING
,已经发起了CPU_ON
请求,ATF
还未处理;INTERNAL_FAILURE
,因为物理原因,不能启动CPU核。0
:target_affinity
中的所有位域都是有效的。在不支持硬件线程化的处理器系统中,target_affinity
将会表示单个核。1
:表示target_affinity
中,忽略Aff0
位域。target_affinity
表示亲和力等级为1的处理单元。2
:表示target_affinity
中,忽略Aff0
和Aff1
位域。target_affinity
表示亲和力等级为2的处理单元。3
:表示target_affinity
中,忽略Aff0
、Aff1
和Aff2
位域。target_affinity
表示亲和力等级为3的处理单元。0x8400 0004
-SMC32
版本0xC400 0004
-SMC64
版本uint32 Function ID
:target_affinity
同CPU_ON
的target_cpu
参数格式一样。(SMC32
或SMC64
)lowest_affinity_level
表示target_affinity
参数中有效的最低亲和力级别。该参数允许AFFINITY_INFO
调用者请求大于0的亲和力等级的信息。
可能的值:
从PSCI 1.0
版本开始,AFFINITY_INFO
不再需要支持高于0
的亲和级别。int32
:2 ON_PENDING
,亲和力对象正在转换为ON
状态的过程中;1 OFF
,亲和力对象中,所有核都关闭;0 ON
,亲和力对象中,至少有一个核开启;INVALID_PARAMETERS
(PSCI 1.0
以上,请求亲和力值大于0的请求会返回该值);DISABLED
,由于物理原因禁止。0x8400 0005
-SMC32
版本0xC400 0005
-SMC64
版本uint32 Function ID
:target_cpu
同CPU_ON
调用的target_cpu
参数一样。int32
:SUCCESS
,成功则返回该值;NOT_SUPPORTED
,不支持该功能,或不需要迁移;INVALID_PARAMETERS
,描述了一个无效的MPIDR
;DENIED
,可信OS启动,但是不可迁移;INTERNAL_FAILURE
,因为物理原因,不能迁移;NOT_PRESENT
,可信OS不在请求的核上。0x8400 0006
uint32 Function ID
:int32
:0
支持单核迁移的可信OS。可信OS只能运行在一个核上。可信OS支持迁移功能,可以被迁移到任意一个核上。如果尝试对运行可信OS的核调用CPU_OFF
,请求会被拒绝(DENIED
)。1
不支持单核迁移的可信OS。可信OS只能运行在一个核上。可信OS不支持迁移功能。调用MIGRATE
会被拒绝。2
可信OS既不存在、也不需要迁移。这类系统不要求调用者使用MIGRATE
功能。如果硬要调用,返回NOT_SUPPORTED
。NOT_SUPPORTED
调用操作系统可以认为等价于返回值为2
的情况。0x8400 0007
-SMC32
版本0xC400 0007
-SMC64
版本uint32 Function ID
:UNDEFINED
:如果 MIGRATE_INFO_TYPE
调用返回2
或NOT_SUPPORTED
;基于MPIDR的值
:格式与CPU_ON
调用中的target_cpu
参数一样。SYSTEM_OFF
提供了一个系统关闭的接口。在调用该接口之前,调用者必须将所有的核置于已知状态。调用也只能是由非安全空间发起。一旦发起该调用,PSCI实现将会完全关闭最高等级的电源(也就是系统电源)。
启动必须是冷启动。0x8400 0008
uint32 Function ID
:0x8400 0009
uint32 Function ID
:SYSTEM_RESET
的扩展,PSCI 1.1
引入。提供:reset
方法reset
方法Bit[31]
,保留的话就必须为0.Bits[30:0]
0x0
SYSTEM_WARM_RESET
.0x8400 0012
-SMC32
版本0xC400 0012
-SMC64
版本uint32 Function ID
:reset_type
32位值,被分为两部分:cookie
32位或64位值。用来传递额外的reset
信息。int32
:SUCCESS
,成功不返回NOT_SUPPORTED
;INVALID_PARAMETERS
;PSCI 1.1
引入。0x8400 0013
uint32 Function ID
:enable
32位值,非0值表示内存保护被启动。0值表示禁止保护功能。int32
:NOT_SUPPORTED
。MEM_PROTECT
保护。PSCI 1.1
引入。0x8400 0014
-SMC32
版本0xC400 0014
-SMC64
版本uint32 Function ID
:uint32/64 base
要检查的内存的基地址;uint32/64 length
要检查的内存的长度;int32
:SUCCESS
DENIED
NOT_SUPPORTED
SMCCC_VERSION
或者某个PSCI
功能是否被实现。PSCI 1.0
引入。0x8400 000A
uint32 Function ID
:psci_func_id
功能ID:PSCI
或SMCCC_VERSION
CPU_SUSPEND
功能ID[31:2]
保留,等于0
[1]0
,power_state
使用原始格式(PSCI 2.0
)
1
,power_state
新的扩展StateID
格式
[0]0
,不支持OS协调方式
1
,支持OS协调方式其它功能ID[31:0]
保留都是0CPU_OFF
不同,中断仍然可以传递给该核。但是,该核一直会处于低功耗状态中,直到CPU_ON
调用将其启动。PSCI 1.0
引入。0x8400 000B
uint32 Function ID
:int32
:NOT_SUPPORTED
或DENIED
。CPU_SUSPEND
不同的是,不需要指定power_state
参数。PSCI 1.0
引入。0x8400 000C
-SMC32
版本0xC400 000C
-SMC64
版本uint32 Function ID
:entry_point_address
参考CPU_SUSPEND
;context_id
参考CPU_SUSPEND
;int32
:SUCCESS
INVALID_ADDRESS
PSCI 1.0
引入。0x8400 000D
-SMC32
版本0xC400 000D
-SMC64
版本uint32 Function ID
:target_cpu
参考CPU_ON
;power_level
表示想要请求的节点,在电源域拓扑结构的层级。这是供应商自定义的,但是0保留给CPU核。int32
:2 HW_STANDBY
:返回2
,表示处于standby
或retention
电源状态;1 HW_OFF
:返回1
,表示处于powerdown
状态;0 HW_ON
:返回0
,表示处于run
状态;NOT_SUPPORTED
INVALID_PARAMETERS
CPU_SUSPEND
,将系统置于最低功耗状态。该调用是实现system suspend-to-RAM
的基础(ACPI规范中描述的S2和S3状态)。值得注意的是,系统进入S2或S3状态,需要几个前提条件。系统中所有设备必须与进入该系统挂起状态兼容,可能需要在调用之前,优雅地处理各个外设。这些前提条件不在本文的讨论范围内。SYSTEM_SUSPEND
仅限于提供进入S2或S3状态的机制,所有必要的条件都由调用OS满足。尽管ACPI将suspend-to-RAM
功能分为S2
或S3
两种状态,但是PSCI
只提供了一个API。
同SYSTEM_SHUTDOWN
和SYSTEM_RESET
一样,该函数适用于调用OS的机器视角。
为了使用该函数调用,调用者必须使用CPU_OFF
关闭所有的核,但保留一个核。剩下的这个核调用SYSTEM_SUSPEND
,传递entry_point_address
和context_id
参数(唤醒时用),进入挂起状态。调用者(OS)可以在调用SYSTEM_SUSPEND
之前,使用AFFINITY_INFO
函数保证所有其它核都已关闭。0x8400 000E
-SMC32
版本0xC400 000E
-SMC64
版本uint32 Function ID
:entry_point_address
:参考CPU_SUSPEND
context_id
:参考CPU_SUSPEND
NOT_SUPPORTED
INVALID_ADDRESS
ALREADY_ON
PSCI 1.0
引入。0
: 平台协调方式1
: OS协调方式0x8400 000F
uint32 Function ID
:mode
int32
SUCCESS
NOT_SUPPORTED
INVALID_PARAMETERS
DENIED
PSCI 1.0
引入。0x8400 0010
-SMC32
版本0xC400 0010
-SMC64
版本uint32 Function ID
:target_cpu
格式与CPU_ON
调用相同;power_state
指定的电源状态。PSCI 1.0
引入。0x8400 0010
-SMC32
版本0xC400 0010
-SMC64
版本uint32 Function ID
:target_cpu
格式与CPU_ON
调用相同;power_state
指定的电源状态。定义 | 值 |
---|---|
SUCCESS | 0 |
NOT_SUPPORTED | -1 |
INVALID_PARAMETERS | -2 |
DENIED | -3 |
ALREADY_ON | -4 |
ON_PENDING | -5 |
INTERNAL_FAILURE | -6 |
NOT_PRESENT | -7 |
DISABLED | -8 |
INVALID_ADDRESS | -9 |
本文分享自 嵌入式ARM和Linux 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!