基于ARM架构的PSCI接口规范

电子说

1.3w人已加入

描述

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设备上可能有的软件栈,如下所示:

Linux

如图所示,非安全空间中的拥有特权的代码:

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中。在该层,直接拥有物理核的视角。下图的左边部分就是示例。

Linux

对于本文涉及的电源管理,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的电源。

Linux

上图展示了一个系统级的电源域的拓扑结构的示例。它拥有两个子电源域,每一个包含一个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一直处于掉电状态中。

Linux

通常情况下,电源状态越深,唤醒延迟越长。所以,我们假设保持状态比掉电状态具有更短的唤醒延迟。但是,事实并非如此。根据第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实现者只需实现,给我什么请求,我就响应什么动作即可。示例如下表所示:

Linux

如表所示,我们可以看到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示例编码

Linux

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调用流程

Linux

6.1.2 CPU_OFF调用流程

Linux

6.1.3 CPU_ON调用流程

Linux

审核编辑:郭婷

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分