电子说
1 介绍
本文主要是在ARM架构的不同异常等级上工作的软件之间,提供一个标准的电源管理接口。这些软件,比如Linux、Hypervisor、安全Firmware和可信OS之间必须能够实现互相操作。而这些软件可能由不同厂商提供,本标准就是为这些软件的集成提供便利。
这些PSCI接口有利于电源管理代码通用化、模块化:
CPU核的空闲管理
CPU核的动态添加、删除,以及辅核引导
系统关机和复位
该接口规范不会包含动态电压频率调节(DVFS)或设备电源管理(比如,GPU等外设的管理).
该接口规范设计用来与硬件探测技术(如ACPI和FDT)等配合使用,并不是要取代ACPI或FDT。
本文描述了PSCI版本1.1,1.0和0.2。对于0.2,还提供了一个勘误更新。
本文包含以下内容:
第1章 提供介绍和文档引用
第2-4章 提供背景知识,包括:
PSCI的设计目的
电源状态术语的定义
发送PSCI请求的方法
ARM架构知识
第5章 提供PSCI功能的主要描述
第6章 提供PSCI功能的实现细节
第7-8章 提供PSCI规范的修订历史和术语表
1.1 ARM官方文档
下面这些文档包含与本文档相关的信息:
[1] ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition (ARM DDI 0406).
[2] Embedded Trace Macrocell Architecture Specification (ARM IHI 0014).
[3] Program Flow Trace Architecture Specification (ARM IHI 0035).
[4] SMC调用约定(ARM DEN 0028).
[5] ARM Architecture Reference Manual ARMv8, for ARMv8-A architecture profile (ARM DDI 0487).
[6] ACPI规范.
[7] PSCI设备树定义.
[8] ARM可信固件(ATF).
[9] Power Control System Architecture Specification (ARM DEN 0050).
2 背景知识
支持电源管理的操作系统,能够动态改变CPU核的电源状态,根据进行负载均衡,努力降低功耗。电源管理技术主要分为两类:
空闲管理:当在某个核上,OS的内核没有线程可以调度时,可以将该核置于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情况下如何使用它们。
3 假设和建议
本文档定义了在不同监管软件之间协调电源管理的API。这种API允许监管软件请求给核上电、掉电,安全上下文的核间迁移(可信OS需要)。本文中,假设EL2和EL3都已经实现。
3.1 PSCI用途
PSCI具有下面的用途:
提供给监控程序通用接口,可以在下列情况时,管理功耗:
CPU核的空闲管理;
系统中的CPU核动态添加和删除,也称之为hotplug热插拔;
其它辅核的启动;
将受信任的操作系统上下文从一个核迁移到另一个核;
系统关机和复位。
提供给监控管理程序通用接口,结合FDT和ACPI描述去支持电源管理代码的泛化。
PSCI不包括:外设电源管理 和 动态电压和频率调节(DVFS)。
PSCI不提供给监控软件电源状态表示。但是,可以和ACPI或FDT等硬件描述技术结合使用。
3.2 异常级别、ARMv7特权级别和最高特权级别
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,除非有特殊说明;
3.3 ARM架构上的软件栈
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之间使用。
3.4 通道
在不同的异常级别之间提供可以传送消息的通道(一般使用SMC异常指令实现),这样才能提供相同的PSCI电源管理接口。具体参考SMCCC。
3.5 安全软件和电源管理
许多可信OS不支持SMP。即使在多核平台上,也是运行在某个指定的核上。所以,期望发起SMC调用的核与可信OS运行的核是同一个。不支持多核,可以保证可信OS小而美,容易通过功能安全认证。
基于ARM架构的系统通常会包含一个电源控制器,或者电源管理电路,以便管理CPU核的电源。它会提供许多电源管理功能,比如将核、簇或者集群转变为低功耗状态。在低功耗状态,核可以完全关掉,也可以不执行代码而处于静默状态。ARM 强烈推荐由安全空间控制电源状态的变化。否则,在进入低功耗状态之前,不能清除安全状态(包括安全cache的清零)。其它的电源管理,比如动态电源性能管理(通过调节电压和频率实现)不在本接口规范的范围内。
3.6 虚拟化和CPU核电源管理策略
虚拟机可以分为两种类型
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:
物理OSPM: 这个概念包含管理物理电源状态的软件。
虚拟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类似。
4 PSCI使用场景和要求
4.1 空闲管理
当一个核处于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核会被掉电。软件需要保存所有的核状态数据。从掉电到恢复运行,需要:
上电后,需要复位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提供了传递返回地址和上下文的参数。
4.2 电源状态系统拓扑
多核系统中,不同的电源域控制系统的不同部分。每一个电源域可能是一个或多个PE(CPU核、协处理器、GPU),内存(Cache、DRAM),簇内、簇间一致性部件等组成。
电源域中的每个组件的电源状态,都可以影响电源域中的其它组件。虽然,从物理上来说,电源域不是一个必须存在的层次结构。但是,从软件的角度来说,必须进行一个逻辑上的划分。如果想要改变电源域的电源状态,必须对其依赖项进行排序。比如,共享Cache的电源域,以及使用共享Cache的CPU核的电源域,它们之间的依赖关系。在这样一个系统中,为了保证数据的一致性,必须先关闭CPU核的电源,然后再关闭共享Cache的电源。
上图展示了一个系统级的电源域的拓扑结构的示例。它拥有两个子电源域,每一个包含一个cluster簇,支持一组cluster电源状态。每一个cluster电源域,又包含两个子电源域,每一个包含一个CPU核,并额外支持一个电源状态。
从硬件的角度来看,一个系统被划分为多个单独或共享的电源域。每个电源域都可以表示为电源域拓扑树中的一个节点。兄弟电源域是互斥的。父电源域由子电源域共享。树中的各种级别(示例中的核、cluster簇和系统)称为电源级别。较高的级别,更接近树的根(系统),较低的级别更接近树叶(核)。
4.2.1 局部电源状态和组合电源状态
上面拓扑结构中的各个节点都有自己的电源状态,我们称为局部电源状态。当处于空闲核上的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 |
4.2.2 亲和力的层次结构
ARM系统通常是多核、或多簇的处理器。本文档使用亲和力的层次结构描述CPU核和簇的架构关系。亲和力层次结构往往直接对应系统的电源拓扑,但这也不是绝对的。
4.2.3 电源状态协调
高层的节点进入某种局部电源状态,必须与子节点的电源状态进行协调。比如说,想要使一个簇(cluster)进入Powerdown状态,那么该簇内所有的核也必须进入Powerdown状态。实现方式就是,其它核都进入Powerdown状态,最后一个核再把自己和簇置于Powerdown状态。
对于这种对子节点的电源状态进行协调的方式,PSCI支持两种:平台协调模式、OS发起模式。
平台协调模式
这是默认的电源协调模式。在该模式下,PSCI实现者(如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之前的版本只支持平台协调模式。
调用者请求的电源状态已经是最深休眠状态了;
调用者请求的电源状态的唤醒延迟不能比这更长了;
OS协调模式
PSCI 1.0引入,这种模式将电源协调的权利交给了OS。这种模式下,只有节点内的最后一个核进入空闲状态,OSPM才会为该节点申请空闲状态。
相比平台协调方式,OS协调方式则是将怎么选择最合适的休眠节点交给了OS,PSCI实现者只需实现,给我什么请求,我就响应什么动作即可。示例如下表所示:
如表所示,我们可以看到OS视角和PSCI实现的视角有些不同的地方(红色标记)。这是因为OS虽然请求了,但是PSCI实现还未响应导致的。在上电的时候也会发生,因为PSCI实现会比OS更早看到CPU核。为了实现OS协调方式,必须解决竞争问题。
PSCI实现必须怀疑与自己视角不一样的电源状态请求;
OS必须指明哪个核是最后一个,而且还要指明该核处于哪一级电源中,如,是簇内的最后一个核,还是系统内最后的一个核。
4.3 CPU热插拔和辅核启动
CPU热插拔的概念不需要再重复。但是,CPU热插拔和空闲管理中的powerdown还是有一些差异:
当核被拔出时,监控软件会停止在中断和线程处理中对该核的所有使用。调用监控软件认为核不再可用。
想要使用该核,必须发送命令将核再插入。
唤醒事件不会唤醒被拔出的核。
操作系统通常在主核上完成内核的引导过程,然后再启动辅核。所以,对于支持热插拔的系统来说,辅核的启动和hotplug的操作是相同的,可以提供一套接口。
对于运行在单核上的可信OS,移除该核可能不可行,除非把可信OS迁移到其它核上。
PSCI提供具有下列属性的接口:
监控软件可以请求给一个核上电。监控软件还必须提供一个启动地址,作为它从安全固件退出时,继续执行的地方。通过提供一个入口地址,监控软件可以直接在自己的地址空间中干一些特殊的事情。为此,监控软件还必须使用内部的per-CPU数据结构保存这些值。
监控软件可以请求给一个核掉电。并且还能通知更高异常级别上的软件。
监控软件还能请求将可信OS迁移到另一个核上。
监控软件,狭义上理解为操作系统的内核。
4.4 系统级的shutdown、reset和suspend
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。
5 函数接口描述
功能接口描述。这些API描述不包含底层的SMC或HVC调用。但是,这些函数却都遵守SMCCC调用规约。如果实现了EL2却没有实现EL3,则hypervisor使用HVC为运行在EL1的Guest OS提供调用支持。调用格式都是一样的。PSCI函数只能由非安全空间发起调用(EL1或EL2)。
5.1 PSCI_VERSION
功能描述
返回PSCI实现的版本号。
参数
uint32 Function ID: 0x8400 0000
返回值
uint32:
位[31:16]-主版本号;
位[15:0]-次版本号;
注意
对于没有实现的PSCI函数,返回NOT_SUPPORTED。
5.2 CPU_SUSPEND
功能描述
挂起CPU核或它之上的更高拓扑结构中的节点。用于空闲状态管理,期望CPU核唤醒时从之前的执行位置继续执行。
参数
对于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调用传递的入口地址必须是调用者视角下的物理地址。
上下文标识符只对调用者有意义。PSCI实现者保存,唤醒时在返回的异常级别下,再传递给CPU核,通过该值,恢复掉电前的上下文。
INVALID_PARAMETERS:如果发生下面的情况,就会返回该错误。
INVALID_ADDRESS
如果传递的入口地址,PSCI实现者认为是非法的,就返回该值。
PSCI 1.0之前使用INVALID_PARAMETERS代替该值。
在OS协调模式下,如果发生以下两种情况,就会返回DENIED:
在OS协调模式下,如果系统的状态和请求状态不一致,会返回INVALID_PARAMETERS,不同之处在于:
为高于核电源级别的拓扑节点请求低功耗电源状态
该节点中至少一个子节点与请求的电源状态不兼容(比如,一个核发起请求,将系统级节点置于powerdown状态,但是,该系统节点中的另一个核处于retention状态时,就会返回参数错误。)
提供的power_state参数不正确。预期是与平台固件表(如ACPI或FDT一致)
在OS协调模式下,发生以下两种条件时,也会返回参数错误:
在DENIED情况中,不一致的核必须运行中。错误会出现在调用者和实现者两侧。
在INVALID_PARAMETERS情况中,不一致的节点必须处于低功耗状态,不一致只能通过调用者(OS)的错误产生。
为高于核电源级别的拓扑节点请求低功耗电源状态
所有与请求不一致的核必须处于运行中,而不是低功耗状态
原始格式
PSCI 1.0之前的版本支持的形式。当使用这种格式时,PSCI_FEATURES使用CPU_SUSPEND功能ID返回的标志字段的bit[1]位被设置为0。
各比特位的意义:
位域 | 描述 |
---|---|
31:26 | 保留,必须是0 |
25:24 | PowerLevel |
23:17 | 保留,必须是0 |
16 | StateType |
15:0 | StateID |
扩展StateID:
对于一个硬件平台,支持每个核、簇或整个系统固定组合状态。这些状态产生了一组合法的power_state值。这些状态应该通过固件表(如ACPI或FDT)表示给OSPM。为此,PSCI 1.0引入了一个新的扩展StateID格式。这种格式对于PSCI的实现者来说更为灵活,方便开发者实现PSCI,可以通过ACPI或FDT电源状态的描述进行改进。这样的情况下,原先的格式有些字段就多余了。
使用这种格式的时候,PSCI_FEATURES函数的返回标志中的bit[1]会被设为1(传递CPU_SUSPEND功能ID)。
注意:一种实现中不可能混用这两种格式。
下表是power_state参数的位域(扩展StateID格式)。
位域 | 描述 |
---|---|
31 | 保留,必须是0 |
30 | StateType |
29:28 | 保留,必须是0 |
27:0 | StateID |
推荐的编码格式:参考前面。
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小节。
位域 | 描述 |
---|---|
15:12 |
核是电源等级中的最后一个 • 0: Core Level • 1: Cluster Level • 2: System Level |
11:8 |
系统级局部电源状态: • 0: Run • 2: Retention • 3: Powerdown |
7:4 |
簇级局部电源状态: • 0: Run • 2: Retention • 3: Powerdown |
3:0 |
核级局部电源状态: • 0: Run • 1: standby • 2: Retention • 3: Powerdown |
0x8400 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调用之前,非安全空间必须遵守以下规则:
调用者必须处理可能的错误码:
PSCI实现者的责任:状态协调
在平台协调者模式中,调用者通过power_state参数传递的指定进入的电源状态,在语义上不是强制的。相反,它代表的是调用者容忍的最深的电源状态。此种情况下,是通过PSCI实现真正进入的电源状态。为此,如果一个核没有调用CPU_ON而上电,或者调用了CPU_OFF而关闭的情况下,假定该核进入了最深的电源状态。
而在OS协调模式中,调用者显式请求某个特定的电源状态,而不是让PSCI实现决定。实现必须遵循请求,除非与实现当前的状态不一致。
PSCI实现者的责任:与可信OS或PF进行交互
PSCI实现必须能够与可信OS或SP进行通信。交互方法请参考ARMv8-A的Firmware Framework。
因为某些原因,可信OS或SP可能不兼容某种特殊的状态。这种情况下,ARM建议:可信OS或SP使用自定义的机制与非安全空间通信,保证它的限制可以被非安全空间的代码考虑。
PSCI实现者的责任:Cache和内存一致性管理
Powerdown状态要求清除Cache。PSCI实现者必须在掉电一个节点之前,为该节点中所有的Cache和正在最后关闭的那个核执行清除操作。另外,PSCI实现还需要在启动阶段执行对Cache的失效操作,除非这是硬件能够自动完成的。在相关处理器和互连IP的技术参考手册中可以看到,上电或掉电应该遵守的顺序。
PSCI实现者的责任:返回状态
当从standby状态返回时,对于调用者来说,CPU核的状态应该没有变化,除了定时器和由于唤醒中断造成的CPU interface的变化之外。对于核来说,standby状态和使用WFI指令没有什么不同。唯一的不同就是,调用SMC指令造成的寄存器变化。R0或W0返回的值是错误码。对于standby状态,成功时返回SUCCESS。对于powerdown状态,如果成功不会返回,因为唤醒时,从传递的入口地址处开始执行。如果不成功,返回错误码,表明错误原因。
返回值
int32:
SUCCESS;
INVALID_PARAMETERS;
INVALID_ADDRESS;
DENIED;
注意
对于没有实现的PSCI函数,返回NOT_SUPPORTED。
5.3 CPU_OFF
功能描述
关闭核。用于hotplug。只能使用CPU_ON调用重新开启一个核。
参数
0x8400 0002
uint32 Function ID:
返回值
int32:成功不会返回;否则返回DENIED。
5.4 CPU_ON
功能描述
启动一个核。有两种情况:(1)启动阶段时调用;(2)该核之前被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: 功能ID
uint32/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核。
5.5 AFFINITY_INFO
功能描述
请求某个亲和力等级上的信息。
参数
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,由于物理原因禁止。
5.6 MIGRATE
功能描述
(可选的)请求将可信OS迁移到另一个核上。
参数
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不在请求的核上。
5.7 MIGRATE_INFO_TYPE
功能描述
(可选的)请求可信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的情况。
5.8 MIGRATE_INFO_UP_CPU
功能描述
(可选的)返回单核可信OS所在的核。
参数
0x8400 0007-SMC32版本
0xC400 0007-SMC64版本
uint32 Function ID:
返回值
可能是32位或64位:
UNDEFINED:如果 MIGRATE_INFO_TYPE调用返回2或NOT_SUPPORTED;
基于MPIDR的值:格式与CPU_ON调用中的target_cpu参数一样。
5.9 SYSTEM_OFF
功能描述
关闭系统。
SYSTEM_OFF提供了一个系统关闭的接口。在调用该接口之前,调用者必须将所有的核置于已知状态。调用也只能是由非安全空间发起。一旦发起该调用,PSCI实现将会完全关闭最高等级的电源(也就是系统电源)。
启动必须是冷启动。
参数
0x8400 0008
uint32 Function ID:
返回值
不需要返回。
5.10 SYSTEM_RESET
功能描述
提供系统冷复位的方法。
参数
0x8400 0009
uint32 Function ID:
返回值
不需要返回。
5.11 SYSTEM_RESET2
功能描述
(可选)对SYSTEM_RESET的扩展,PSCI 1.1引入。提供:
架构相关的reset方法
供应商提供的reset方法
参数
Bit[31],保留的话就必须为0.
Bits[30:0]
设为1,则使用供应商提供的reset方法;
设为0,则为架构提供的reset方法;
0x0 SYSTEM_WARM_RESET.
其它值保留.
对于供应商提供的reset方法,这些位的意义由供应商定义。
对于架构提供的reset方法,定义如下:
0x8400 0012-SMC32版本
0xC400 0012-SMC64版本
uint32 Function ID:
reset_type
32位值,被分为两部分:
cookie
32位或64位值。用来传递额外的reset信息。
返回值
int32:
SUCCESS,成功不返回
NOT_SUPPORTED;
INVALID_PARAMETERS;
5.12 MEM_PROTECT
功能描述
(可选)通过在将内存移交给操作系统加载程序之前,重写这段内存,来提供针对冷重启攻击的保护。PSCI 1.1引入。
参数
0x8400 0013
uint32 Function ID:
enable
32位值,非0值表示内存保护被启动。0值表示禁止保护功能。
返回值
int32:
成功,则返回之前的使能状态:0,表示之前是被禁止的;1,表示之前是使能的。
失败,则返回NOT_SUPPORTED。
5.13 MEM_PROTECT_CHECK_RANGE
功能描述
(可选)可以检查某段内存是否被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
5.14 PSCI_FEATURES
功能描述
查询SMCCC_VERSION或者某个PSCI功能是否被实现。PSCI 1.0引入。
参数
0x8400 000A
uint32 Function ID:
psci_func_id
功能ID:PSCI或SMCCC_VERSION
返回值
如果功能实现,则意义如下:
psci_func_id | 标志位 | 描述 |
---|---|---|
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] | 保留都是0 |
5.15 CPU_FREEZE
功能描述
(可选)将核置于供应商自定义的低功耗状态中。与CPU_OFF不同,中断仍然可以传递给该核。但是,该核一直会处于低功耗状态中,直到CPU_ON调用将其启动。PSCI 1.0引入。
参数
0x8400 000B
uint32 Function ID:
返回值
int32:
成功,不返回。
失败,则返回NOT_SUPPORTED或DENIED。
5.16 CPU_DEFAULT_SUSPEND
功能描述
(可选)将核置于供应商自定义的低功耗状态中。与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
5.17 NODE_HW_STATE
功能描述
(可选)返回系统的电源域拓扑结构中一个节点的硬件状态。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
5.18 SYSTEM_SUSPEND
功能描述
语义等价于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
返回值
返回32位值。
NOT_SUPPORTED
INVALID_ADDRESS
ALREADY_ON
成功不会返回;
失败则返回:
5.19 PSCI_SET_SUSPEND_MODE
功能描述
(可选)设置电源状态协调方式。PSCI 1.0引入。
参数
0: 平台协调方式
1: OS协调方式
0x8400 000F
uint32 Function ID:
mode
返回值
int32
SUCCESS
NOT_SUPPORTED
INVALID_PARAMETERS
DENIED
5.20 PSCI_STAT_RESIDENCY
功能描述
(可选)返回冷启动之后,在某种状态下的度过时间。PSCI 1.0引入。
参数
0x8400 0010-SMC32版本
0xC400 0010-SMC64版本
uint32 Function ID:
target_cpu
格式与CPU_ON调用相同;
power_state
指定的电源状态。
返回值
可能是32位或64位。返回处于指定电源状态的时间。
5.21 PSCI_STAT_COUNT
功能描述
(可选)返回冷启动之后,进入某种状态下的次数。PSCI 1.0引入。
参数
0x8400 0010-SMC32版本
0xC400 0010-SMC64版本
uint32 Function ID:
target_cpu
格式与CPU_ON调用相同;
power_state
指定的电源状态。
返回值
可能是32位或64位。进入某种状态下的次数。
5.22 错误码
定义 | 值 |
---|---|
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 |
6 其它实现细节
6.1 PSCI调用流程
6.1.1 CPU_SUSPEND、CPU_DEFAULT_SUSPEND和SYSTEM_SUSPEND调用流程
6.1.2 CPU_OFF调用流程
6.1.3 CPU_ON调用流程
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !