ACPI是高级配置与电源接口(AdvancedConfiguration and Power Interface)的简称,它是1997年由Intel、Microsoft、Toshiba,HP,Phoenix所共同制定,提供操作系统应用程序管理所有电源管理的接口。2000年8月推出 ACPI 2.0规范。2004年9月推出 ACPI 3.0规范。2009年6月16日则推出ACPI 4.0规范。最新ACPI版本为5.0,2011年发布。电源管理是ACPI中非常重要的一部分。
ACPI中的I是指Interface,它是一系列的表格。这些表格描述了系统信息,特性,以及设定这些特性的方法。SBIOS一般会将这些表格放在F段内存中,供非EFI操作系统读取。
这些表格的结构和联系如下所示:
图1. RSDP
图2. 引出的表格
一.G状态
针对系统整个平台来定义,肉眼可以识别。我们根据吃电量大小,软件是否工作,外部事件触发到工作状态的延时时间,拆机是否安全等来判断系统处于哪种状态。
G0:工作状态,操作系统分发用户线程并执行。在此状态中,外围设备吃电量可以改变。
G1:显示器关闭,用户态线程不再执行。系统状态S1,S3,S4均属G1状态。返回G0状态用时比G2短。
G2:关机状态,硬件不会保存软件环境,需要较长时间才能返回到工作状态。此状态也称为soft off。
G3:也称Mechanicaloff,除RTC电开启外,再无其它电,此种状态下,我们拆机不会有短路风险。
对于工控机和服务器而言,我们要经常做的一个功能叫AC Power Loss。就是丢失AC电源后,再重新获得AC电后,平台电源应该如果设定。AC power Loss后的状态为G3,我们可以设定PCH的PMC寄存器位AFTERG3,来告知PCH,平台重新获得AC电后,我们需要进入S5状态或者S0状态。当然有些笔记本平台也做这个功能,但笔记本厂商为了省电并不会像做工控机和服务器一样去做这个功能,因为这样做要开启ALWAYS电和RSMRST#,这样如果用户设定G3After进S5,那么对锂电池是一种浪费。所以笔记本如果做这个功能,通常由EC来做。
二.S状态
系统状态,这种状态是针对OS所定义。G状态中除了G3,其余G0,G1和G2分别有相应的状态与之相对应。
S状态的判定:可根据平台吃电量大小,系统返回工作状态的延时时间来判定。
操作系统是否支持此种状态,支持几种S状态,要根据SBIOS提供给OS的ACPI接口所定。在表格DSDT中,有如下NAME OBJECT
Name(\_S0, Package(4) {0x0,0x0,0,0})
Name(\_S3, Package(4) {0x5,0x0,0,0})
Name(\_S4, Package(4) {0x6,0x0,0,0})
Name(\_S5, Package(4) {0x7,0x0,0,0})
由此,OS可知此平台需要支持S0,S3,S4,S5四种S状态。Package中的第一个元素,是OS进相应状态时,往FADT中的PM_CNT字段要写的值。
S0:工作状态,和G0相同。
S1:CPU时钟信号被停止,CPU有较低的功耗,返回到S0的时间较短。
S3:即我们常说的睡眠状态。此状态下,系统环境保存在内存里面。设备带电方面:只有内存VCC保留,其余设备全部关闭。时钟方面:只有RTC时钟依然有效,其余全部关闭。
S4:我们常说的休眠状态。此状态下,系统环境保存在硬盘上面。设备带电方面,所有设备都没电。时钟方面,RTC时钟依然工作。
S5:关机状态。系统环境不再保存。返回S0时,系统要重新启动。此状态下,吃电量和S4吃电量一样。不同的是,OSPM不会把系统环境保存在硬盘上面。
之前,在做一个国产平台时,CPU厂商让我配合着做S1。但它们只是让CPUHALT,让我把LVDS屏的背光关掉,CPU时钟信号还是跑得嗷嗷叫。我一直纳闷:这哪是S1啊,只能算是比较浅的G1吧,但别人既然这么叫了,咱也得认不是。
作为ECBIOS,要根据SLP_S4#和SLP_S3#和电平状态来给平台供电。至于SLP_S5#,对于ECBIOS来讲,没有什么意义。至于系统是否处于S1状态,ECBIOS无法知晓,因为没有任意一个PIN给指示。下图是他们的电平高低所指示的S状态。
SLP_S3# |
SLP_S4# |
SLEEP状态 |
H |
H |
S0 |
L |
H |
S3 |
L |
L |
S4或S5 |
三.C状态
C状态是G0下的CPU电源状态。分为ACTIVE和SLEEP状态。即C0,C1,C2,C3……Cn。最常用的为C0和C1。
C0:ACTIVE状态,此状态下,CPU执行指令。CPU PSTATE和THROTTLING功能都在此状态下被调用。
C1:所有的处理器必须支持这种状态。这种状态的支持是通过一个本地的处理器指令(HLT或者mwait),并且认为不需要芯片组的硬件支持,即不需要PMC的支持。这种状态的硬件延迟必须足够的低。在C1状态下,处理器可以保持系统cache里面的内容。只要系统有任何中断产生,CPU便从C1返回C0。
其余C状态均不是必须的,但为了平台省电功能,也最好加上去。我曾经因为有些机台开启C1以上的状态时会死机。所以只能开启C0和C1,其余C状态均禁掉。但这样做,测试结果是:会造成电池耗电量比正常开启所有支持的C状态的机台高一倍,可见C状态对平台功耗还是很重要的。如果硬件工程师没有足够的经验支撑,还是不要随便改动公板有关CPU的线路图,这个地方出了问题还得重新改板。
有关C状态的做法,并不复杂。只需要对应文档,查到CPU所能支持的C状态。然后在VFR中设定即可。
在VFR中的相关设定的值,SBIOS一方面会改写MSR中,另一方面会重新改写ASL的变量。这样在OSPM调用_CST时,就会根据ASL的变量作为判断,获取到相应的C状态package。
图3. _CST实例
由图可知,该实例有4个C状态。因为其是从ACPI直接截的图,所以不支持VFR的设定。实际情况可能要比上图复杂得多,并且有的平台还要根据AC和Battery的状态改变,重新通知OSPM来获取C状态。
一.D状态
D状态是描述设备电源状态。OSPM使用它来管理系统,以期达到性能和能耗的折中状态。
D0:Active状态,系统为其供电。此状态下,用户可以使用其提供功能。
D3:设备关闭状态。在此状态下,电源完全被移除。系统重新为其供电时,要再次初始化。
为了提供给OSPM设备的D状态,我们要在相应的设备下面添加_PS0和_PS3的支持。OSPM调用_PS0和_PS3时,我们的设备电源相关寄存器就会被改写。
二.系统待机流程
在WINDOWS下,执行待机操作。操作系统,SBIOS,ECBIOS依次跑自己的代码。
1,关机程序取得SE_SHUTDOWN_NAME权限,然后调用时SetSystemPowerState函数。
2,检查各个设备的唤醒功能(_PRW)和其POWER RESOURCE。
3,设置设备的D状态,如果其没有WAKE功能,则将其于D3状态
4,OSPM执行_PTS来调用BIOS对平台的设定。
5,OS将Wake function的Wake vector填写入FACS表中,待系统从S3返回时调用。
6,根据步骤2设置唤醒功能,在GPE0_EN或PM1_EVT里置相应位。
7, OSPM在FADT中,找到PM1a_CNT_BLK,根据DSDT中的 Name(_S3, Package(4) {0x05, Zero,Zero, Zero}),将(0x05<<10)|(1<<13)写入PM1a_CNT_BLK中。
8,上述步骤触发S3SLEEP SMI中断,CPU进入SMM模式,并执行S3 SMI HANDLE,最后将 PM1a_CNT_BLK的值最低位变1,再次写入此寄存器。
9,EC检测到南桥的S3#有效,便把主板上的电逐一拉低,只保留内存电压。
三.系统关机流程
在WINDOWS下,用户执行软关机。操作系统,SBIOS,ECBIOS依次跑自己的代码。
1,取得SE_SHUTDOWN_NAME权限,然后调用时ExitWindowsEx函数。
2,关机指令通知Windows子系统CSRSS.EXE,CSRSS.EXE,收到通知后会和Winlogon.EXE做一个数据交换,再由Winlogon.EXE通知CSRSS.EXE开始关闭系统的流程。
3,Winlogon.EXE调用NtShutdownSystem()函数来最后关机。
4,OSPM执行_PTS来调用BIOS对平台的设定。
5,OSPM在FADT中,找到PM1a_CNT_BLK,将DSDT中的 Name(_S5, Package(4) {0x07, Zero,Zero, Zero}),将(0x07<<10)|(1<<13)写入PM1a_CNT_BLK中。
6,步骤5触发了S5 SMI中断,CPU跳转到SMBASE+0x8000处。此处是SMI HANDLE的入口函数,该函数会逐一检查SMI中断类型,最后确定为SLP_SMI_STS。然后BIOS FIRMWARE通过读取 PM1a_CNT_BLK中的值判定SLP_STYLE为S5。BIOSFIRMWARE根据注册的S5 SLEEP HANDLE逐一执行完毕。最后将PM1a_CNT_BLK的值最低位变1,再次写入此寄存器。
7,此时,南桥S3#,S4#,S5#会依次变低。EC接到信号后,将主板上的信号依次拉低。