The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=1ecf7d5b38319d110d0f5bff26d6f8a9c1042cf4
commit 1ecf7d5b38319d110d0f5bff26d6f8a9c1042cf4 Author: Andrew Turner <[email protected]> AuthorDate: 2026-05-13 10:41:17 +0000 Commit: Andrew Turner <[email protected]> CommitDate: 2026-08-26 11:17:18 +0000 arm64: vmm: Split out VGIC register handling to a common file Reviewed by: Sarah Walker <[email protected]> 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)
