public inbox for linux-arm-kernel@lists.infradead.org 
 help / color / mirror / Atom feed
* [BOOTWRAPPER PATCH v3 0/2] Support GICv5
@ 2026-05-29  9:50 Vladimir Murzin
  2026-05-29  9:50 ` [BOOTWRAPPER PATCH v3 1/2] Introduce --with-gic option Vladimir Murzin
  2026-05-29  9:50 ` [BOOTWRAPPER PATCH v3 2/2] Add support for GICv5 Vladimir Murzin
  0 siblings, 2 replies; 5+ messages in thread
From: Vladimir Murzin @ 2026-05-29  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: vladimir.murzin, mark.rutland, maz, joey.gouly, Sascha.Bischoff

Small series adding GICv5 to the list of supported GIC
versions. Minimal implementation, just enough for Fast Models.

Thanks!

Changelog:
  v2 -> v3
     - Fixed code formatting and incorrect comments (per Sascha)
     - Fixed spelling and grammar mistakes (per Sascha)
     - Added tags from Sascha Bischoff
  v1 -> v2
     - Assign SW_PPI to NS domain (per Sascha)

Vladimir Murzin (2):
  Introduce --with-gic option
  Add support for GICv5

 Makefile.am                    |  15 +++-
 arch/aarch64/include/asm/cpu.h |  11 +++
 common/{gic.c => gic-v2.c}     |   0
 common/gic-v5.c                | 132 +++++++++++++++++++++++++++++++++
 configure.ac                   |  24 ++++--
 scripts/FDT.pm                 |  16 ++++
 scripts/findbase-by-regname.pl |  44 +++++++++++
 7 files changed, 232 insertions(+), 10 deletions(-)
 rename common/{gic.c => gic-v2.c} (100%)
 create mode 100644 common/gic-v5.c
 create mode 100755 scripts/findbase-by-regname.pl

-- 
2.34.1



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [BOOTWRAPPER PATCH v3 1/2] Introduce --with-gic option
  2026-05-29  9:50 [BOOTWRAPPER PATCH v3 0/2] Support GICv5 Vladimir Murzin
@ 2026-05-29  9:50 ` Vladimir Murzin
  2026-05-29  9:50 ` [BOOTWRAPPER PATCH v3 2/2] Add support for GICv5 Vladimir Murzin
  1 sibling, 0 replies; 5+ messages in thread
From: Vladimir Murzin @ 2026-05-29  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: vladimir.murzin, mark.rutland, maz, joey.gouly, Sascha.Bischoff

We are about to add support for another GIC version, so introduce a
new --with-gic option to select the desired GIC version at configure
time. The default remains v2, preserving existing behavior.  However,
for GICv3, we replace the previous --enable-gicv3 option with
--with-gic=v3 which is backward-incompatible change (yet I hope we can
live with that).

Signed-off-by: Vladimir Murzin <vladimir.murzin@arm•com>
Reviewed-by: Sascha Bischoff <sascha.bischoff@arm•com>
---
 Makefile.am                |  8 +++++---
 common/{gic.c => gic-v2.c} |  0
 configure.ac               | 23 ++++++++++++++++-------
 3 files changed, 21 insertions(+), 10 deletions(-)
 rename common/{gic.c => gic-v2.c} (100%)

diff --git a/Makefile.am b/Makefile.am
index 0178e5d..2710494 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -87,15 +87,17 @@ GIC_DIST_BASE	:= $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNE
 GIC_RDIST_BASE	:= $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 1 'arm,gic-v3')
 DEFINES		+= -DGIC_DIST_BASE=$(GIC_DIST_BASE)
 DEFINES		+= -DGIC_RDIST_BASE=$(GIC_RDIST_BASE)
-COMMON_OBJ	+= gic-v3.o
-else
+endif
+
+if GICV2
 GIC_DIST_BASE	:= $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,cortex-a15-gic')
 GIC_CPU_BASE	:= $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 1 'arm,cortex-a15-gic')
 DEFINES		+= -DGIC_CPU_BASE=$(GIC_CPU_BASE)
 DEFINES		+= -DGIC_DIST_BASE=$(GIC_DIST_BASE)
-COMMON_OBJ	+= gic.o
 endif
 
+COMMON_OBJ	+= gic-$(GIC_VERSION).o
+
 if KERNEL_32
 MBOX_OFFSET	:= 0x7ff8
 TEXT_LIMIT	:= 0x3000
diff --git a/common/gic.c b/common/gic-v2.c
similarity index 100%
rename from common/gic.c
rename to common/gic-v2.c
diff --git a/configure.ac b/configure.ac
index 42858df..6f486c4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -139,12 +139,21 @@ AC_ARG_WITH([xen-cmdline],
 	[X_CMDLINE=$withval])
 AC_SUBST([XEN_CMDLINE], [$X_CMDLINE])
 
-# Allow a user to pass --enable-gicv3
-AC_ARG_ENABLE([gicv3],
-	AS_HELP_STRING([--enable-gicv3], [enable GICv3 instead of GICv2]),
-	[USE_GICV3=$enableval])
-AM_CONDITIONAL([GICV3], [test "x$USE_GICV3" = "xyes"])
-AS_IF([test "x$USE_GICV3" = "xyes"], [], [USE_GICV3=no])
+
+AC_ARG_WITH([gic],
+  AS_HELP_STRING([--with-gic={v2|v3}], [select GIC version]),
+  [GIC_VERSION=$withval],
+  [GIC_VERSION=v2])
+
+AS_CASE([$GIC_VERSION],
+  [v2|v3], [],
+  [AC_MSG_ERROR([Invalid GIC version: $GIC_VERSION (use v2 or v3)])])
+
+AC_SUBST([GIC_VERSION], [$GIC_VERSION])
+
+AM_CONDITIONAL([GICV2], [test "x$GIC_VERSION" = "xv2"])
+AM_CONDITIONAL([GICV3], [test "x$GIC_VERSION" = "xv3"])
+
 
 # Ensure that we have all the needed programs
 AC_PROG_CC
