git: 1ecf7d5b3831 - main - arm64: vmm: Split out VGIC register handling to a common file

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Wed, 26 Aug 2026 11:33:28 UTC
The branch main has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=1ecf7d5b38319d110d0f5bff26d6f8a9c1042cf4

commit 1ecf7d5b38319d110d0f5bff26d6f8a9c1042cf4
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2026-05-13 10:41:17 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2026-08-26 11:17:18 +0000

    arm64: vmm: Split out VGIC register handling to a common file
    
    Reviewed by:    Sarah Walker <sarah.walker2@arm.com>
    Sponsored by:   Arm Ltd
---
 sys/arm64/vmm/io/vgic.c          |  79 +++++++++++++++++++++-
 sys/arm64/vmm/io/vgic_internal.h |  49 ++++++++++++++
 sys/arm64/vmm/io/vgic_v3.c       | 137 +++------------------------------------
 3 files changed, 136 insertions(+), 129 deletions(-)

diff --git a/sys/arm64/vmm/io/vgic.c b/sys/arm64/vmm/io/vgic.c
index ee841292ed33..582280823f1e 100644
--- a/sys/arm64/vmm/io/vgic.c
+++ b/sys/arm64/vmm/io/vgic.c
@@ -1,7 +1,7 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause
  *
- * Copyright (c) 2023 Arm Ltd
+ * Copyright (c) 2023,2026 Arm Ltd
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,9 +32,86 @@
 
 #include "vgic.h"
 #include "vgic_if.h"
+#include "vgic_internal.h"
 
 device_t vgic_dev;
 
