Fehlerhafte ACPI Tabellen für Tagesalarm korrigieren

Geschrieben von Andreas am 15. Oktober 2022

Um meinen TV-PC mal wieder etwas zu erneuern habe ich ein gebrauchtes GA-N3160TN Mainboard erstanden. Das ist zwar schon etwas älter aber durch den Celeron N3160 sehr stromsparend und ausreichend leistungsstark. (Mainboard, RAM und SSD brauchen im Betrieb weniger Strom als eine Fritzbox, deren Netzteil passt hervorrangend als Stromversorgung)

Leider schaffen es auch höherwertige Hersteller anscheinend nicht mehr ein vernünftig angepasstes BIOS für Ihre Mainboards zu erstellen, so meldet der Linux Kernel dann auch beim Boot, das die RTC nur 24-Stunden Alarme kann:

$ dmesg | grep rtc_cmos
[    1.063278] rtc_cmos 00:00: RTC can wake from S4
[    1.063870] rtc_cmos 00:00: registered as rtc0
[    1.064262] rtc_cmos 00:00: setting system clock to 2022-10-09T14:46:21 UTC (1665326781)
[    1.064325] rtc_cmos 00:00: alarms up to one day, y3k, 242 bytes nvram

Für einen TV-PC ist das suboptimal. Eigentlich können alle Intel Chipsätze mit integrierter RTC auch sogenannte Tagesalarme, also Aufwachen bis 30 Tage in die Zukunft. Da der Linux Kernel die Information zu den Fähigkeiten der RTC aus der FADT ACPI Tabelle holt, kann man das Problem durch Patchen dieser Tabelle lösen.

FADT Patchen

Zunächst einmal werden die dafür notendigen Tools installiert:

$ apt install acpica-tools

Der nächste Schritt ist es dann die ACPI tabellen auszulesen und zu dekompilieren:

$ mkdir acpi
$ cd acpi
$ acpidump >acpidump
$ acpixtract -a acpidump

Intel ACPI Component Architecture
ACPI Binary Table Extraction Utility version 20200925
Copyright (c) 2000 - 2020 Intel Corporation

  MCFG -      60 bytes written (0x0000003C) - mcfg.dat
  APIC -     132 bytes written (0x00000084) - apic.dat
  SSDT -     656 bytes written (0x00000290) - ssdt1.dat
  UEFI -      66 bytes written (0x00000042) - uefi.dat
  DSDT -   53903 bytes written (0x0000D28F) - dsdt.dat
  LPIT -     260 bytes written (0x00000104) - lpit.dat
  SSDT -     378 bytes written (0x0000017A) - ssdt2.dat
  FACP -     268 bytes written (0x0000010C) - facp.dat
  FPDT -      68 bytes written (0x00000044) - fpdt.dat
  SSDT -    1891 bytes written (0x00000763) - ssdt3.dat
  CSRT -     332 bytes written (0x0000014C) - csrt.dat
  FIDT -     156 bytes written (0x0000009C) - fidt.dat
  FACS -      64 bytes written (0x00000040) - facs.dat
  SSDT -    1621 bytes written (0x00000655) - ssdt4.dat
  SSDT -     141 bytes written (0x0000008D) - ssdt5.dat
  SSDT -     933 bytes written (0x000003A5) - ssdt6.dat
  SSDT -     351 bytes written (0x0000015F) - ssdt7.dat
$ iasl -d *.dat

Die ACPI Tabellen können nun mit einem einfachen Editor bearbeitet werden. Die RTC Eigenschaften werden in der FADT bzw FACP Tabelle beschrieben. Es müssen zwei Felder in der Tabelle angepasst werden:

  • Die Oem Revision der Tabelle muss erhöht werden und

  • das RTC Day Alarm Index Feld muss auf den Wert „0D“ geändert werden

facp.dsl
/*
 * Intel ACPI Component Architecture
 * AML/ASL+ Disassembler version 20200925 (64-bit version)
 * Copyright (c) 2000 - 2020 Intel Corporation
 *
 * Disassembly of facp.dat, Sat Oct 15 13:59:47 2022
 *
 * ACPI Data Table [FACP]
 *
 * Format: [HexOffset DecimalOffset ByteLength]  FieldName : FieldValue
 */

[000h 0000   4]                    Signature : "FACP"    [Fixed ACPI Description Table (FADT)]
[004h 0004   4]                 Table Length : 0000010C
[008h 0008   1]                     Revision : 05
[009h 0009   1]                     Checksum : 39
[00Ah 0010   6]                       Oem ID : "ALASKA"
[010h 0016   8]                 Oem Table ID : "A M I "
[018h 0024   4]                 Oem Revision : 0107200A
...
[06Ah 0106   1]          RTC Day Alarm Index : 0D
...

Das kann man mit einem beliebigen Editor erledigen. Danach wird die FACP wieder compiliert:

$ iasl -sa facp.dsl

Intel ACPI Component Architecture
ASL+ Optimizing Compiler/Disassembler version 20200925
Copyright (c) 2000 - 2020 Intel Corporation

Table Input:   facp.dsl -   10104 bytes    148 fields      178 source lines
Binary Output: facp.aml -     268 bytes

Compilation successful. 0 Errors, 0 Warnings, 0 Remarks

Kernel neue Tabelle unterschieben

Im zweiten Schritt wird dem Kernel die neue Tabelle untergeschoben, d.h. der Kernel soll statt der originalen die neue gepatchte Tabelle verwenden. Das ist relativ einfach möglich, wenn man initrds zum booten benutzt. Es wird dazu einfach eine weitere initrd vor die „normale“ initrd gepackt.

Entsprechend der Kernel Dokumentation 1 wird diese zunächst wie folgt erstellt:

$ mkdir -p kernel/firmware/acpi
$ cp facp.dsl kernel/firmware/acpi/
$ find kernel | cpio -H newc --create >/boot/initrd.img-acpi

Danach hab ich ein hook-Script für die initramfs-tools erstellt, welches automatisch die gepatchte initrd voranstellt:

/etc/initramfs-tools/hooks/patch-acpi
#!/bin/sh
PREREQ=""
prereqs()
{
     echo "$PREREQ"
}

case $1 in
prereqs)
     prereqs
     exit 0
     ;;
esac

. /usr/share/initramfs-tools/hook-functions

prepend_earlyinitramfs /boot/initrd.img-acpi

Diese Datei muss dann noch als ausführbar markiert werden und dann kann die initrd neu erstellt werden:

$ chmod +x /etc/initramfs-tools/hooks/patch-acpi
$ update-initramfs -c -k all

Danach muss neu gebootet werden und die RTC sollte nun auch Tagesalarme unterstützen:

$ dmesg | grep rtc_cmos
[    1.042898] rtc_cmos 00:00: RTC can wake from S4
[    1.044270] rtc_cmos 00:00: registered as rtc0
[    1.044710] rtc_cmos 00:00: setting system clock to 2022-10-15T12:34:06 UTC (1665837246)
[    1.044868] rtc_cmos 00:00: alarms up to one month, y3k, 242 bytes nvram

Links

1

https://docs.kernel.org/admin-guide/acpi/initrd_table_override.html