From bc09c2d865315e8f0ffdb20b31cd420faec16b5d Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Mon, 7 Nov 2022 23:31:30 -0600 Subject: [PATCH] acpi-fpdt: Use kernel fpdt parsing On some kernels/distros (RHEL/aarch64) /dev/mem is turned off. This means that the ACPI FPDT data is missing from systemd-analyze output when /dev/mem fails to provide the boot times. Instead recent kernels can export that data from /sys/firmware/acpi/fpdt/boot/ entries. Use that information if available first. Signed-off-by: Jeremy Linton --- TODO | 4 ++++ src/shared/acpi-fpdt.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/TODO b/TODO index 0b9f4da7f08..9c30bfb30d8 100644 --- a/TODO +++ b/TODO @@ -115,6 +115,10 @@ Deprecations and removals: * H2 2023: remove support for unmerged-usr +* Remove /dev/mem ACPI FPDT parsing when /sys/firmware/acpi/fpdt is ubiquitous. + That requires distros to enable CONFIG_ACPI_FPDT, and have kernels v5.12 for + x86 and v6.2 for arm. + Features: * sd-boot: add a new PE section .bls or so that carries a cpio with additional diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 668f6c3eee9..9f77997d5a5 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -61,6 +61,37 @@ struct acpi_fpdt_boot { uint64_t exit_services_exit; } _packed; +/* /dev/mem is deprecated on many systems, try using /sys/firmware/acpi/fpdt parsing instead. + * This code requires kernel version 5.12 on x86 based machines or 6.2 for arm64 */ +static int acpi_get_boot_usec_kernel_parsed(usec_t *ret_loader_start, usec_t *ret_loader_exit) { + usec_t start, end; + int r; + + r = read_timestamp_file("/sys/firmware/acpi/fpdt/boot/exitbootservice_end_ns", &end); + if (r < 0) + return r; + + if (end == 0) + /* Non-UEFI compatible boot. */ + return -ENODATA; + + r = read_timestamp_file("/sys/firmware/acpi/fpdt/boot/bootloader_launch_ns", &start); + if (r < 0) + return r; + + if (start == 0 || end < start) + return -EINVAL; + if (end > NSEC_PER_HOUR) + return -EINVAL; + + if (ret_loader_start) + *ret_loader_start = start / 1000; + if (ret_loader_exit) + *ret_loader_exit = end / 1000; + + return 0; +} + int acpi_get_boot_usec(usec_t *ret_loader_start, usec_t *ret_loader_exit) { _cleanup_free_ char *buf = NULL; struct acpi_table_header *tbl; @@ -73,6 +104,10 @@ int acpi_get_boot_usec(usec_t *ret_loader_start, usec_t *ret_loader_exit) { struct acpi_fpdt_boot_header hbrec; struct acpi_fpdt_boot brec; + r = acpi_get_boot_usec_kernel_parsed(ret_loader_start, ret_loader_exit); + if (r != -ENOENT) /* fallback to /dev/mem hack only if kernel doesn't support the new sysfs files */ + return r; + r = read_full_virtual_file("/sys/firmware/acpi/tables/FPDT", &buf, &l); if (r < 0) return r;