+/* Common register read-only/write-ignored helpers */
+void
+vgic_zero_read(struct hypctx *hypctx, u_int reg, uint64_t *rval,
+    void *arg)
+{
+	*rval = 0;
+}
+
+void
+vgic_ignore_write(struct hypctx *hypctx, u_int reg, u_int offset, u_int size,
+    uint64_t wval, void *arg)
+{
+	/* Nothing to do */
+}
+
+bool
+vgic_register_read(struct hypctx *hypctx, struct vgic_register *reg_list,
+    u_int reg_list_size, u_int reg, u_int size, uint64_t *rval, void *arg)
+{
+	u_int i, offset;
+
+	for (i = 0; i < reg_list_size; i++) {
+		if (reg_list[i].start <= reg && reg_list[i].end >= reg + size) {
+			offset = reg & (reg_list[i].size - 1);
+			reg -= offset;
+			if ((reg_list[i].flags & size) != 0) {
+				reg_list[i].read(hypctx, reg, rval, NULL);
+
+				/* Move the bits into the correct place */
+				*rval >>= (offset * 8);
+				if (size < 8) {
+					*rval &= (1ul << (size * 8)) - 1;
+				}
+			} else {
+				/*
+				 * The access is an invalid size. Section
+				 * 12.1.3 "GIC memory-mapped register access"
+				 * of the GICv3 and GICv4 spec issue H
+				 * (IHI0069) lists the options. For a read
+				 * the controller returns unknown data, in
+				 * this case it is zero.
+				 */
+				*rval = 0;
+			}
+			return (true);
+		}
+	}
+	return (false);
+}
+
+bool
+vgic_register_write(struct hypctx *hypctx, struct vgic_register *reg_list,
+    u_int reg_list_size, u_int reg, u_int size, uint64_t wval, void *arg)
+{
+	u_int i, offset;
+
+	for (i = 0; i < reg_list_size; i++) {
+		if (reg_list[i].start <= reg && reg_list[i].end >= reg + size) {
+			offset = reg & (reg_list[i].size - 1);
+			reg -= offset;
+			if ((reg_list[i].flags & size) != 0) {
+				reg_list[i].write(hypctx, reg, offset,
+				    size, wval, NULL);
+			} else {
+				/*
+				 * See the comment in vgic_register_read.
+				 * For writes the controller ignores the
+				 * operation.
+				 */
+			}
+			return (true);
+		}
+	}
+	return (false);
+}
+
 bool
 vgic_present(void)
 {
diff --git a/sys/arm64/vmm/io/vgic_internal.h b/sys/arm64/vmm/io/vgic_internal.h
index 2f5cfc7c0891..2f47aef50724 100644
--- a/sys/arm64/vmm/io/vgic_internal.h
+++ b/sys/arm64/vmm/io/vgic_internal.h
@@ -80,4 +80,53 @@ struct vgic_v3_cpu {
 	u_int		ich_lr_used;
 };
 
+typedef void (register_read)(struct hypctx *, u_int, uint64_t *, void *);
+typedef void (register_write)(struct hypctx *, u_int, u_int, u_int,
+    uint64_t, void *);
+
+register_read vgic_zero_read;
+register_write vgic_ignore_write;
+
+#define	VGIC_8_BIT	(1 << 0)
+/* (1 << 1) is reserved for 16 bit accesses */
+#define	VGIC_32_BIT	(1 << 2)
+#define	VGIC_64_BIT	(1 << 3)
+
+struct vgic_register {
+	u_int start;	/* Start within a memory region */
+	u_int end;
+	u_int size;
+	u_int flags;
+	register_read *read;
+	register_write *write;
+};
+
+#define	VGIC_REGISTER_RANGE(reg_start, reg_end, reg_size, reg_flags, readf, \
+    writef)								\
+{									\
+	.start = (reg_start),						\
+	.end = (reg_end),						\
+	.size = (reg_size),						\
+	.flags = (reg_flags),						\
+	.read = (readf),						\
+	.write = (writef),						\
+}
+
+#define	VGIC_REGISTER_RANGE_RAZ_WI(reg_start, reg_end, reg_size, reg_flags) \
+	VGIC_REGISTER_RANGE(reg_start, reg_end, reg_size, reg_flags,	\
+	    vgic_zero_read, vgic_ignore_write)
+
+#define	VGIC_REGISTER(start_addr, reg_size, reg_flags, readf, writef)	\
+	VGIC_REGISTER_RANGE(start_addr, (start_addr) + (reg_size),	\
+	    reg_size, reg_flags, readf, writef)
+
+#define	VGIC_REGISTER_RAZ_WI(start_addr, reg_size, reg_flags)		\
+	VGIC_REGISTER_RANGE_RAZ_WI(start_addr,				\
+	    (start_addr) + (reg_size), reg_size, reg_flags)
+
+bool vgic_register_read(struct hypctx *, struct vgic_register *, u_int, u_int,
+    u_int, uint64_t *, void *);
+bool vgic_register_write(struct hypctx *, struct vgic_register *, u_int, u_int,
+    u_int, uint64_t, void *);
+
 #endif /* _VGIC_INTERNAL_H_ */
diff --git a/sys/arm64/vmm/io/vgic_v3.c b/sys/arm64/vmm/io/vgic_v3.c
index 763267a2a3c8..ff7a2a9a761f 100644
--- a/sys/arm64/vmm/io/vgic_v3.c
+++ b/sys/arm64/vmm/io/vgic_v3.c
@@ -107,50 +107,7 @@ static int vgic_v3_max_cpu_count(device_t dev, struct hyp *hyp);
 #define	INJECT_IRQ(hyp, vcpuid, irqid, level)			\
     vgic_v3_inject_irq(NULL, (hyp), (vcpuid), (irqid), (level))
 
