git: 1ecf7d5b3831 - main - arm64: vmm: Split out VGIC register handling to a common file
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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)