HEST上报开发小结
2024-01-12
1. HEST表、GHES、CPER #
- APEI(ACPI Platform Error Interfaces):提供了一种将错误信息传递给OS的机制。
- APEI包含了四张ACPI表:
- ERST(Error Record Serialization Table)
- BERT(Boot Error Record Table)
- HEST(Hardware Error Source Table)
- EINJ (Error Injection Table)
- HEST用来将系统硬件错误传递给OSPM,HEST表的结构如下:
-
- GHES(Generic Hardware Error Source)通用硬件错误源,GHES是Error Source Structure的一种。除了GHES外,还有其他的一些错误源(IA-32 Architecture Machine Check Exception、PCI Express Root Port AER、PCI Express Device AER Structure)。
- GHES的结构如下图,其中比较重要的字段为Error Status Address和Notify。
- Error Status Address是一个地址,指向了一块大小固定的地址空间,该空间存放上报给OS的错误信息,结构如下图所示。
- Notify表示当错误发生时如何上报给OS。(支持的方式包括SCI、Polled等)
-
- CPER(Common Platform Error Record):上图中的Error Section可以用来存放CPER(详见UEFI_SPEC的 N)。CPER的结构如下图:
-
- 可以通过如下流程,将硬件错误上报给OS,流程如下:
- 新增一条GHES,并将此GHES插入到HEST中。保存GHES中申请的地址基址。
- 要求此GHES的Notify Type为Polled。使用Polled后OS会定期去轮询。
- 创建CPER,将存在Error的物理地址写入到CPER中。
- 将CPER插入到GHES指向的物理地址中。(此步骤比较难,需要同步修改Generic Error Status Block和Generic Error Data Entry)。
- 新增一条GHES,并将此GHES插入到HEST中。保存GHES中申请的地址基址。
- 整个流程用到的数据结构的关系如下:
-
2. Linux串口配置 #
-
开启Linux串口可以收集OS的日志,也可以解决OS下BIOS日志显示不全的问题
-
开启步骤如下:
- 编译grub配置文件,在文件末尾添加如下的配置
vim /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,115200n8"
GRUB_TERMINAL=serial
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"
- 执行如下命令生成grub配置文件。
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
3. 编译Linux内核 #
- 在使用CPER上报OS的过程中,发现dmesg一直报错
GHES:Failed to read error status block!
,后续重新编译Linux内核,才定位到错误。 - 编译Linux内核流程如下:
- 在Github下载最新的Linux内核代码(下载最新的即可,老版本内核代码可能缺少后续更新的某些patch):
- 将内核代码传到Linux服务器上,并进行解压。
- 将/boot路径下的config-xxx文件拷贝到内核代码的路径,并重命名为.config。
cp /boot/config-4.18.0-193.el8.x86_64 .config
- 进入Linux内核目录,执行
make menuconfig
,之后找找有没有自己感兴趣的配置,把它选上后,保存退出。 - 开始编译Linux内核,执行
make -j128
,其中-j表示并行编译,可以加快编译速度,可以根据自己CPU的核心数来调整该值的大小。- 如果出现报错,是因为缺少某些库,可以自己按照报错去搜一下需要安装的软件或者需要注释掉的选项。
- 当编译完成后,执行
make modules_install
来安装内核模块。 - 执行
make install
安装Linux内核。 - 更新grub配置,让其重新扫描内核,并从新的Linux内核启动
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
- 如果以上步骤执行完后,重新启动可以看到grub中新增加了一个刚编译的内核的启动项。
- 内核中使用printk来添加打印信息,使用方式如下:
//KERN_ERR是打印级别
printk(KERN_ERR "%s: kpf acpi_hest_get_size(gdata) = 0x%x, data_len = 0x%x\n", __func__, acpi_hest_get_size(gdata), data_len);
- 重新编译并安装内核后,使用
dmesg -w
即可看到添加的打印信息。
4. 内存 #
- DIMM(Double In-line Memory Module)双列内存模组,双列指的是电路板两侧有两列金手指。
- SDRAM(Synchronous Dynamic Random Access Memory):同步动态随机存储器。同步指的是其时钟频率与CPU前端总线的系统时钟频率相同;动态指的是存储阵列需要不断的刷新来保证数据不丢失;随机指的是可以自由指定地址进行数据的读写。
- RANK:也叫P-Bank(Physical Bank),P-Bank是一组内存芯片的集合,这个集合的总位宽必须要和CPU的数据位宽相同。
- 每个内存芯片都有自己的位宽((SDRAM)存储单元容量=位宽,(DDR)存储单元容量=2×位宽),位宽就是每个传输周期提供的数据量。一般一个内存芯片的位宽为8Bit。
- 只有知道芯片位宽的情况下,才能确定P-BANK的数量。
- BANK:内存可以看作是一个表格,指定一个行(Row)和一个列(Column)后,就可以找到所需要的单元格了,这个单元格可以称为
存储单元
(一个存储单元可以存nbit的数据(n取决于位宽)),这个表格就叫L-BANK(逻辑Bank,也叫BANK)。- 一个BANK一般会包含多个表格。所以在进行寻址时,需要先确定是哪个BANK,然后在这个选定的L-BANK中选择相应的行和列进行寻址。
- 内存芯片的容量(存储单元的容量) = 行数 x 列数 x L-BANK的数量。
- DDR SDRAM(Double Data Rate SDRAM):双倍数据流SDRAM。