@@ -174,7 +183,7 @@ echo "  Device tree compiler:              ${DTC}"
 echo "  Linux kernel command line:         ${CMDLINE}"
 echo "  Embedded initrd:                   ${FILESYSTEM:-NONE}"
 echo "  Use PSCI?                          ${USE_PSCI}"
-echo "  Use GICv3?                         ${USE_GICV3}"
+echo "  GIC version:                       ${GIC_VERSION}"
 echo "  Boot-wrapper execution state:      AArch${BOOTWRAPPER_ES}"
 echo "  Kernel execution state:            AArch${KERNEL_ES}"
 echo "  Xen image                          ${XEN_IMAGE:-NONE}"
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [BOOTWRAPPER PATCH v3 2/2] Add support for GICv5
  2026-05-29  9:50 [BOOTWRAPPER PATCH v3 0/2] Support GICv5 Vladimir Murzin
  2026-05-29  9:50 ` [BOOTWRAPPER PATCH v3 1/2] Introduce --with-gic option Vladimir Murzin
@ 2026-05-29  9:50 ` Vladimir Murzin
  2026-05-29 15:34   ` Sascha Bischoff
  1 sibling, 1 reply; 5+ messages in thread
From: Vladimir Murzin @ 2026-05-29  9:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: vladimir.murzin, mark.rutland, maz, joey.gouly, Sascha.Bischoff

Performs the minimal initialization required for GICv5 support. GICv5
support can be requested with --with-gic=v5.

Signed-off-by: Vladimir Murzin <vladimir.murzin@arm•com>
Tested-by: Sascha Bischoff <sascha.bischoff@arm•com>
---
 Makefile.am                    |   7 ++
 arch/aarch64/include/asm/cpu.h |  11 +++
 common/gic-v5.c                | 132 +++++++++++++++++++++++++++++++++
 configure.ac                   |   7 +-
 scripts/FDT.pm                 |  16 ++++
 scripts/findbase-by-regname.pl |  44 +++++++++++
 6 files changed, 214 insertions(+), 3 deletions(-)
 create mode 100644 common/gic-v5.c
 create mode 100755 scripts/findbase-by-regname.pl

diff --git a/Makefile.am b/Makefile.am
index 2710494..aacd639 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -82,6 +82,13 @@ PSCI_NODE	:=
 CPU_NODES	:=
 endif
 
+if GICV5
+GIC_IRS_BASE	:= $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase-by-regname.pl $(KERNEL_DTB) "el3-config" 'arm,gic-v5-irs')
+GIC_IWB_BASE	:= $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,gic-v5-iwb')
+DEFINES		+= -DGIC_IRS_BASE=$(GIC_IRS_BASE)
+DEFINES		+= -DGIC_IWB_BASE=$(GIC_IWB_BASE)
+endif
+
 if GICV3
 GIC_DIST_BASE	:= $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,gic-v3')
 GIC_RDIST_BASE	:= $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 1 'arm,gic-v3')
diff --git a/arch/aarch64/include/asm/cpu.h b/arch/aarch64/include/asm/cpu.h
index ac50474..af4191c 100644
--- a/arch/aarch64/include/asm/cpu.h
+++ b/arch/aarch64/include/asm/cpu.h
@@ -128,6 +128,7 @@
 #define ID_AA64PFR1_EL1_THE		BITS(51, 48)
 
 #define ID_AA64PFR2_EL1			s3_0_c0_c4_2
+#define ID_AA64PFR2_EL1_GCIE		BITS(15, 12)
 #define ID_AA64PFR2_EL1_FPMR		BITS(35, 32)
 
 #define ID_AA64SMFR0_EL1		s3_0_c0_c4_5
@@ -169,6 +170,11 @@
 #define ICC_CTLR_EL3		S3_6_C12_C12_4
 #define ICC_PMR_EL1		S3_0_C4_C6_0
 
+#define ICC_PPI_DOMAINR0_EL3	S3_6_C12_C8_4
+#define ICC_PPI_DOMAINR1_EL3	S3_6_C12_C8_5
+#define ICC_PPI_DOMAINR2_EL3	S3_6_C12_C8_6
+#define ICC_PPI_DOMAINR3_EL3	S3_6_C12_C8_7
+
 #define VSTCR_EL2		s3_4_c2_c6_2
 #define VSCTLR_EL2		s3_4_c2_c0_0
 
@@ -245,6 +251,11 @@ static inline int has_gicv3_sysreg(void)
 	return !!mrs_field(ID_AA64PFR0_EL1, GIC);
 }
 
+static inline int has_gicv5_sysreg(void)
+{
+	return !!mrs_field(ID_AA64PFR2_EL1, GCIE);
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif
diff --git a/common/gic-v5.c b/common/gic-v5.c
new file mode 100644
index 0000000..49b7b0e
--- /dev/null
+++ b/common/gic-v5.c
@@ -0,0 +1,132 @@
+/*
+ * gic-v5.c
+ *
+ * Copyright (C) 2025 ARM Limited. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE.txt file.
+ */
+
+#include <stdint.h>
+
+#include <cpu.h>
+#include <gic.h>
+#include <asm/io.h>
+
+#define IWB_IDR0			0x0
+#define IWB_IDR0_IW_RANGE_SHIFT		0x0
+#define IWB_IDR0_IW_RANGE_MASK		0x7ff
+
+#define IWB_CR0				0x80
+#define IWB_CR0_IWBEN			(1 << 0)
+#define IWB_CR0_IDLE			(1 << 1)
+
+#define IWB_WENABLE_STATUSR		0xc0
+#define IWB_WENABLE_STATUSR_IDLE	(1 << 0)
+
+#define IWB_WDOMAIN_STATUSR		0xc4
+#define IWB_WDOMAIN_STATUSR_IDLE	(1 << 0)
+
+#define IWB_WENABLER			0x2000
+#define IWB_WDOMAINR			0x8000
+
+#define IRS_IDR6			0x0018
+#define IRS_IDR6_SPI_IRS_RANGE_MASK	0x1ffffff
+
+#define IRS_IDR7			0x001c
+#define IRS_IDR7_SPI_BASE_MASK		0xffffff
+
+#define IRS_SPI_SELR			0x108
+#define IRS_SPI_DOMAINR			0x10c
+
+#define IRS_SPI_STATUSR			0x0118
+#define IRS_SPI_STATUSR_IDLE		(1 << 0)
+
+static void gic_iwb_init(void) {
+	void *iwb_ptr = (void *)GIC_IWB_BASE;
+	unsigned int num;
+	unsigned int i;
+
+	/* Get number of implemented wire control registers */
+	num = ((raw_readl(iwb_ptr + IWB_IDR0) >> IWB_IDR0_IW_RANGE_SHIFT) & IWB_IDR0_IW_RANGE_MASK) + 1;
+
+	/* Disable all wires */
+	for (i = 0; i < num; i++)
+		raw_writel(0, iwb_ptr + IWB_WENABLER + i * 4);
+
+	while (!(raw_readl(iwb_ptr + IWB_WENABLE_STATUSR) & IWB_WENABLE_STATUSR_IDLE));
+
+	/* Assign all wires to Non-Secure domain */
+	for (i = 0; i < num * 2; i++)
+		raw_writel(0x55555555, iwb_ptr + IWB_WDOMAINR + i * 4);
+
+	while (!(raw_readl(iwb_ptr + IWB_WDOMAIN_STATUSR) & IWB_WDOMAIN_STATUSR_IDLE));
+
+	/* Enable IWB */
+	raw_writel(IWB_CR0_IWBEN, iwb_ptr + IWB_CR0);
+
+	while (!(raw_readl(iwb_ptr + IWB_CR0) & IWB_CR0_IDLE));
+}
+
+static void gic_irs_init(void) {
+	void *irs_ptr = (void *)GIC_IRS_BASE;
+	unsigned int range;
+	unsigned int base;
+	unsigned int i;
+
+	/* Get the range of implemented SPIs */
+	base = raw_readl(irs_ptr + IRS_IDR7) & IRS_IDR7_SPI_BASE_MASK;
+	range = raw_readl(irs_ptr + IRS_IDR6) & IRS_IDR6_SPI_IRS_RANGE_MASK;
+
+	for (i = base; i < base + range; i++) {
+		/* Select SPI */
+		raw_writel(i, irs_ptr + IRS_SPI_SELR);
+		while (!(raw_readl(irs_ptr + IRS_SPI_STATUSR) & IRS_SPI_STATUSR_IDLE));
+
+		/* Assign SPI to Non-Secure domain */
+		raw_writel(1, irs_ptr + IRS_SPI_DOMAINR);
+		while (!(raw_readl(irs_ptr + IRS_SPI_STATUSR) & IRS_SPI_STATUSR_IDLE));
+	}
+}
+
+static void gic_ppi_init(void) {
+	uint64_t val = 0;
+
+	val |= 1UL << (2 * 31); // Trace Buffer Unit
+	val |= 1UL << (2 * 30); // EL1 Physical Timer
+	val |= 1UL << (2 * 28); // Non-secure EL2 Virtual Timer
+	val |= 1UL << (2 * 27); // EL1 Virtual Timer
+	val |= 1UL << (2 * 26); // Non-secure EL2 Physical Timer
+	val |= 1UL << (2 * 25); // GIC maintenance interrupt
+	val |= 1UL << (2 * 24); // Generic CTI interrupt trigger event
+	val |= 1UL << (2 * 23); // PMU overflow interrupt request
+	val |= 1UL << (2 * 22); // Debug communication channel
+	val |= 1UL << (2 * 21); // Profiling Buffer management interrupt request
+	val |= 1UL << (2 * 15); // Hardware accelerator for cleaning Dirty state interrupt
+	val |= 1UL << (2 * 3);  // Reserved for software usage
+
+	/* Assign PPI to Non-Secure domain */
+	msr(ICC_PPI_DOMAINR0_EL3, val);
+	isb();
+}
+
+void gic_secure_init(void)
+{
+	/*
+	 * If GICv5 is not available, skip initialisation. The OS will probably
+	 * fail with a warning, but this should be easier to debug than a
+	 * failure within the boot wrapper.
+	 */
+	if (!has_gicv5_sysreg())
+		return;
+
+	if (this_cpu_logical_id() == 0) {
+		gic_iwb_init();
+		gic_irs_init();
+	}
+
+	gic_ppi_init();
+
+	return;
+}
+
diff --git a/configure.ac b/configure.ac
index 6f486c4..f4faff7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -141,18 +141,19 @@ AC_SUBST([XEN_CMDLINE], [$X_CMDLINE])
 
 
 AC_ARG_WITH([gic],
-  AS_HELP_STRING([--with-gic={v2|v3}], [select GIC version]),
+  AS_HELP_STRING([--with-gic={v2|v3|v5}], [select GIC version]),
   [GIC_VERSION=$withval],
   [GIC_VERSION=v2])
 
 AS_CASE([$GIC_VERSION],
-  [v2|v3], [],
-  [AC_MSG_ERROR([Invalid GIC version: $GIC_VERSION (use v2 or v3)])])
+  [v2|v3|v5], [],
+  [AC_MSG_ERROR([Invalid GIC version: $GIC_VERSION (use v2, v3, or v5)])])
 
 AC_SUBST([GIC_VERSION], [$GIC_VERSION])
 
 AM_CONDITIONAL([GICV2], [test "x$GIC_VERSION" = "xv2"])
 AM_CONDITIONAL([GICV3], [test "x$GIC_VERSION" = "xv3"])
+AM_CONDITIONAL([GICV5], [test "x$GIC_VERSION" = "xv5"])
 
 
 # Ensure that we have all the needed programs
diff --git a/scripts/FDT.pm b/scripts/FDT.pm
index 9adf70b..3f49ba6 100755
--- a/scripts/FDT.pm
+++ b/scripts/FDT.pm
@@ -322,6 +322,22 @@ sub get_num_reg_cells
 	return ($ac, $sc);
 }
 
+sub get_regname_idx
+{
+    my $self = shift;
+    my $regname = shift;
+
+    my $prop = $self->get_property("reg-names");
+
+    return undef if (not defined($prop));
+
+    my @names = $prop->read_strings();
+
+    my ($idx) = grep { $names[$_] eq $regname } 0 .. $#names;
+
+    return $idx;
+}
+
 sub translate_address
 {
 	my $self = shift;
diff --git a/scripts/findbase-by-regname.pl b/scripts/findbase-by-regname.pl
new file mode 100755
index 0000000..49cd0ce
--- /dev/null
+++ b/scripts/findbase-by-regname.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl -w
+# Find device register base addresses.
+#
+# Usage: ./$0 <DTB> <regname> <compatible ...>
+#
+# Copyright (C) 2026 ARM Limited. All rights reserved.
+#
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE.txt file.
+
+use warnings;
+use strict;
+
+use FDT;
+
+my $filename = shift;
+die("No filename provided") unless defined($filename);
+
+my $regname = shift;
+die("no reg regname provided") unless defined($regname);
+
+my @compats = shift;
+
+open (my $fh, "<:raw", $filename) or die("Unable to open file '$filename'");
+
+my $fdt = FDT->parse($fh) or die("Unable to parse DTB");
+
+my $root = $fdt->get_root();
+
+my @devs = ();
+for my $compat (@compats) {
+	push @devs, $root->find_compatible($compat);
+}
+
+# We only care about finding the first matching device
+my $dev = shift @devs;
+die("No matching devices found") if (not defined($dev));
+
+my $idx = $dev->get_regname_idx($regname);
+die("Cannot find reg name $regname") if (not defined($idx));
+my ($addr, $size) = $dev->get_translated_reg($idx);
+die("Cannot find reg entry $idx") if (not defined($addr) or not defined($size));
+
+printf("0x%016x\n", $addr);
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [BOOTWRAPPER PATCH v3 2/2] Add support for GICv5
  2026-05-29  9:50 ` [BOOTWRAPPER PATCH v3 2/2] Add support for GICv5 Vladimir Murzin
