diff options
Diffstat (limited to 'src/shared/acpi-fpdt.c')
-rw-r--r-- | src/shared/acpi-fpdt.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 668f6c3eee..9f77997d5a 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; |