drivers/acpi/arm64/gtdt.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
The following commit has been merged into the timers/clocksource branch of tip:
Commit-ID: 002dcb3a893627fcedf12692063b80c720869ea5
Gitweb: https://git.kernel.org/tip/002dcb3a893627fcedf12692063b80c720869ea5
Author: Marc Zyngier <maz@kernel.org>
AuthorDate: Sat, 23 May 2026 15:02:26 +01:00
Committer: Daniel Lezcano <daniel.lezcano@kernel.org>
CommitterDate: Wed, 03 Jun 2026 09:52:23 +02:00
ACPI: GTDT: Account for GTDTv3 size when walking the platform timer descriptors
Since ARMv8.1, the architecture has grown an EL2-private virtual
timer. This has been described in ACPI since ACPI v6.3 and revision
3 of the GTDT table.
An aditional structure was added in ACPICA, though in a rather
bizarre way, and merged in v5.1 as 8f5a14d053100 ("ACPICA: ACPI 6.3:
add GTDT Revision 3 support").
Finally plug the table parsing in GTDT, and correct the parsing of
the platform timer subtables to account for the expanded size of
the base table. This also comes with some extra sanitisation of
the table, in the unlikely case someone got it wrong...
Suggested-by: Sudeep Holla <sudeep.holla@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Daniel Lezcano <daniel.lezcano@kernel.org>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
Reviewed-by: Sudeep Holla <sudeep.holla@kernel.org>
Link: https://patch.msgid.link/20260523140242.586031-2-maz@kernel.org
---
drivers/acpi/arm64/gtdt.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c
index ffc867b..950d5ef 100644
--- a/drivers/acpi/arm64/gtdt.c
+++ b/drivers/acpi/arm64/gtdt.c
@@ -34,14 +34,25 @@ struct acpi_gtdt_descriptor {
void *platform_timer;
};
+struct gtdt_v3 {
+ struct acpi_table_gtdt gtdt_v2;
+ struct acpi_gtdt_el2 el2_vtimer;
+};
+
static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
static __init bool platform_timer_valid(void *platform_timer)
{
struct acpi_gtdt_header *gh = platform_timer;
+ void *platform_timer_begin;
- return (platform_timer >= (void *)(acpi_gtdt_desc.gtdt + 1) &&
- platform_timer < acpi_gtdt_desc.gtdt_end &&
+ if (acpi_gtdt_desc.gtdt->header.revision >= 3)
+ platform_timer_begin = container_of(acpi_gtdt_desc.gtdt, struct gtdt_v3, gtdt_v2) + 1;
+ else
+ platform_timer_begin = acpi_gtdt_desc.gtdt + 1;
+
+ return (platform_timer >= platform_timer_begin &&
+ platform_timer + sizeof(*gh) <= acpi_gtdt_desc.gtdt_end &&
gh->length != 0 &&
platform_timer + gh->length <= acpi_gtdt_desc.gtdt_end);
}
@@ -166,6 +177,13 @@ int __init acpi_gtdt_init(struct acpi_table_header *table,
u32 cnt = 0;
gtdt = container_of(table, struct acpi_table_gtdt, header);
+
+ if ((gtdt->header.revision >= 3 && gtdt->header.length < sizeof(struct gtdt_v3)) ||
+ (gtdt->header.revision == 2 && gtdt->header.length < sizeof(*gtdt))) {
+ pr_err(FW_BUG "GTDT with invalid size %d\n", gtdt->header.length);
+ return -EINVAL;
+ }
+
acpi_gtdt_desc.gtdt = gtdt;
acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
acpi_gtdt_desc.platform_timer = NULL;
© 2016 - 2026 Red Hat, Inc.