-typedef void (register_read)(struct hypctx *, u_int, uint64_t *, void *);
-typedef void (register_write)(struct hypctx *, u_int, u_int, u_int,
-    uint64_t, void *);
-
-#define	VGIC_8_BIT	(1 << 0)
-/* (1 << 1) is reserved for 16 bit accesses */
-#define	VGIC_32_BIT	(1 << 2)
-#define	VGIC_64_BIT	(1 << 3)
-
-struct vgic_register {
-	u_int start;	/* Start within a memory region */
-	u_int end;
-	u_int size;
-	u_int flags;
-	register_read *read;
-	register_write *write;
-};
-
-#define	VGIC_REGISTER_RANGE(reg_start, reg_end, reg_size, reg_flags, readf, \
-    writef)								\
-{									\
-	.start = (reg_start),						\
-	.end = (reg_end),						\
-	.size = (reg_size),						\
-	.flags = (reg_flags),						\
-	.read = (readf),						\
-	.write = (writef),						\
-}
-
-#define	VGIC_REGISTER_RANGE_RAZ_WI(reg_start, reg_end, reg_size, reg_flags) \
-	VGIC_REGISTER_RANGE(reg_start, reg_end, reg_size, reg_flags,	\
-	    gic_zero_read, gic_ignore_write)
-
-#define	VGIC_REGISTER(start_addr, reg_size, reg_flags, readf, writef)	\
-	VGIC_REGISTER_RANGE(start_addr, (start_addr) + (reg_size),	\
-	    reg_size, reg_flags, readf, writef)
-
-#define	VGIC_REGISTER_RAZ_WI(start_addr, reg_size, reg_flags)		\
-	VGIC_REGISTER_RANGE_RAZ_WI(start_addr,				\
-	    (start_addr) + (reg_size), reg_size, reg_flags)
-
 static register_read gic_pidr2_read;
-static register_read gic_zero_read;
-static register_write gic_ignore_write;
 
 /* GICD_CTLR */
 static register_read dist_ctlr_read;
@@ -203,13 +160,13 @@ static struct vgic_register dist_registers[] = {
 	VGIC_REGISTER(GICD_CTLR, 4, VGIC_32_BIT, dist_ctlr_read,
 	    dist_ctlr_write),
 	VGIC_REGISTER(GICD_TYPER, 4, VGIC_32_BIT, dist_typer_read,
-	    gic_ignore_write),
+	    vgic_ignore_write),
 	VGIC_REGISTER(GICD_IIDR, 4, VGIC_32_BIT, dist_iidr_read,
-	    gic_ignore_write),
+	    vgic_ignore_write),
 	VGIC_REGISTER_RAZ_WI(GICD_STATUSR, 4, VGIC_32_BIT),
-	VGIC_REGISTER(GICD_SETSPI_NSR, 4, VGIC_32_BIT, gic_zero_read,
+	VGIC_REGISTER(GICD_SETSPI_NSR, 4, VGIC_32_BIT, vgic_zero_read,
 	    dist_setclrspi_nsr_write),
-	VGIC_REGISTER(GICD_CLRSPI_NSR, 4, VGIC_32_BIT, gic_zero_read,
+	VGIC_REGISTER(GICD_CLRSPI_NSR, 4, VGIC_32_BIT, vgic_zero_read,
 	    dist_setclrspi_nsr_write),
 	VGIC_REGISTER_RAZ_WI(GICD_SETSPI_SR, 4, VGIC_32_BIT),
 	VGIC_REGISTER_RAZ_WI(GICD_CLRSPI_SR, 4, VGIC_32_BIT),
@@ -273,7 +230,7 @@ static struct vgic_register dist_registers[] = {
 
 	VGIC_REGISTER_RANGE_RAZ_WI(GICD_PIDR4, GICD_PIDR2, 4, VGIC_32_BIT),
 	VGIC_REGISTER(GICD_PIDR2, 4, VGIC_32_BIT, gic_pidr2_read,
-	    gic_ignore_write),
+	    vgic_ignore_write),
 	VGIC_REGISTER_RANGE_RAZ_WI(GICD_PIDR2 + 4, GICD_SIZE, 4, VGIC_32_BIT),
 };
 
@@ -295,11 +252,11 @@ static register_read redist_typer_read;
 
 static struct vgic_register redist_rd_registers[] = {
 	VGIC_REGISTER(GICR_CTLR, 4, VGIC_32_BIT, redist_ctlr_read,
-	    gic_ignore_write),
+	    vgic_ignore_write),
 	VGIC_REGISTER(GICR_IIDR, 4, VGIC_32_BIT, redist_iidr_read,
-	    gic_ignore_write),
+	    vgic_ignore_write),
 	VGIC_REGISTER(GICR_TYPER, 8, VGIC_64_BIT | VGIC_32_BIT,
-	    redist_typer_read, gic_ignore_write),
+	    redist_typer_read, vgic_ignore_write),
 	VGIC_REGISTER_RAZ_WI(GICR_STATUSR, 4, VGIC_32_BIT),
 	VGIC_REGISTER_RAZ_WI(GICR_WAKER, 4, VGIC_32_BIT),
 	VGIC_REGISTER_RAZ_WI(GICR_SETLPIR, 8, VGIC_64_BIT | VGIC_32_BIT),
