Index | Thread | Search

From:
Mark Kettenis <mark.kettenis@xs4all.nl>
Subject:
Re: [PATCH 4/4] Generate FDT entry for the EL2 virtual timer when available in GTDT
To:
Marc Zyngier <maz@kernel.org>
Cc:
tech@openbsd.org, kettenis@openbsd.org, legoll@online.fr
Date:
Sat, 25 Apr 2026 22:36:52 +0200

Download raw body.

Thread
> Date: Sun, 12 Apr 2026 17:54:59 +0100
> From: Marc Zyngier <maz@kernel.org>

Hi Marc,

> On Sun, 12 Apr 2026 11:18:24 +0100,
> Marc Zyngier <maz@kernel.org> wrote:
> > 
> > The GTDT ACPI table optionally indicates the interrupt number for
> > the EL2 virtual timer. Popagate this into the generated FDT so that
> > it can be used when running at EL2.
> > 
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > ---
> >  sys/arch/arm64/stand/efiboot/efiacpi.c | 15 +++++++++++++--
> >  1 file changed, 13 insertions(+), 2 deletions(-)
> > 
> > diff --git a/sys/arch/arm64/stand/efiboot/efiacpi.c b/sys/arch/arm64/stand/efiboot/efiacpi.c
> > index 6e0ace3ef..02fa4fe80 100644
> > --- a/sys/arch/arm64/stand/efiboot/efiacpi.c
> > +++ b/sys/arch/arm64/stand/efiboot/efiacpi.c
> > @@ -228,6 +228,8 @@ struct acpi_gtdt {
> >  	uint64_t	cnt_read_base;
> >  	uint32_t	platform_timer_count;
> >  	uint32_t	platform_timer_offset;
> > +	uint32_t	virt_el2_interrupt;
> > +	uint32_t	virt_el2_flags;
> >  } __packed;
> >  
> >  struct acpi_madt {
> > @@ -402,7 +404,8 @@ efi_acpi_gtdt(struct acpi_table_header *hdr)
> >  	const uint32_t map[] = { 0x4, 0x1, 0x8, 0x2 };
> >  	const uint32_t mask = ACPI_GTDT_TIMER_TRIGGER_EDGE |
> >  	    ACPI_GTDT_TIMER_POLARITY_LOW;
> > -	uint32_t interrupts[12];
> > +	uint32_t interrupts[15];
> > +	size_t sz = sizeof(interrupts);
> >  	void *node;
> >  
> >  	/* All interrupts are supposed to be PPIs. */
> > @@ -419,9 +422,17 @@ efi_acpi_gtdt(struct acpi_table_header *hdr)
> >  	interrupts[10] = htobe32(gtdt->nonsec_el2_interrupt - 16);
> >  	interrupts[11] = htobe32(map[gtdt->nonsec_el2_flags & mask]);
> >  
> > +	if (gtdt->hdr_length > 0x60) {
> > +		interrupts[12] = htobe32(1);
> > +		interrupts[13] = htobe32(gtdt->virt_el2_interrupt - 16);
> > +		interrupts[14] = htobe32(map[gtdt->virt_el2_flags & mask]);
> > +
> > +		sz += 3 * sizeof(uint32_t);
> 
> As pointed out by Vincent off-list, the initialisation and this line
> combine badly, resulting in an embarrassing bug.
> 
> The init part should reflect the later correction with something like
> this:
> 
> diff --git stand/efiboot/efiacpi.c stand/efiboot/efiacpi.c
> index 02fa4fe80..ca6defd7d 100644
> --- stand/efiboot/efiacpi.c
> +++ stand/efiboot/efiacpi.c
> @@ -405,7 +405,7 @@ efi_acpi_gtdt(struct acpi_table_header *hdr)
>  	const uint32_t mask = ACPI_GTDT_TIMER_TRIGGER_EDGE |
>  	    ACPI_GTDT_TIMER_POLARITY_LOW;
>  	uint32_t interrupts[15];
> -	size_t sz = sizeof(interrupts);
> +	size_t sz = sizeof(interrupts) - 3 * sizeof(uint32_t);
>  	void *node;
>  
>  	/* All interrupts are supposed to be PPIs. */
> 
> Apologies for the noise.

Thanks!

The fields in the GTSD table are new in version 3 of the table.  And
the EL2 virtual timer interrupt field can be 0, which indicates no
support.  So I tightened up the check a bit.  I also decided to add an
"interrupt-names" property to make it easier to see what timer
interrupts are supported.

Anyone reviewing this should ignore the dt_blob.S bit; that is just
the result of regenerating the blob from acpi.dts.

ok?


Index: arch/arm64/stand/efiboot/acpi.dts
===================================================================
RCS file: /cvs/src/sys/arch/arm64/stand/efiboot/acpi.dts,v
diff -u -p -r1.1 acpi.dts
--- arch/arm64/stand/efiboot/acpi.dts	25 Jun 2018 22:39:14 -0000	1.1
+++ arch/arm64/stand/efiboot/acpi.dts	25 Apr 2026 20:27:47 -0000
@@ -29,6 +29,7 @@
 	timer {
 		compatible = "arm,armv8-timer";
 		interrupts = <0 0 0>, <0 0 0>, <0 0 0>, <0 0 0>;
+		interrupt-names = "sec-phys", "phys", "virt", "hyp-phys";
 		status = "disabled";
 	};
 
Index: arch/arm64/stand/efiboot/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/stand/efiboot/conf.c,v
diff -u -p -r1.53 conf.c
--- arch/arm64/stand/efiboot/conf.c	25 Jan 2026 18:19:13 -0000	1.53
+++ arch/arm64/stand/efiboot/conf.c	25 Apr 2026 20:27:47 -0000
@@ -47,7 +47,7 @@
 #include "efipxe.h"
 #include "softraid_arm64.h"
 
-const char version[] = "1.24";
+const char version[] = "1.25";
 int	debug = 0;
 
 struct fs_ops file_system[] = {
Index: arch/arm64/stand/efiboot/dt_blob.S
===================================================================
RCS file: /cvs/src/sys/arch/arm64/stand/efiboot/dt_blob.S,v
diff -u -p -r1.2 dt_blob.S
--- arch/arm64/stand/efiboot/dt_blob.S	14 Mar 2022 19:09:32 -0000	1.2
+++ arch/arm64/stand/efiboot/dt_blob.S	25 Apr 2026 20:27:47 -0000
@@ -7,7 +7,10 @@ _dt_blob_start:
 dt_header:
 _dt_header:
 	/* magic */
-	.byte 0xd0; .byte 0x0d; .byte 0xfe; .byte 0xed
+	.byte	0xd0
+	.byte	0x0d
+	.byte	0xfe
+	.byte	0xed
 	/* totalsize */
 	.byte	((_dt_blob_abs_end - _dt_blob_start) >> 24) & 0xff
 	.byte	((_dt_blob_abs_end - _dt_blob_start) >> 16) & 0xff
@@ -29,11 +32,20 @@ _dt_header:
 	.byte	((_dt_reserve_map - _dt_blob_start) >> 8) & 0xff
 	.byte	(_dt_reserve_map - _dt_blob_start) & 0xff
 	/* version */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x11
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x11
 	/* last_comp_version */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x10
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x10
 	/* boot_cpuid_phys */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
 	/* size_dt_strings */
 	.byte	((_dt_strings_end - _dt_strings_start) >> 24) & 0xff
 	.byte	((_dt_strings_end - _dt_strings_start) >> 16) & 0xff
@@ -55,320 +67,900 @@ _dt_reserve_map:
 dt_struct_start:
 _dt_struct_start:
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	""
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x05
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x41; .byte 0x43; .byte 0x50; .byte 0x49
-	.byte	0x0
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x0d
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x06
-	.byte 0x6f; .byte 0x70; .byte 0x65; .byte 0x6e
-	.byte 0x62; .byte 0x73; .byte 0x64; .byte 0x2c
-	.byte 0x61; .byte 0x63; .byte 0x70; .byte 0x69
-	.byte	0x0
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x11
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x22
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x31
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	""
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x05
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x41
+	.byte	0x43
+	.byte	0x50
+	.byte	0x49
+	.byte	0x0
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x0d
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x06
+	.byte	0x6f
+	.byte	0x70
+	.byte	0x65
+	.byte	0x6e
+	.byte	0x62
+	.byte	0x73
+	.byte	0x64
+	.byte	0x2c
+	.byte	0x61
+	.byte	0x63
+	.byte	0x70
+	.byte	0x69
+	.byte	0x0
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x11
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x22
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x31
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	.balign	4, 0
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	"chosen"
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x11
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x3d
-	.byte 0x73; .byte 0x65; .byte 0x72; .byte 0x69
-	.byte 0x61; .byte 0x6c; .byte 0x30; .byte 0x3a
-	.byte 0x31; .byte 0x31; .byte 0x35; .byte 0x32
-	.byte 0x30; .byte 0x30; .byte 0x6e; .byte 0x38
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	"chosen"
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x11
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x3d
+	.byte	0x73
+	.byte	0x65
+	.byte	0x72
+	.byte	0x69
+	.byte	0x61
+	.byte	0x6c
+	.byte	0x30
+	.byte	0x3a
+	.byte	0x31
+	.byte	0x31
+	.byte	0x35
+	.byte	0x32
+	.byte	0x30
+	.byte	0x30
+	.byte	0x6e
+	.byte	0x38
 	.byte	0x0
 	.balign	4, 0
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	"aliases"
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x0a
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x49
-	.byte 0x2f; .byte 0x73; .byte 0x65; .byte 0x72
-	.byte 0x69; .byte 0x61; .byte 0x6c; .byte 0x40
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	"aliases"
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x0a
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x49
+	.byte	0x2f
+	.byte	0x73
+	.byte	0x65
+	.byte	0x72
+	.byte	0x69
+	.byte	0x61
+	.byte	0x6c
+	.byte	0x40
 	.byte	0x30
 	.byte	0x0
 	.balign	4, 0
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	"cpus"
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x22
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x31
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	"cpus"
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x22
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x31
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
 	.balign	4, 0
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	"psci"
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x0d
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x06
-	.byte 0x61; .byte 0x72; .byte 0x6d; .byte 0x2c
-	.byte 0x70; .byte 0x73; .byte 0x63; .byte 0x69
-	.byte 0x2d; .byte 0x31; .byte 0x2e; .byte 0x30
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	"psci"
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x0d
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x06
+	.byte	0x61
+	.byte	0x72
+	.byte	0x6d
+	.byte	0x2c
+	.byte	0x70
+	.byte	0x73
+	.byte	0x63
+	.byte	0x69
+	.byte	0x2d
+	.byte	0x31
+	.byte	0x2e
+	.byte	0x30
 	.byte	0x0
 	.balign	4, 0
 	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x51
-	.byte 0x73; .byte 0x6d; .byte 0x63; .byte 0x00
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x09
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x58
-	.byte 0x64; .byte 0x69; .byte 0x73; .byte 0x61
-	.byte 0x62; .byte 0x6c; .byte 0x65; .byte 0x64
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x51
+	.byte	0x73
+	.byte	0x6d
+	.byte	0x63
+	.byte	0x00
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x09
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x58
+	.byte	0x64
+	.byte	0x69
+	.byte	0x73
+	.byte	0x61
+	.byte	0x62
+	.byte	0x6c
+	.byte	0x65
+	.byte	0x64
 	.byte	0x0
 	.balign	4, 0
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	"timer"
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x10
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x06
-	.byte 0x61; .byte 0x72; .byte 0x6d; .byte 0x2c
-	.byte 0x61; .byte 0x72; .byte 0x6d; .byte 0x76
-	.byte 0x38; .byte 0x2d; .byte 0x74; .byte 0x69
-	.byte 0x6d; .byte 0x65; .byte 0x72; .byte 0x00
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x30
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x5f
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x09
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x58
-	.byte 0x64; .byte 0x69; .byte 0x73; .byte 0x61
-	.byte 0x62; .byte 0x6c; .byte 0x65; .byte 0x64
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	"timer"
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x10
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x06
+	.byte	0x61
+	.byte	0x72
+	.byte	0x6d
+	.byte	0x2c
+	.byte	0x61
+	.byte	0x72
+	.byte	0x6d
+	.byte	0x76
+	.byte	0x38
+	.byte	0x2d
+	.byte	0x74
+	.byte	0x69
+	.byte	0x6d
+	.byte	0x65
+	.byte	0x72
+	.byte	0x00
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x30
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x5f
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x1c
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x6a
+	.byte	0x73
+	.byte	0x65
+	.byte	0x63
+	.byte	0x2d
+	.byte	0x70
+	.byte	0x68
+	.byte	0x79
+	.byte	0x73
+	.byte	0x00
+	.byte	0x70
+	.byte	0x68
+	.byte	0x79
+	.byte	0x73
+	.byte	0x00
+	.byte	0x76
+	.byte	0x69
+	.byte	0x72
+	.byte	0x74
+	.byte	0x00
+	.byte	0x68
+	.byte	0x79
+	.byte	0x70
+	.byte	0x2d
+	.byte	0x70
+	.byte	0x68
+	.byte	0x79
+	.byte	0x73
+	.byte	0x00
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x09
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x58
+	.byte	0x64
+	.byte	0x69
+	.byte	0x73
+	.byte	0x61
+	.byte	0x62
+	.byte	0x6c
+	.byte	0x65
+	.byte	0x64
 	.byte	0x0
 	.balign	4, 0
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	.globl	gic
 gic:
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	"interrupt-controller@0"
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x0c
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x06
-	.byte 0x6f; .byte 0x70; .byte 0x65; .byte 0x6e
-	.byte 0x62; .byte 0x73; .byte 0x64; .byte 0x2c
-	.byte 0x67; .byte 0x69; .byte 0x63; .byte 0x00
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x6a
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x22
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x31
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x7b
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x90
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x20
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x97
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x09
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x58
-	.byte 0x64; .byte 0x69; .byte 0x73; .byte 0x61
-	.byte 0x62; .byte 0x6c; .byte 0x65; .byte 0x64
-	.byte	0x0
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x04
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x9b
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	"interrupt-controller@0"
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x0c
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x06
+	.byte	0x6f
+	.byte	0x70
+	.byte	0x65
+	.byte	0x6e
+	.byte	0x62
+	.byte	0x73
+	.byte	0x64
+	.byte	0x2c
+	.byte	0x67
+	.byte	0x69
+	.byte	0x63
+	.byte	0x00
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x7a
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x22
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x31
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x8b
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0xa0
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x20
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0xa7
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x09
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x58
+	.byte	0x64
+	.byte	0x69
+	.byte	0x73
+	.byte	0x61
+	.byte	0x62
+	.byte	0x6c
+	.byte	0x65
+	.byte	0x64
+	.byte	0x0
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x04
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0xab
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
 	.balign	4, 0
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	.globl	gic_end
 gic_end:
 	.globl	uart0
 uart0:
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	"serial@0"
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x0d
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x06
-	.byte 0x6f; .byte 0x70; .byte 0x65; .byte 0x6e
-	.byte 0x62; .byte 0x73; .byte 0x64; .byte 0x2c
-	.byte 0x75; .byte 0x61; .byte 0x72; .byte 0x74
-	.byte	0x0
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x10
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x97
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x09
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x58
-	.byte 0x64; .byte 0x69; .byte 0x73; .byte 0x61
-	.byte 0x62; .byte 0x6c; .byte 0x65; .byte 0x64
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	"serial@0"
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x0d
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x06
+	.byte	0x6f
+	.byte	0x70
+	.byte	0x65
+	.byte	0x6e
+	.byte	0x62
+	.byte	0x73
+	.byte	0x64
+	.byte	0x2c
+	.byte	0x75
+	.byte	0x61
+	.byte	0x72
+	.byte	0x74
+	.byte	0x0
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x10
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0xa7
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x09
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x58
+	.byte	0x64
+	.byte	0x69
+	.byte	0x73
+	.byte	0x61
+	.byte	0x62
+	.byte	0x6c
+	.byte	0x65
+	.byte	0x64
 	.byte	0x0
 	.balign	4, 0
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	.globl	uart0_end
 uart0_end:
 	/* FDT_BEGIN_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x01
-	.string	"acpi@0"
-	.balign	4, 0
-	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x11
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x06
-	.byte 0x6f; .byte 0x70; .byte 0x65; .byte 0x6e
-	.byte 0x62; .byte 0x73; .byte 0x64; .byte 0x2c
-	.byte 0x61; .byte 0x63; .byte 0x70; .byte 0x69
-	.byte 0x2d; .byte 0x35; .byte 0x2e; .byte 0x30
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x01
+	.asciz	"acpi@0"
+	.balign	4, 0
+	/* FDT_PROP */
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x11
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x06
+	.byte	0x6f
+	.byte	0x70
+	.byte	0x65
+	.byte	0x6e
+	.byte	0x62
+	.byte	0x73
+	.byte	0x64
+	.byte	0x2c
+	.byte	0x61
+	.byte	0x63
+	.byte	0x70
+	.byte	0x69
+	.byte	0x2d
+	.byte	0x35
+	.byte	0x2e
+	.byte	0x30
 	.byte	0x0
 	.balign	4, 0
 	/* FDT_PROP */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x03
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x10
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x97
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x03
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x10
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0xa7
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
 	.balign	4, 0
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	/* FDT_END_NODE */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x02
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x02
 	/* FDT_END */
-	.byte 0x00; .byte 0x00; .byte 0x00; .byte 0x09
+	.byte	0x00
+	.byte	0x00
+	.byte	0x00
+	.byte	0x09
 	.globl	dt_struct_end
 dt_struct_end:
 _dt_struct_end:
 	.globl	dt_strings_start
 dt_strings_start:
 _dt_strings_start:
-	.string "model"
-	.string "compatible"
-	.string "interrupt-parent"
-	.string "#address-cells"
-	.string "#size-cells"
-	.string "stdout-path"
-	.string "serial0"
-	.string "method"
-	.string "status"
-	.string "interrupts"
-	.string "#interrupt-cells"
-	.string "interrupt-controller"
-	.string "ranges"
-	.string "reg"
-	.string "phandle"
+	.asciz "model"
+	.asciz "compatible"
+	.asciz "interrupt-parent"
+	.asciz "#address-cells"
+	.asciz "#size-cells"
+	.asciz "stdout-path"
+	.asciz "serial0"
+	.asciz "method"
+	.asciz "status"
+	.asciz "interrupts"
+	.asciz "interrupt-names"
+	.asciz "#interrupt-cells"
+	.asciz "interrupt-controller"
+	.asciz "ranges"
+	.asciz "reg"
+	.asciz "phandle"
 	.globl	dt_strings_end
 dt_strings_end:
 _dt_strings_end:
Index: arch/arm64/stand/efiboot/efiacpi.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/stand/efiboot/efiacpi.c,v
diff -u -p -r1.19 efiacpi.c
--- arch/arm64/stand/efiboot/efiacpi.c	10 Feb 2025 20:40:26 -0000	1.19
+++ arch/arm64/stand/efiboot/efiacpi.c	25 Apr 2026 20:27:47 -0000
@@ -221,13 +221,15 @@ struct acpi_gtdt {
 #define ACPI_GTDT_TIMER_ALWAYS_ON	0x4
 	uint32_t	nonsec_el1_interrupt;
 	uint32_t	nonsec_el1_flags;
-	uint32_t	virt_interrupt;
-	uint32_t	virt_flags;
+	uint32_t	virt_el1_interrupt;
+	uint32_t	virt_el1_flags;
 	uint32_t	nonsec_el2_interrupt;
 	uint32_t	nonsec_el2_flags;
 	uint64_t	cnt_read_base;
 	uint32_t	platform_timer_count;
 	uint32_t	platform_timer_offset;
+	uint32_t	virt_el2_interrupt;
+	uint32_t	virt_el2_flags;
 } __packed;
 
 struct acpi_madt {
@@ -402,8 +404,12 @@ efi_acpi_gtdt(struct acpi_table_header *
 	const uint32_t map[] = { 0x4, 0x1, 0x8, 0x2 };
 	const uint32_t mask = ACPI_GTDT_TIMER_TRIGGER_EDGE |
 	    ACPI_GTDT_TIMER_POLARITY_LOW;
-	uint32_t interrupts[12];
+	char interrupt_names[] = "sec-phys\0phys\0virt\0hyp-phys\0hyp-virt";
+	uint32_t interrupts[15];
 	void *node;
+	size_t len;
+
+	node = fdt_find_node("/timer");
 
 	/* All interrupts are supposed to be PPIs. */
 	interrupts[0] = htobe32(1);
@@ -413,15 +419,25 @@ efi_acpi_gtdt(struct acpi_table_header *
 	interrupts[4] = htobe32(gtdt->nonsec_el1_interrupt - 16);
 	interrupts[5] = htobe32(map[gtdt->nonsec_el1_flags & mask]);
 	interrupts[6] = htobe32(1);
-	interrupts[7] = htobe32(gtdt->virt_interrupt - 16);
-	interrupts[8] = htobe32(map[gtdt->virt_flags & mask]);
+	interrupts[7] = htobe32(gtdt->virt_el1_interrupt - 16);
+	interrupts[8] = htobe32(map[gtdt->virt_el1_flags & mask]);
 	interrupts[9] = htobe32(1);
 	interrupts[10] = htobe32(gtdt->nonsec_el2_interrupt - 16);
 	interrupts[11] = htobe32(map[gtdt->nonsec_el2_flags & mask]);
+	len = 12 * sizeof(uint32_t);
 
-	node = fdt_find_node("/timer");
-	fdt_node_set_property(node, "interrupts",
-	    interrupts, sizeof(interrupts));
+	if (gtdt->hdr.revision > 2 && gtdt->hdr.length >= 104 &&
+	    gtdt->virt_el2_interrupt > 0) {
+		interrupts[12] = htobe32(1);
+		interrupts[13] = htobe32(gtdt->virt_el2_interrupt - 16);
+		interrupts[14] = htobe32(map[gtdt->virt_el2_flags & mask]);
+		len = 15 * sizeof(uint32_t);
+
+		fdt_node_set_property(node, "interrupt-names",
+		    interrupt_names, sizeof(interrupt_names));
+	}
+
+	fdt_node_set_property(node, "interrupts", interrupts, len);
 	fdt_node_set_string_property(node, "status", "okay");
 }