From nobody Wed Aug 26 11:33:28 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hVMwS67h0z6pwk8 for ; Wed, 26 Aug 2026 11:33:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hVMwS4tq7z4FgT for ; Wed, 26 Aug 2026 11:33:28 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1787744008; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Z/t0qkx2ZwqRjWcYEM8Rr4PNB3V4AVE6AsOHr5Dn6Xg=; b=VoDaS7QRcg22gaiEPdKgrnftoY8XNyU8e3TLupmbfdiw9SXx9ucjp1s7Q2FgFkoBorzmRz TUc3Wt8LVNtdINnTjffWlI81BMcDzHQNwWuxE7ASA1DCdnsYwCFPAU+j6WRd6xF2mYH2fz wkl5kLjO87aY2/y3mAHExIlTX5Dbv5mOzZAVry71vCoH3Jt8ODG5CUctxf8/dyyUSF5Ood yr0jv/k1VDv6WwHB3GnbCRkDhdmGM1myoBtm861SolV+5YkIG2XHSoVtPHwmtaORAmODfr VJmGm5Vo/pk5e8WSo/jmmWtVOFrqMTe+UY/n/OD4tqPQ1Txiiqlyyfd66mwqnQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1787744008; a=rsa-sha256; cv=none; b=d83octqjVZ5dP0R+BqZaVNePIn5uggeCI04NdG4UoDYs74WTSmn30DalQA51NMV0SnvWbF uiWvQ4N+ueKqZLk/8oU060m5XROKccX5f9rnk4Tuyc/ZvjAhkRN61bSRNlPGbZQy9eBRNX fBQFYC5nPV2/7tIFhZ4bGwkdE7cBAOtxOsIYOp48p25oIijM89pgxPjtbq1EygJjer1fGB IET/ePXqrkyEduTIqgveTqi6r7dprcbW6kftoTi+eZnQn0ltZpNvzXvSzzvfdIHO7TEtmb N1cDtnoiJBf4Z5ckhduqCz1n6VWDS7d9uEXF2i+sC3LH04W/8F4EMxG9h48BbA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1787744008; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Z/t0qkx2ZwqRjWcYEM8Rr4PNB3V4AVE6AsOHr5Dn6Xg=; b=opgq8m1R+n1ZAZ3v5eSRlt8VisbHdSBTAk/FKupFi4fmBRrs8bHeCiCM8/aNA0IB52EorL Iie8MiLprrNS7QNAuuKsikmbQuKdqXJmky+VaZFGQrgnsOGQR4+Wulu93khVLD0FLiivzj AHAlBo2m28b4+x1nfvaE2dqnYcCrRBjQkNNpv0y8pnjFSmspdO32A0GAHdR77NQjxBEgi6 4xr+XovPXyqJ0YIhL8VfuRWN4Lwxo/ilAJm5WqmRbYBIKYFVhyMyys3UGBAyumACI4WPmk K/g0tUFaA4RV2jYT7JkhGfy5RvGe/vuBWDt0FWdLU02LiLZZAfrAzzcYOqz3dw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hVMwS3l2jzcJC for ; Wed, 26 Aug 2026 11:33:28 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 40c1b by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 26 Aug 2026 11:33:28 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Andrew Turner Subject: git: 1ecf7d5b3831 - main - arm64: vmm: Split out VGIC register handling to a common file List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: andrew X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 1ecf7d5b38319d110d0f5bff26d6f8a9c1042cf4 Auto-Submitted: auto-generated Date: Wed, 26 Aug 2026 11:33:28 +0000 Message-Id: <6a8ecf08.40c1b.60f8c966@gitrepo.freebsd.org> The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=1ecf7d5b38319d110d0f5bff26d6f8a9c1042cf4 commit 1ecf7d5b38319d110d0f5bff26d6f8a9c1042cf4 Author: Andrew Turner AuthorDate: 2026-05-13 10:41:17 +0000 Commit: Andrew Turner CommitDate: 2026-08-26 11:17:18 +0000 arm64: vmm: Split out VGIC register handling to a common file Reviewed by: Sarah Walker 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)