@@ -313,7 +270,7 @@ static struct vgic_register redist_rd_registers[] = {
 	/* These are identical to the dist registers */
 	VGIC_REGISTER_RANGE_RAZ_WI(GICD_PIDR4, GICD_PIDR2, 4, VGIC_32_BIT),
 	VGIC_REGISTER(GICD_PIDR2, 4, VGIC_32_BIT, gic_pidr2_read,
-	    gic_ignore_write),
+	    vgic_ignore_write),
 	VGIC_REGISTER_RANGE_RAZ_WI(GICD_PIDR2 + 4, GICD_SIZE, 4,
 	    VGIC_32_BIT),
 };
@@ -597,21 +554,6 @@ gic_pidr2_read(struct hypctx *hypctx, u_int reg, uint64_t *rval,
 	*rval = GICR_PIDR2_ARCH_GICv3 << GICR_PIDR2_ARCH_SHIFT;
 }
 
-/* Common read-only/write-ignored helpers */
-static void
-gic_zero_read(struct hypctx *hypctx, u_int reg, uint64_t *rval,
-    void *arg)
-{
-	*rval = 0;
-}
-
-static void
-gic_ignore_write(struct hypctx *hypctx, u_int reg, u_int offset, u_int size,
-    uint64_t wval, void *arg)
-{
-	/* Nothing to do */
-}
-
 static uint64_t
 read_enabler(struct hypctx *hypctx, int n)
 {
@@ -1262,67 +1204,6 @@ dist_irouter_write(struct hypctx *hypctx, u_int reg, u_int offset, u_int size,
 	write_route(hypctx, n, wval, offset, size);
 }
 
-static bool
-vgic_register_read(struct hypctx *hypctx, struct vgic_register *reg_list,
-    u_int reg_list_size, u_int reg, u_int size, uint64_t *rval, void *arg)
-{
-	u_int i, offset;
-
-	for (i = 0; i < reg_list_size; i++) {
-		if (reg_list[i].start <= reg && reg_list[i].end >= reg + size) {
-			offset = reg & (reg_list[i].size - 1);
-			reg -= offset;
-			if ((reg_list[i].flags & size) != 0) {
-				reg_list[i].read(hypctx, reg, rval, NULL);
-
-				/* Move the bits into the correct place */
-				*rval >>= (offset * 8);
-				if (size < 8) {
-					*rval &= (1ul << (size * 8)) - 1;
-				}
-			} else {
-				/*
-				 * The access is an invalid size. Section
-				 * 12.1.3 "GIC memory-mapped register access"
-				 * of the GICv3 and GICv4 spec issue H
-				 * (IHI0069) lists the options. For a read
-				 * the controller returns unknown data, in
-				 * this case it is zero.
-				 */
-				*rval = 0;
-			}
-			return (true);
-		}
-	}
-	return (false);
-}
-
-static bool
-vgic_register_write(struct hypctx *hypctx, struct vgic_register *reg_list,
-    u_int reg_list_size, u_int reg, u_int size, uint64_t wval, void *arg)
-{
-	u_int i, offset;
-
-	for (i = 0; i < reg_list_size; i++) {
-		if (reg_list[i].start <= reg && reg_list[i].end >= reg + size) {
-			offset = reg & (reg_list[i].size - 1);
-			reg -= offset;
-			if ((reg_list[i].flags & size) != 0) {
-				reg_list[i].write(hypctx, reg, offset,
-				    size, wval, NULL);
-			} else {
-				/*
-				 * See the comment in vgic_register_read.
-				 * For writes the controller ignores the
-				 * operation.
-				 */
-			}
-			return (true);
-		}
-	}
-	return (false);
-}
-
 static int
 dist_read(struct vcpu *vcpu, uint64_t fault_ipa, uint64_t *rval,
     int size, void *arg)