由于我的笔记本(Y450)太老,开虚拟机进行代码编译慢的要死。因此前些天淘了一台二手DELL C1100刀片式服务器,搁在家里作为编译服务器用。我配了两条4G ECC内存,一颗L5640志强6核心处理器,再加上两个500G硬盘组成硬RAID,总共2000来块,还算便宜。硬件方面绝对比虚拟机什么的强多了。在系统上,我选择了比较新的ubuntu server14.04 作为服务器系统(Centos/Redhat等也许更合适做服务器,但ubuntu貌似用起来更顺手)。
软硬件环境搭建好后,我尝试编译了一下Exynos4412的uboot和内核,make clean后uboot编译花了不到5秒钟,内核编译花了1分钟多一点。这个速度比虚拟机快一个数量级,爽!
但最让我头疼的是噪音问题,服务器全速运行噪音像飞机引擎声,因为1U服务器空间狭小,必须使用小口径暴力风扇吹。不过经过我的精心改造,声音已经小到比普通台式机大一点点的程度,完全不影响正常生活学习。
好了不扯这些了,我们赶紧切入正题。由于服务器的功耗相对较高,实测空闲70W左右, 满载130W左右。而白天家里基本没人,让它跑着白白浪费电力,不划算,但关机又嫌启动慢,因此我想到普通笔记本和台式机必备的功能:待机!待机功耗非常低,而且唤醒速度也非常快,通常几秒就可以将服务器唤醒。但是悲催的事情来了,无论我怎么弄,无论安装什么电源管理工具,都无法让设备进入S3状态,只能进入S2状态。查看机器支持的电源模式:
~$ sudo cat /sys/power/state
freeze standby disk
只有freeze stanby和disk三项,没有进入S3状态的mem,于是我想到是不是ACPI管理除了什么问题或者服务器硬件根本就不支持。我尝试修改了内核源码,让服务器强制执行进入S3状态的代码,输入:
~$ sudo echo ‘mem’ > /sys/power/state
后,系统进入了S3状态,但无法唤醒,肯定哪里还有问题。不过到这里我已经坚信硬件是支持S3待机的,只是可能BIOS里ACPI配置可能出了问题。
这里先科普一下,ACPI是高级配置与电源接口, 它里面定义了6种电源模式,即S0~S5其中:
S0 正常工作状态,功耗最高。
S1 称为POS(power on suspend),这时仅CPU时钟关闭,到达S0状态接近0秒
S2 比S1更进一步,系统总线时钟也被关闭,但主板不会掉电,到达S0状态 < 0.1秒
S3 称为STR(suspend to RAM), 即我们常说的待机(睡眠),这时除了内存供电外其他设备全部下电(WOL网卡除外),功耗很低, 到达S0状态 < 4秒
S4 称为STD(suspend to disk), 即我们常说的休眠,这时将RAM数据保存到硬盘,然后包括内存在内的全部设备下电(WOL网卡除外),功耗与S5相同, 到达S0状态
< 60秒,看硬盘速度
S5 即关机,功耗几乎为0
从ACPI的工作模式来看,很显然空闲时让服务器进入S3是最佳选择,无论从功耗还是从唤醒时间考虑。
了解ACPI的人都知道,ACPI的功能主要在操作系统级别实现,BIOS的ACPI模块会给操作系统内核提供一系列ACPI配置表项,其中一个比较重要的表是DSDT表,它主要描述各个主板硬件差异的一个配置表,或者说某种驱动代码。网上有很多帖子介绍修改DSDT支持黑苹果的帖子,我也从中受到了一些启发,于是希望也能通过修改DSDT来达到支持S3待机的目的。
经过一个晚上的研究,终于成功的在DELL C1100上实现了S3待机功能。为了避免修改BIOS带来的风险和操作难度的提升,这里只介绍使用linux内核重载DSDT表功能来实现S3待机。该方法需要重新编译linux内核和制作initrd,而本文不详细介绍。另外,这里申明一下,我服务器上的BIOS版本是S99C3B22.ROM, 而最新版本是S99C3B23.ROM,没有验证是否已经解决了这个问题。
0. 申明
本文内容和教程仅供学习交流使用,不得用于商业用途。
1. 准备工作:
① 下载linux内核源码,使用最新稳定版或者机器自带的内核版本都行。
② 在服务器安装acpidump工具和dstd编译工具
~$ sudo apt-get install acpidump
~$ sudo apt-get install iasl
2. 获取dsdt.dat文件
方法一:
~$ cp /proc/acpi/dsdt DSDT
~$ acpixtract DSDT acpidump > dstd.dat
方法二:
~$ sudo acpidump -b > acpi.aml
会在当前目录下生成dstd.dat
3. 反编译dsdt.dat
~$ iasl -d dstd.dat
在当前目录生成dsdt.dsl源码文件
4. 修改电源部分代码
~$ vi dstd.dsl
① 在7289行左右,删除 If (SS1) If(SS3) 和 If(SS4)这几个判断语句,让下面语句直接生效:
Name (_S1, Package (0x04) // _S1_: S1 System State
Name (_3S, Package (0x04)
Name (_S4, Package (0x04) // _S4_: S4 System Stat
② 也是最重要的修改
修改Name (_3S, Package (0x04)为Name (_S3, Package (0x04)
补充一下:我不知道DELL公司的程序员是笔误犯傻还是故意为之,Linux内核代码里会解析DSTD中的内容,如果找不到_S3,肯定就不支持S34待机啦。
下面是修改范例:
图1 修改前的代码
图2 修改后的代码
5. 编译dsdt.dsl生成dstd.hex
~$ iasl -tc dsdt.dsl
在当前目录生成dstd.hex文件
6. 重新编译linux内核,嵌入dsdt.hex
① 解压内核到路径,这里用SRC表示;
② ~$ cp dsdt.hex SRC/include/
③ ~$ make menuconfig 或 直接修改.config文件
CONFIG_STANDALONE=n
CONFIG_ACPI_CUSTOM_DSDT=y
CONFIG_ACPI_CUSTOM_DSDT_FILE="dsdt.hex"
④ ~$ make 编译内核生成内核映像
这里有个技巧,可以把内核的CONFIG_DEBUG选项关闭,这样编译出来的内核和驱动模块体积较小,initrd也会相应缩小10倍体积左右。
7. 使用mkinitrd工具制作initrd启动盘,更新grub
这时候如果系统能够引导启动,则/sys/power/state 下应该已经出现mem,则说明系统已经支持S3待机状态
8. 安装电源管理工具pm-utils
这一步也比较重要,我尝试了一下ubuntu上使用这个工具比较好用。
~$ sudo apt-get install pm-utils
9. 运行pm-utils进入待机
在本地终端上执行:
~$ sudo pm-suspend
即可进入S3待机状态,按电源键或者WOL可以唤醒, 如果在远程终端上(SSH),则必须将pm-suspend放到后台执行
~$ sudo pm-suspend &
因为 pm-suspend 在机器唤醒后还会执行唤醒部分的操作,如果是远程登录,一旦进入S3 状态,网络就会断开,等到唤醒时,pm-suspend会由于会话期结束而退出,没有执行设备 唤醒操作,最终导致无法唤醒的问题。
10. 参考文献
https://01.org/zh/linux-acpi/documentation/overriding-dsdt?langredirect=1 关于linux内核对DSTD重载的使用说明
http://bbs.pcbeta.com/viewthread-1133482-1-1.html acpidump的使用介绍
内核Documents/下的相关文档
好了,方法都介绍完毕了,该到了show一下服务器的时候了,拍的技术不咋的,见笑了,哈哈!