HEST上报开发小结

HEST上报开发小结

2024-01-12
bios

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,流程如下:
    1. 新增一条GHES,并将此GHES插入到HEST中。保存GHES中申请的地址基址。
      1. 要求此GHES的Notify Type为Polled。使用Polled后OS会定期去轮询。
    2. 创建CPER,将存在Error的物理地址写入到CPER中。
    3. 将CPER插入到GHES指向的物理地址中。(此步骤比较难,需要同步修改Generic Error Status Block和Generic Error Data Entry)。
  • 整个流程用到的数据结构的关系如下:

2. Linux串口配置 #

  • 开启Linux串口可以收集OS的日志,也可以解决OS下BIOS日志显示不全的问题

  • 开启步骤如下:

  1. 编译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"
  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内核流程如下:
  1. 在Github下载最新的Linux内核代码(下载最新的即可,老版本内核代码可能缺少后续更新的某些patch):
  1. 将内核代码传到Linux服务器上,并进行解压。
  2. 将/boot路径下的config-xxx文件拷贝到内核代码的路径,并重命名为.config。cp /boot/config-4.18.0-193.el8.x86_64 .config
  3. 进入Linux内核目录,执行make menuconfig,之后找找有没有自己感兴趣的配置,把它选上后,保存退出。
  4. 开始编译Linux内核,执行make -j128,其中-j表示并行编译,可以加快编译速度,可以根据自己CPU的核心数来调整该值的大小。
    1. 如果出现报错,是因为缺少某些库,可以自己按照报错去搜一下需要安装的软件或者需要注释掉的选项。
  5. 当编译完成后,执行make modules_install来安装内核模块。
  6. 执行make install安装Linux内核。
  7. 更新grub配置,让其重新扫描内核,并从新的Linux内核启动grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
  8. 如果以上步骤执行完后,重新启动可以看到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。