我手上这台ThinkPad X200,宝刀不老,长期以来一直都是我写程序写论文的主力。不过,前主人给它设置了超级管理员密码,由于相隔已久,早已忘了密码。幸好超级密码只锁定BIOS设置,不影响进系统,倒也相安无事。
然而,有密码始终影响我对笔记本的掌控。我尝试像台式机那样,拔掉BIOS电池来清除密码。殊不知,X200是商务笔记本系列,联想早已经做足了防范。结果很惨:每次开机都得输入管理员密码!
最终,我决定,刷coreboot,一劳永逸解决。coreboot是一款自由、开源的系统固件,是BIOS和UEFI的替代。它早已对ThinkPad X200提供完备的支持。何不用它,绕过密码验证,直接引导系统?
准备工具
BIOS刷写需要准备以下工具:
- 一台安装了Linux发行版的电脑
- CH341A土豪金编程器
- SOP-16夹具
既然电脑无法进系统,想要刷BIOS,当然离不开编程器了。我选用的是著名的CH341A土豪金编程器,接下来用到的刷写工具Flashrom为它提供了官方支持。
X200的BIOS芯片是25型,拥有16根引脚,可以直接通过SOP-16夹具来连接编程器。夹具和编程器都可在淘宝购买到。
系统环境方面,选用Linux发行版。通过它来运行Flashrom来刷写BIOS,以及编译coreboot。
值得注意的是,coreboot只提供源代码,不提供已经编译的固件,所以需要自己编译。你也许可以选用网上别人编译好的固件,但它们常常缺少正确的配置,导致功能缺失(例如,无线网卡和蓝牙不能使用)。
编程器连接
编程器的卖家通常会提供完备的资料。由于CH341A编程器可能有不同的外观,配件也可能有不同的组装方式,故应当以资料为准。这里省略。
备份原机BIOS
连接编程器后,首先需要备份原机BIOS ROM。一方面是防止万一,另一方面是coreboot需要使用官方BIOS的组件。
(1) 检测芯片型号
首先运行以下命令,尝试读取BIOS芯片,检测型号,借此检查连接情况:
1 |
|
若一切正常,执行结果如下。可以看到,编程器已经识别出了芯片:
1 |
|
输出日志中,不止一个型号被检测出来。后续的操作,我们使用最长串的型号:MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E/MX25L6473F
。
提示: 检测出多型号是正常现象,因为BIOS芯片本身有多种型号定义,仅通过编程器是无法精确识别。
(2) 开始备份
运行以下命令,将整个BIOS ROM备份到文件x200_bios.rom
中:
1 |
|
正常情况下,输出结果如下所示:
1 |
|
由于传输过程可能存在异常,为保险期间,多备份几次,然后比较各个备份文件(例如,SHA256校验和)。如果完全相同,则说明备份无误。
例如,先备份,然后使用OpenSSL来比较SHA256:
1 |
|
如果传输无误,则上述文件的SHA256值应当相同,如下:
1 |
|
准备coreboot源代码
接下来的教程中,假定我们把coreboot的源码目录放在用户主目录下。
(1) 克隆源码
首先,克隆coreboot的代码库:
1 |
|
如果不小心漏掉了--recursive
参数,则同步子模块:
1 |
|
(2) 准备交叉编译器
coreboot涉及到更底层的系统环境。为了保证coreboot的正常编译,还需要准备交叉编译器。例如,Intel x86_64平台中,一律使用i386的GCC编译器。
首先,安装GCC Ada工具链。
coreboot包含一个显卡驱动:libgfxinit,它可以在Intel平台下初始化集成显卡或核芯显卡,使用Ada语言的子集SPARK编写。要给交叉编译器提供Ada语言的支持,必须先在当前主机上安装GCC Ada工具链。
不同的发行版有不同的包名。在Arch Linux中,使用以下命令安装:
1 |
|
接下来,就可以让coreboot自动构建交叉编译器,只需运行以下命令:
1 |
|
构建过程是全自动的,一步到位。
准备BIOS组件
coreboot需要从原机的官方BIOS ROM中提取以下三个组件:
- Flash descriptor,存放闪存芯片的布局信息
- ME Firmware,即Intel Management Engine的固件
- GbE,有线网卡的配置文件
上述组件可以直接使用coreboot提供的ifdtool
来自动提取。
(1) 编译ifdtool
进入coreboot源码目录,然后浏览到ifdtool
的源码目录,并编译:
1 |
|
编译完成后,当前目录会多出可执行文件ifdtool
。为了方便,可以把它安装到系统中:
1 |
|
(2) 提取组件
浏览到存放BIOS备份的目录,运行以下命令提取:
1 |
|
执行结果如下所示:
1 |
|
此时,当前目录下就会多出几个文件。它们都是提取出的组件,属于BIOS ROM的组成部分。
- flashregion_0_flashdescriptor.bin
- flashregion_1_bios.bin
- flashregion_2_intel_me.bin
- flashregion_3_gbe.bin
- flashregion_4_platform_data.bin
(3) 把组件放入coreboot源码目录中
接下来,我们把提取出的组件放入指定目录中,使coreboot可以识别。
首先,进入coreboot源码目录,然后建立下面的子目录:
1 |
|
然后,把提取出的以下三个组件改名,放入上述目录中:
原名 | 更改的名字 |
---|---|
flashregion_0_flashdescriptor.bin |
descriptor.bin |
flashregion_2_intel_me.bin |
me.bin |
flashregion_3_gbe.bin |
gbe.bin |
至此,BIOS组件准备完成,可以开始后续的配置了。
配置coreboot
coreboot使用KBuild来配置,编译过Linux内核的开发者应该不会陌生。接下来,我们将配置coreboot,打造出功能完备的体验,不应满足于点亮机器进系统。
基本操作
- 上下移动光标:选择设置项
- Enter:
- 进入子菜单或多选一菜单
- 确认当前选项
- Y/N/空格:勾选(或取消勾选),适用于带有方括号的项目,方括号里出现星号,表示已选中
- 连按两次ESC:返回上一页
(1) 进入配置菜单
进入coreboot源码目录,然后打开配置菜单:
1 |
|
(2) 设置主板类型
首先,要将coreboot的主板类型设置为ThinkPad X200。
进入一级菜单 【Mainboard(主板)】,然后选择 【Mainboard vendor(主板厂商)】,按Enter进入。在列表中,光标定位到
Lenovo
,按空格选中。然后,选择 【Mainboard model(主板型号)】,同样按Enter进入,在列表中,光标定位到
ThinkPad X201 / X201i / X201s / X201t
,按空格选中。
选好后,按两次ESC,退回主页面。接下来的步骤都从主页面开始。
(3) 设置BIOS组件
进入一级菜单 【Chipset(芯片组)】,然后勾选 【Add Intel descriptor.bin file(添加英特尔descriptor.bin 文件)】。
此时,列表下方会多出下面两个选项。依次勾选它们:
- 【Add Intel ME/TXE firmware(添加英特尔ME/TXE固件)】
- 【Add gigabit ethernet configuration(添加千兆以太网配置数据)】
其余选项保持默认值。固件的路径默认均指向3rdparty/blobs/mainboard/lenovo/x200
这一目录的相应文件,无需修改。
(4) 启用无线网卡支持
一些型号的Intel PCIe无线网卡,如果在ACPI和SMBIOS中缺少数据,则操作系统将无法识别它们。为了保证笔记本上安装的Intel网卡可用,需要在coreboot中提供对它们的支持。
进入一级菜单 【Generic drivers(通用驱动)】 ,勾选最后一项 【Support Intel PCI-e WiFi adapters(英特尔PCIe无线网卡支持)】,即可。
(5) 启用二合一网卡蓝牙支持
有别于笔记本常见的二合一无线网卡,X200采用独立的博通蓝牙适配器,走的是USB通道。但部分用户可能更换了二合一网卡。要想让这类网卡的蓝牙工作,需要开启coreboot的相关支持选项。
进入一级菜单 【Chipset】,选择 【Support bluetooth on wifi cards(为搭载于无线网卡上的蓝牙提供支持)】,按Y勾选即可。
(6) 启用NVRAM存储
coreboot可以把BIOS的参数保存在NVRAM中,这些参数控制着笔记本的各种特性,比如显存大小、无线网卡开关、告警提示音开关等。
但是,coreboot默认并没有开启参数保存的功能,这将导致所有参数在每次开机时还原为默认。并且,还会导致蓝牙指示灯无法点亮。
因此,我们需要手工打开它。具体步骤如下:
进入一级菜单 【General setup(一般配置)】,然后选中 【Option backend to use(要使用的配置项存储后端)】。
回车,然后在列表中,光标定位到 【Use CMOS for configuration values(用CMOS来保存设置值)】,按空格选中,搞定。
(7) 启用显卡支持:libgfxinit与Linear Frame buffer
coreboot首选的显卡支持方案是VGA Option ROM,即VGA BIOS镜像。用户需要获取当前显卡的VGA BIOS,编译时将它集成在coreboot中,每次开机即可利用它来初始化显卡。
如果系统能正常启动,我可以直接在Linux中获取VGA Option ROM。然而,现在X200无法进入系统,再买一台X200也不现实,因此根本没办法获取。
所幸,我还可以使用libgfxinit,这个库可以用来初始化Intel平台的核显与集显,驱动X200的GM45集显不在话下。在它的基础上,再启用Linear Framebuffer功能——建立一个帧缓冲(frame buffer),允许程序直接在coreboot中调用显卡绘图,从而使显卡在系统引导阶段发挥应有效能。
具体步骤如下:
进入一级菜单 【Devices(设备)】,选择【Graphics initialization(图形初始化)】。在选项列表中,光标定位到 【Use libgfxinit(使用libgfxinit)】,按空格确认。
然后,依次进入子菜单 【Display(显示)】➡️ 【Framebuffer mode(帧缓冲模式)】。在选项列表中,光标定位到 【Linear “high-resolution” framebuffer(线性高分辨率帧缓冲)】。
之后,在【Framebuffer mode】子菜单中,会多出以下两个选项,指定为X200显示器的最佳分辨率即可:
【Maximum width in pixels(最大像素宽度)】,指定为
1280
【Maximum height in pixels(最大像素高度)】,指定为
800
至此,显卡支持设置完成。
编译coreboot
配置完成后,就可以立刻着手编译:
1 |
|
**最终编译好的coreboot ROM位于build
子目录,文件名为coreboot.rom
**。
刷入coreboot并开机测试
连接编程器,运行以下命令,将coreboot刷入BIOS芯片中:
1 |
|
若一切正常,输出结果将如下所示:
1 |
|
刷好之后,松开夹具,断开编程器,扣上电池,开机!
上电后,coreboot将初始化硬件,随后启动SeaBIOS——一款开源的BIOS实现。SeaBIOS再引导硬盘上的操作系统。
在X200中,屏幕上出现SeaBIOS的版本号,以及本机的UUID。不一会,本地硬盘上的Grub也成功引导,出现了“Welcome to Grub!”的一样,随后熟悉的Grub菜单出现在眼前。
启动成功!
内部刷写
刷好coreboot之后,尽管放心上好X200的盖子。后续的BIOS更新,无需再使用编程器,仅使用Flashrom就可以完成。
(1) 卸载lpc_ich
驱动
通常,获取BIOS芯片状态的命令是flashrom -p internal
。但一般情况下,在Arch Linux中运行时,会报错:
1 |
|
网上的刷写教程,甚至是coreboot的官方文档,都是不会告诉你这个问题的。
所幸,Flashrom的官方文档提供了对策。只需卸载系统的lpc_ich
驱动,即可释放对BIOS芯片的访问权限。运行以下命令:
1 |
|
(2) 备份与刷写
卸载上述驱动后,直接运行Flashrom刷写即可。你既可以备份整颗芯片,也可以只备份BIOS区域而保持ME、GbE等其他部分不变。
例如,刷写刚刚编译好的coreboot:
1 |
|
以及,备份当前版本的BIOS:
1 |
|
后续问题:Grub的显示
我在测试coreboot的时候,启动过程中,会卡在“Welcome to Grub!”字样。但没过多久,Grub仍能正常引导Linux。
Grub默认会以图形方式显示菜单,这要求显卡必须初始化图形功能——有别于传统的VGA文字模式。
然而,我的X200只能用libgfxinit初始化。如果不启用Linear Framebuffer,则默认只能使用文字模式,而Grub无法对此作出自适应的处理,所以菜单无法显示。
对此,有两种解决方案:
方案一:将Grub切换到文字模式
进入Linux后,修改/etc/default/grub
,取消注释下面这行:
1 |
|
如果是新版本的GRUB,则取消注释这一行:
1 |
|
重新生成Grub配置文件:
1 |
|
重启后,Grub就会以简易的文字来绘制界面,可以顺利使用了。
方案二:启用Linear Framebuffer
使用Linear Framebuffer,就可以保证Grub的图形菜单能正常显示。
但是,Linear Framebuffer不支持缩放,只能点对点显示,这意味着如果输入分辨率小于Linear Framebuffer指定的分辨率,画面就只能靠左上角显示。
并且,Grub也无法获取Linear Framebuffer的最佳分辨率,它一律会用640x480的最低分辨率输出。最终的显示效果很“憋屈”。
所以,我们还需要设置Grub的输出分辨率。打开修改/etc/default/grub
,修改参数GRUB_GFXMODE
:
1 |
|
X200的最佳分辨率是1280x800,32位色深。后面的x32
可以省略。
修改后,更新Grub配置文件,重启生效,此时Grub能全屏显示了。
参考资料
- Installing coreboot on the Thinkpad X200, X201 and on the ASUS P5Q(如何正确使用Flashrom刷写X200的BIOS)
- coreboot: Board:lenovo/x200(coreboot官方关于X200的文档,其中提到如何正确设置充电阈值)
- How can I do about /dev/men errors?(如何正确使用Flashrom进行内部刷写,解决
/dev/map error
的问题) - 这几天在一台ThinkPad X201上刷进了Coreboot (帖主提到使用PhonenixTool来提取VGA BIOS。并且强调,有了
NATIVE_GRAPHICS_INIT
,也就是libgfxinit提供的支持,就不需要VGA BIOS了。实践证明果然如此)
- 本文作者: 爱拼安小匠
- 本文链接: https://anclark.github.io/2022/10/19/coreboot/x200-coreboot/
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0(署名-非商用-禁止演绎 3.0) 许可协议。转载请注明出处!