@ 2026-05-29 15:34   ` Sascha Bischoff
  2026-05-29 15:52     ` Vladimir Murzin
  0 siblings, 1 reply; 5+ messages in thread
From: Sascha Bischoff @ 2026-05-29 15:34 UTC (permalink / raw)
  To: linux-arm-kernel@lists•infradead.org, Vladimir Murzin
  Cc: maz@kernel•org, Joey Gouly, Mark Rutland, nd

Hi Vladimir,

Thanks for the rapid turn-around. This is now looking good to me. I've
tested things again and have confirmed that they're working for me.

One small thing to point out is that I got this when applying:

Applying: Add support for GICv5
.git/rebase-apply/patch:203: new blank line at EOF.
+
warning: 1 line adds whitespace errors.

It looks like you have an extra newline, which must have been there
previously too. Sorry for missing it. In either case, this looks to be
in a good state now:

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm•com>

Thanks,
Sascha

On Fri, 2026-05-29 at 10:50 +0100, Vladimir Murzin wrote:
> Performs the minimal initialization required for GICv5 support. GICv5
> support can be requested with --with-gic=v5.
> 
> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm•com>
> Tested-by: Sascha Bischoff <sascha.bischoff@arm•com>
> ---
>  Makefile.am                    |   7 ++
>  arch/aarch64/include/asm/cpu.h |  11 +++
>  common/gic-v5.c                | 132
> +++++++++++++++++++++++++++++++++
>  configure.ac                   |   7 +-
>  scripts/FDT.pm                 |  16 ++++
>  scripts/findbase-by-regname.pl |  44 +++++++++++
>  6 files changed, 214 insertions(+), 3 deletions(-)
>  create mode 100644 common/gic-v5.c
>  create mode 100755 scripts/findbase-by-regname.pl
> 
> diff --git a/Makefile.am b/Makefile.am
> index 2710494..aacd639 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -82,6 +82,13 @@ PSCI_NODE	:=
>  CPU_NODES	:=
>  endif
>  
> +if GICV5
> +GIC_IRS_BASE	:= $(shell perl -I $(SCRIPT_DIR)
> $(SCRIPT_DIR)/findbase-by-regname.pl $(KERNEL_DTB) "el3-config"
> 'arm,gic-v5-irs')
> +GIC_IWB_BASE	:= $(shell perl -I $(SCRIPT_DIR)
> $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,gic-v5-iwb')
> +DEFINES		+= -DGIC_IRS_BASE=$(GIC_IRS_BASE)
> +DEFINES		+= -DGIC_IWB_BASE=$(GIC_IWB_BASE)
> +endif
> +
>  if GICV3
>  GIC_DIST_BASE	:= $(shell perl -I $(SCRIPT_DIR)
> $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,gic-v3')
>  GIC_RDIST_BASE	:= $(shell perl -I $(SCRIPT_DIR)
> $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 1 'arm,gic-v3')
> diff --git a/arch/aarch64/include/asm/cpu.h
> b/arch/aarch64/include/asm/cpu.h
> index ac50474..af4191c 100644
> --- a/arch/aarch64/include/asm/cpu.h
> +++ b/arch/aarch64/include/asm/cpu.h
> @@ -128,6 +128,7 @@
>  #define ID_AA64PFR1_EL1_THE		BITS(51, 48)
>  
>  #define ID_AA64PFR2_EL1			s3_0_c0_c4_2
> +#define ID_AA64PFR2_EL1_GCIE		BITS(15, 12)
>  #define ID_AA64PFR2_EL1_FPMR		BITS(35, 32)
>  
>  #define ID_AA64SMFR0_EL1		s3_0_c0_c4_5
> @@ -169,6 +170,11 @@
>  #define ICC_CTLR_EL3		S3_6_C12_C12_4
>  #define ICC_PMR_EL1		S3_0_C4_C6_0
>  
> +#define ICC_PPI_DOMAINR0_EL3	S3_6_C12_C8_4
> +#define ICC_PPI_DOMAINR1_EL3	S3_6_C12_C8_5
> +#define ICC_PPI_DOMAINR2_EL3	S3_6_C12_C8_6
> +#define ICC_PPI_DOMAINR3_EL3	S3_6_C12_C8_7
> +
>  #define VSTCR_EL2		s3_4_c2_c6_2
>  #define VSCTLR_EL2		s3_4_c2_c0_0
>  
> @@ -245,6 +251,11 @@ static inline int has_gicv3_sysreg(void)
>  	return !!mrs_field(ID_AA64PFR0_EL1, GIC);
>  }
>  
> +static inline int has_gicv5_sysreg(void)
> +{
> +	return !!mrs_field(ID_AA64PFR2_EL1, GCIE);
> +}
> +
>  #endif /* !__ASSEMBLY__ */
>  
>  #endif
> diff --git a/common/gic-v5.c b/common/gic-v5.c
> new file mode 100644
> index 0000000..49b7b0e
> --- /dev/null
> +++ b/common/gic-v5.c
> @@ -0,0 +1,132 @@
> +/*
> + * gic-v5.c
> + *
> + * Copyright (C) 2025 ARM Limited. All rights reserved.
> + *
> + * Use of this source code is governed by a BSD-style license that
> can be
> + * found in the LICENSE.txt file.
> + */
> +
> +#include <stdint.h>
> +
> +#include <cpu.h>
> +#include <gic.h>
> +#include <asm/io.h>
> +
> +#define IWB_IDR0			0x0
> +#define IWB_IDR0_IW_RANGE_SHIFT		0x0
> +#define IWB_IDR0_IW_RANGE_MASK		0x7ff
> +
> +#define IWB_CR0				0x80
> +#define IWB_CR0_IWBEN			(1 << 0)
> +#define IWB_CR0_IDLE			(1 << 1)
> +
> +#define IWB_WENABLE_STATUSR		0xc0
> +#define IWB_WENABLE_STATUSR_IDLE	(1 << 0)
> +
> +#define IWB_WDOMAIN_STATUSR		0xc4
> +#define IWB_WDOMAIN_STATUSR_IDLE	(1 << 0)
> +
> +#define IWB_WENABLER			0x2000
> +#define IWB_WDOMAINR			0x8000
> +
> +#define IRS_IDR6			0x0018
> +#define IRS_IDR6_SPI_IRS_RANGE_MASK	0x1ffffff
> +
> +#define IRS_IDR7			0x001c
> +#define IRS_IDR7_SPI_BASE_MASK		0xffffff
> +
> +#define IRS_SPI_SELR			0x108
> +#define IRS_SPI_DOMAINR			0x10c
> +
> +#define IRS_SPI_STATUSR			0x0118
> +#define IRS_SPI_STATUSR_IDLE		(1 << 0)
> +
> +static void gic_iwb_init(void) {
> +	void *iwb_ptr = (void *)GIC_IWB_BASE;
> +	unsigned int num;
> +	unsigned int i;
> +
> +	/* Get number of implemented wire control registers */
> +	num = ((raw_readl(iwb_ptr + IWB_IDR0) >>
> IWB_IDR0_IW_RANGE_SHIFT) & IWB_IDR0_IW_RANGE_MASK) + 1;
> +
> +	/* Disable all wires */
> +	for (i = 0; i < num; i++)
> +		raw_writel(0, iwb_ptr + IWB_WENABLER + i * 4);
> +
> +	while (!(raw_readl(iwb_ptr + IWB_WENABLE_STATUSR) &
> IWB_WENABLE_STATUSR_IDLE));
> +
> +	/* Assign all wires to Non-Secure domain */
> +	for (i = 0; i < num * 2; i++)
> +		raw_writel(0x55555555, iwb_ptr + IWB_WDOMAINR + i *
> 4);
> +
> +	while (!(raw_readl(iwb_ptr + IWB_WDOMAIN_STATUSR) &
> IWB_WDOMAIN_STATUSR_IDLE));
> +
> +	/* Enable IWB */
> +	raw_writel(IWB_CR0_IWBEN, iwb_ptr + IWB_CR0);
> +
> +	while (!(raw_readl(iwb_ptr + IWB_CR0) & IWB_CR0_IDLE));
> +}
> +
> +static void gic_irs_init(void) {
> +	void *irs_ptr = (void *)GIC_IRS_BASE;
> +	unsigned int range;
> +	unsigned int base;
> +	unsigned int i;
> +
> +	/* Get the range of implemented SPIs */
> +	base = raw_readl(irs_ptr + IRS_IDR7) &
> IRS_IDR7_SPI_BASE_MASK;
> +	range = raw_readl(irs_ptr + IRS_IDR6) &
> IRS_IDR6_SPI_IRS_RANGE_MASK;
> +
> +	for (i = base; i < base + range; i++) {
> +		/* Select SPI */
> +		raw_writel(i, irs_ptr + IRS_SPI_SELR);
> +		while (!(raw_readl(irs_ptr + IRS_SPI_STATUSR) &
> IRS_SPI_STATUSR_IDLE));
> +
> +		/* Assign SPI to Non-Secure domain */
> +		raw_writel(1, irs_ptr + IRS_SPI_DOMAINR);
> +		while (!(raw_readl(irs_ptr + IRS_SPI_STATUSR) &
> IRS_SPI_STATUSR_IDLE));
> +	}
> +}
> +
> +static void gic_ppi_init(void) {
> +	uint64_t val = 0;
> +
> +	val |= 1UL << (2 * 31); // Trace Buffer Unit
> +	val |= 1UL << (2 * 30); // EL1 Physical Timer
> +	val |= 1UL << (2 * 28); // Non-secure EL2 Virtual Timer
> +	val |= 1UL << (2 * 27); // EL1 Virtual Timer
> +	val |= 1UL << (2 * 26); // Non-secure EL2 Physical Timer
> +	val |= 1UL << (2 * 25); // GIC maintenance interrupt
> +	val |= 1UL << (2 * 24); // Generic CTI interrupt trigger
> event
> +	val |= 1UL << (2 * 23); // PMU overflow interrupt request
> +	val |= 1UL << (2 * 22); // Debug communication channel
> +	val |= 1UL << (2 * 21); // Profiling Buffer management
> interrupt request
> +	val |= 1UL << (2 * 15); // Hardware accelerator for cleaning
> Dirty state interrupt
> +	val |= 1UL << (2 * 3);  // Reserved for software usage
> +
> +	/* Assign PPI to Non-Secure domain */
> +	msr(ICC_PPI_DOMAINR0_EL3, val);
> +	isb();
> +}
> +
> +void gic_secure_init(void)
> +{
> +	/*
> +	 * If GICv5 is not available, skip initialisation. The OS
> will probably
> +	 * fail with a warning, but this should be easier to debug
> than a
> +	 * failure within the boot wrapper.
> +	 */
> +	if (!has_gicv5_sysreg())
> +		return;
> +
> +	if (this_cpu_logical_id() == 0) {
> +		gic_iwb_init();
> +		gic_irs_init();
> +	}
> +
> +	gic_ppi_init();
> +
> +	return;
> +}
> +
> diff --git a/configure.ac b/configure.ac
> index 6f486c4..f4faff7 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -141,18 +141,19 @@ AC_SUBST([XEN_CMDLINE], [$X_CMDLINE])
>  
>  
>  AC_ARG_WITH([gic],
> -  AS_HELP_STRING([--with-gic={v2|v3}], [select GIC version]),
> +  AS_HELP_STRING([--with-gic={v2|v3|v5}], [select GIC version]),
>    [GIC_VERSION=$withval],
>    [GIC_VERSION=v2])
>  
>  AS_CASE([$GIC_VERSION],
> -  [v2|v3], [],
> -  [AC_MSG_ERROR([Invalid GIC version: $GIC_VERSION (use v2 or
> v3)])])
> +  [v2|v3|v5], [],
> +  [AC_MSG_ERROR([Invalid GIC version: $GIC_VERSION (use v2, v3, or
> v5)])])
>  
>  AC_SUBST([GIC_VERSION], [$GIC_VERSION])
>  
>  AM_CONDITIONAL([GICV2], [test "x$GIC_VERSION" = "xv2"])
>  AM_CONDITIONAL([GICV3], [test "x$GIC_VERSION" = "xv3"])
> +AM_CONDITIONAL([GICV5], [test "x$GIC_VERSION" = "xv5"])
>  
>  
>  # Ensure that we have all the needed programs
> diff --git a/scripts/FDT.pm b/scripts/FDT.pm
> index 9adf70b..3f49ba6 100755
> --- a/scripts/FDT.pm
> +++ b/scripts/FDT.pm
> @@ -322,6 +322,22 @@ sub get_num_reg_cells
>  	return ($ac, $sc);
>  }
>  
> +sub get_regname_idx
> +{
> +    my $self = shift;
> +    my $regname = shift;
> +
> +    my $prop = $self->get_property("reg-names");
> +
> +    return undef if (not defined($prop));
> +
> +    my @names = $prop->read_strings();
> +
> +    my ($idx) = grep { $names[$_] eq $regname } 0 .. $#names;
> +
> +    return $idx;
> +}
> +
>  sub translate_address
>  {
>  	my $self = shift;
> diff --git a/scripts/findbase-by-regname.pl b/scripts/findbase-by-
> regname.pl
> new file mode 100755
> index 0000000..49cd0ce
> --- /dev/null
> +++ b/scripts/findbase-by-regname.pl
> @@ -0,0 +1,44 @@
> +#!/usr/bin/perl -w
> +# Find device register base addresses.
> +#
> +# Usage: ./$0 <DTB> <regname> <compatible ...>
> +#
> +# Copyright (C) 2026 ARM Limited. All rights reserved.
> +#
> +# Use of this source code is governed by a BSD-style license that
> can be
> +# found in the LICENSE.txt file.
> +
> +use warnings;
> +use strict;
> +
> +use FDT;
> +
> +my $filename = shift;
> +die("No filename provided") unless defined($filename);
> +
> +my $regname = shift;
> +die("no reg regname provided") unless defined($regname);
> +
> +my @compats = shift;
> +
> +open (my $fh, "<:raw", $filename) or die("Unable to open file
> '$filename'");
> +
> +my $fdt = FDT->parse($fh) or die("Unable to parse DTB");
> +
> +my $root = $fdt->get_root();
> +
> +my @devs = ();
> +for my $compat (@compats) {
> +	push @devs, $root->find_compatible($compat);
> +}
> +
> +# We only care about finding the first matching device
> +my $dev = shift @devs;
> +die("No matching devices found") if (not defined($dev));
> +
> +my $idx = $dev->get_regname_idx($regname);
> +die("Cannot find reg name $regname") if (not defined($idx));
> +my ($addr, $size) = $dev->get_translated_reg($idx);
> +die("Cannot find reg entry $idx") if (not defined($addr) or not
> defined($size));
> +
> +printf("0x%016x\n", $addr);


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [BOOTWRAPPER PATCH v3 2/2] Add support for GICv5
  2026-05-29 15:34   ` Sascha Bischoff
@ 2026-05-29 15:52     ` Vladimir Murzin
  0 siblings, 0 replies; 5+ messages in thread
From: Vladimir Murzin @ 2026-05-29 15:52 UTC (permalink / raw)
  To: Sascha Bischoff, linux-arm-kernel@lists•infradead.org
  Cc: maz@kernel•org, Joey Gouly, Mark Rutland, nd

Hi Sascha,

On 5/29/26 16:34, Sascha Bischoff wrote:
> Hi Vladimir,
> 
> Thanks for the rapid turn-around. This is now looking good to me. I've
> tested things again and have confirmed that they're working for me.
> 
> One small thing to point out is that I got this when applying:
> 
> Applying: Add support for GICv5
> .git/rebase-apply/patch:203: new blank line at EOF.
> +
> warning: 1 line adds whitespace errors.
> 
> It looks like you have an extra newline, which must have been there
> previously too. Sorry for missing it. In either case, this looks to be
> in a good state now:
> 
> Reviewed-by: Sascha Bischoff <sascha.bischoff@arm•com>
> 

Thanks for your time!

> Thanks,
> Sascha
> 
> On Fri, 2026-05-29 at 10:50 +0100, Vladimir Murzin wrote:
>> Performs the minimal initialization required for GICv5 support. GICv5
>> support can be requested with --with-gic=v5.
>>
>> Signed-off-by: Vladimir Murzin <vladimir.murzin@arm•com>
>> Tested-by: Sascha Bischoff <sascha.bischoff@arm•com>
>> ---
>>  Makefile.am                    |   7 ++
>>  arch/aarch64/include/asm/cpu.h |  11 +++
>>  common/gic-v5.c                | 132
>> +++++++++++++++++++++++++++++++++
>>  configure.ac                   |   7 +-
>>  scripts/FDT.pm                 |  16 ++++
>>  scripts/findbase-by-regname.pl |  44 +++++++++++
>>  6 files changed, 214 insertions(+), 3 deletions(-)
>>  create mode 100644 common/gic-v5.c
>>  create mode 100755 scripts/findbase-by-regname.pl
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index 2710494..aacd639 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -82,6 +82,13 @@ PSCI_NODE	:=
>>  CPU_NODES	:=
>>  endif
>>  
>> +if GICV5
>> +GIC_IRS_BASE	:= $(shell perl -I $(SCRIPT_DIR)
>> $(SCRIPT_DIR)/findbase-by-regname.pl $(KERNEL_DTB) "el3-config"
>> 'arm,gic-v5-irs')
>> +GIC_IWB_BASE	:= $(shell perl -I $(SCRIPT_DIR)
>> $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,gic-v5-iwb')
>> +DEFINES		+= -DGIC_IRS_BASE=$(GIC_IRS_BASE)
>> +DEFINES		+= -DGIC_IWB_BASE=$(GIC_IWB_BASE)
>> +endif
>> +
>>  if GICV3
>>  GIC_DIST_BASE	:= $(shell perl -I $(SCRIPT_DIR)
>> $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,gic-v3')
>>  GIC_RDIST_BASE	:= $(shell perl -I $(SCRIPT_DIR)
>> $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 1 'arm,gic-v3')
>> diff --git a/arch/aarch64/include/asm/cpu.h
>> b/arch/aarch64/include/asm/cpu.h
>> index ac50474..af4191c 100644
>> --- a/arch/aarch64/include/asm/cpu.h
>> +++ b/arch/aarch64/include/asm/cpu.h
>> @@ -128,6 +128,7 @@
>>  #define ID_AA64PFR1_EL1_THE		BITS(51, 48)
>>  
>>  #define ID_AA64PFR2_EL1			s3_0_c0_c4_2
>> +#define ID_AA64PFR2_EL1_GCIE		BITS(15, 12)
>>  #define ID_AA64PFR2_EL1_FPMR		BITS(35, 32)
>>  
>>  #define ID_AA64SMFR0_EL1		s3_0_c0_c4_5
>> @@ -169,6 +170,11 @@
>>  #define ICC_CTLR_EL3		S3_6_C12_C12_4
>>  #define ICC_PMR_EL1		S3_0_C4_C6_0
>>  
>> +#define ICC_PPI_DOMAINR0_EL3	S3_6_C12_C8_4
>> +#define ICC_PPI_DOMAINR1_EL3	S3_6_C12_C8_5
>> +#define ICC_PPI_DOMAINR2_EL3	S3_6_C12_C8_6
>> +#define ICC_PPI_DOMAINR3_EL3	S3_6_C12_C8_7
>> +
>>  #define VSTCR_EL2		s3_4_c2_c6_2
>>  #define VSCTLR_EL2		s3_4_c2_c0_0
>>  
>> @@ -245,6 +251,11 @@ static inline int has_gicv3_sysreg(void)
>>  	return !!mrs_field(ID_AA64PFR0_EL1, GIC);
>>  }
>>  
>> +static inline int has_gicv5_sysreg(void)
>> +{
>> +	return !!mrs_field(ID_AA64PFR2_EL1, GCIE);
>> +}
>> +
>>  #endif /* !__ASSEMBLY__ */
>>  
>>  #endif
>> diff --git a/common/gic-v5.c b/common/gic-v5.c
>> new file mode 100644
>> index 0000000..49b7b0e
>> --- /dev/null
>> +++ b/common/gic-v5.c
>> @@ -0,0 +1,132 @@
>> +/*
>> + * gic-v5.c
>> + *
>> + * Copyright (C) 2025 ARM Limited. All rights reserved.
>> + *
>> + * Use of this source code is governed by a BSD-style license that
>> can be
>> + * found in the LICENSE.txt file.
>> + */
>> +
>> +#include <stdint.h>
>> +
>> +#include <cpu.h>
>> +#include <gic.h>
>> +#include <asm/io.h>
>> +
>> +#define IWB_IDR0			0x0
>> +#define IWB_IDR0_IW_RANGE_SHIFT		0x0
>> +#define IWB_IDR0_IW_RANGE_MASK		0x7ff
>> +
>> +#define IWB_CR0				0x80
>> +#define IWB_CR0_IWBEN			(1 << 0)
>> +#define IWB_CR0_IDLE			(1 << 1)
>> +
>> +#define IWB_WENABLE_STATUSR		0xc0
>> +#define IWB_WENABLE_STATUSR_IDLE	(1 << 0)
>> +
>> +#define IWB_WDOMAIN_STATUSR		0xc4
>> +#define IWB_WDOMAIN_STATUSR_IDLE	(1 << 0)
>> +
>> +#define IWB_WENABLER			0x2000
>> +#define IWB_WDOMAINR			0x8000
>> +
>> +#define IRS_IDR6			0x0018
>> +#define IRS_IDR6_SPI_IRS_RANGE_MASK	0x1ffffff
>> +
>> +#define IRS_IDR7			0x001c
>> +#define IRS_IDR7_SPI_BASE_MASK		0xffffff
>> +
>> +#define IRS_SPI_SELR			0x108
>> +#define IRS_SPI_DOMAINR			0x10c
>> +
>> +#define IRS_SPI_STATUSR			0x0118
>> +#define IRS_SPI_STATUSR_IDLE		(1 << 0)
>> +
>> +static void gic_iwb_init(void) {
>> +	void *iwb_ptr = (void *)GIC_IWB_BASE;
>> +	unsigned int num;
>> +	unsigned int i;
>> +
>> +	/* Get number of implemented wire control registers */
>> +	num = ((raw_readl(iwb_ptr + IWB_IDR0) >>
>> IWB_IDR0_IW_RANGE_SHIFT) & IWB_IDR0_IW_RANGE_MASK) + 1;
>> +
>> +	/* Disable all wires */
>> +	for (i = 0; i < num; i++)
>> +		raw_writel(0, iwb_ptr + IWB_WENABLER + i * 4);
>> +
>> +	while (!(raw_readl(iwb_ptr + IWB_WENABLE_STATUSR) &
>> IWB_WENABLE_STATUSR_IDLE));
>> +
>> +	/* Assign all wires to Non-Secure domain */
>> +	for (i = 0; i < num * 2; i++)
>> +		raw_writel(0x55555555, iwb_ptr + IWB_WDOMAINR + i *
>> 4);
>> +
>> +	while (!(raw_readl(iwb_ptr + IWB_WDOMAIN_STATUSR) &
>> IWB_WDOMAIN_STATUSR_IDLE));
>> +
>> +	/* Enable IWB */
>> +	raw_writel(IWB_CR0_IWBEN, iwb_ptr + IWB_CR0);
>> +
>> +	while (!(raw_readl(iwb_ptr + IWB_CR0) & IWB_CR0_IDLE));
>> +}
>> +
>> +static void gic_irs_init(void) {
>> +	void *irs_ptr = (void *)GIC_IRS_BASE;
>> +	unsigned int range;
>> +	unsigned int base;
>> +	unsigned int i;
>> +
>> +	/* Get the range of implemented SPIs */
>> +	base = raw_readl(irs_ptr + IRS_IDR7) &
>> IRS_IDR7_SPI_BASE_MASK;
>> +	range = raw_readl(irs_ptr + IRS_IDR6) &
>> IRS_IDR6_SPI_IRS_RANGE_MASK;
>> +
>> +	for (i = base; i < base + range; i++) {
>> +		/* Select SPI */
>> +		raw_writel(i, irs_ptr + IRS_SPI_SELR);
>> +		while (!(raw_readl(irs_ptr + IRS_SPI_STATUSR) &
>> IRS_SPI_STATUSR_IDLE));
>> +
>> +		/* Assign SPI to Non-Secure domain */
>> +		raw_writel(1, irs_ptr + IRS_SPI_DOMAINR);
>> +		while (!(raw_readl(irs_ptr + IRS_SPI_STATUSR) &
>> IRS_SPI_STATUSR_IDLE));
>> +	}
>> +}
>> +
>> +static void gic_ppi_init(void) {
>> +	uint64_t val = 0;
>> +
>> +	val |= 1UL << (2 * 31); // Trace Buffer Unit
>> +	val |= 1UL << (2 * 30); // EL1 Physical Timer
>> +	val |= 1UL << (2 * 28); // Non-secure EL2 Virtual Timer
>> +	val |= 1UL << (2 * 27); // EL1 Virtual Timer
>> +	val |= 1UL << (2 * 26); // Non-secure EL2 Physical Timer
>> +	val |= 1UL << (2 * 25); // GIC maintenance interrupt
>> +	val |= 1UL << (2 * 24); // Generic CTI interrupt trigger
>> event
>> +	val |= 1UL << (2 * 23); // PMU overflow interrupt request
>> +	val |= 1UL << (2 * 22); // Debug communication channel
>> +	val |= 1UL << (2 * 21); // Profiling Buffer management
>> interrupt request
>> +	val |= 1UL << (2 * 15); // Hardware accelerator for cleaning
>> Dirty state interrupt
>> +	val |= 1UL << (2 * 3);  // Reserved for software usage
>> +
>> +	/* Assign PPI to Non-Secure domain */
>> +	msr(ICC_PPI_DOMAINR0_EL3, val);
>> +	isb();
>> +}
>> +
>> +void gic_secure_init(void)
>> +{
>> +	/*
>> +	 * If GICv5 is not available, skip initialisation. The OS
>> will probably
>> +	 * fail with a warning, but this should be easier to debug
>> than a
>> +	 * failure within the boot wrapper.
>> +	 */
>> +	if (!has_gicv5_sysreg())
>> +		return;
>> +
>> +	if (this_cpu_logical_id() == 0) {
>> +		gic_iwb_init();
>> +		gic_irs_init();
>> +	}
>> +
>> +	gic_ppi_init();
>> +
>> +	return;
>> +}
>> +

It is where new blank line has been lurking :) Fixed locally.

I'll wait some time before sending v4 in case someone wants to have
a look or give it a try ;)

Cheers
Vladimir



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-05-29 15:53 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-29  9:50 [BOOTWRAPPER PATCH v3 0/2] Support GICv5 Vladimir Murzin
2026-05-29  9:50 ` [BOOTWRAPPER PATCH v3 1/2] Introduce --with-gic option Vladimir Murzin
2026-05-29  9:50 ` [BOOTWRAPPER PATCH v3 2/2] Add support for GICv5 Vladimir Murzin
2026-05-29 15:34   ` Sascha Bischoff
2026-05-29 15:52     ` Vladimir Murzin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox