From nobody Sun Dec 14 11:18:35 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=arm.com Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1763538872361324.02803330962047; Tue, 18 Nov 2025 23:54:32 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.1165583.1492296 (Exim 4.92) (envelope-from ) id 1vLd18-0008Dn-6b; Wed, 19 Nov 2025 07:54:18 +0000 Received: by outflank-mailman (output) from mailman id 1165583.1492296; Wed, 19 Nov 2025 07:54:18 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vLd18-0008Dg-3i; Wed, 19 Nov 2025 07:54:18 +0000 Received: by outflank-mailman (input) for mailman id 1165583; Wed, 19 Nov 2025 07:54:16 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1vLd16-00088E-PV for xen-devel@lists.xenproject.org; Wed, 19 Nov 2025 07:54:16 +0000 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by se1-gles-sth1.inumbo.com (Halon) with ESMTP id f0c58cc3-c51c-11f0-9d18-b5c5bf9af7f9; Wed, 19 Nov 2025 08:54:14 +0100 (CET) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id C619E1477; Tue, 18 Nov 2025 23:54:05 -0800 (PST) Received: from e134099.cambridge.arm.com (e134099.arm.com [10.1.198.34]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 536893F740; Tue, 18 Nov 2025 23:54:12 -0800 (PST) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: f0c58cc3-c51c-11f0-9d18-b5c5bf9af7f9 From: Harry Ramsey To: xen-devel@lists.xenproject.org Cc: Luca.Fancellu@arm.com, Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk Subject: [PATCH v3 2/3] arm/mpu: Implement reference counting for inclusive regions Date: Wed, 19 Nov 2025 07:53:50 +0000 Message-ID: <20251119075351.3926690-3-harry.ramsey@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251119075351.3926690-1-harry.ramsey@arm.com> References: <20251119075351.3926690-1-harry.ramsey@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1763538874413153000 Content-Type: text/plain; charset="utf-8" Implement reference counting to enable inclusive MPU regions. An inclusive region is defined as a region encapsulated inside a previously allocated region sharing the same permissions. Reference counts are incremented and decremented in xen_mpumap_update_entry. A region will be destroyed if the reference count is 0 upon calling destroy_xen_mappings and if the full region range is specified. Additionally XEN_MPUMAP_ENTRY_SHIFT and XEN_MPUMAP_ENTRY_SHIFT_ZERO are no longer hardcoded and defined inside asm-offsets.c. Signed-off-by: Harry Ramsey Reviewed-by: Michal Orzel --- Changes in v3: - Return early when checking memory attribute condtions - Replace references with refcount Changes in v2: - Improve clarity with regards to MPU inclusive regions - Fix code format issues --- xen/arch/arm/arm32/asm-offsets.c | 2 + xen/arch/arm/arm64/asm-offsets.c | 2 + xen/arch/arm/include/asm/arm32/mpu.h | 2 + xen/arch/arm/include/asm/arm64/mpu.h | 2 + xen/arch/arm/include/asm/mpu/regions.inc | 11 +++- xen/arch/arm/mpu/mm.c | 73 +++++++++++++++++++----- 6 files changed, 76 insertions(+), 16 deletions(-) diff --git a/xen/arch/arm/arm32/asm-offsets.c b/xen/arch/arm/arm32/asm-offs= ets.c index c203ce269d..951f8d03f3 100644 --- a/xen/arch/arm/arm32/asm-offsets.c +++ b/xen/arch/arm/arm32/asm-offsets.c @@ -79,6 +79,8 @@ void __dummy__(void) #ifdef CONFIG_MPU DEFINE(XEN_MPUMAP_MASK_sizeof, sizeof(xen_mpumap_mask)); DEFINE(XEN_MPUMAP_sizeof, sizeof(xen_mpumap)); + DEFINE(XEN_MPUMAP_ENTRY_SHIFT, ilog2(sizeof(pr_t))); + DEFINE(XEN_MPUMAP_ENTRY_ZERO_OFFSET, sizeof(prbar_t) + sizeof(prlar_t)); BLANK(); #endif } diff --git a/xen/arch/arm/arm64/asm-offsets.c b/xen/arch/arm/arm64/asm-offs= ets.c index 320289b281..38a3894a3b 100644 --- a/xen/arch/arm/arm64/asm-offsets.c +++ b/xen/arch/arm/arm64/asm-offsets.c @@ -73,6 +73,8 @@ void __dummy__(void) #ifdef CONFIG_MPU DEFINE(XEN_MPUMAP_MASK_sizeof, sizeof(xen_mpumap_mask)); DEFINE(XEN_MPUMAP_sizeof, sizeof(xen_mpumap)); + DEFINE(XEN_MPUMAP_ENTRY_SHIFT, ilog2(sizeof(pr_t))); + DEFINE(XEN_MPUMAP_ENTRY_ZERO_OFFSET, sizeof(prbar_t) + sizeof(prlar_t)); BLANK(); #endif } diff --git a/xen/arch/arm/include/asm/arm32/mpu.h b/xen/arch/arm/include/as= m/arm32/mpu.h index 0a6930b3a0..137022d922 100644 --- a/xen/arch/arm/include/asm/arm32/mpu.h +++ b/xen/arch/arm/include/asm/arm32/mpu.h @@ -39,6 +39,8 @@ typedef union { typedef struct { prbar_t prbar; prlar_t prlar; + uint8_t refcount; + uint8_t pad[7]; /* Pad structure to 16 Bytes */ } pr_t; =20 #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/arm/include/asm/arm64/mpu.h b/xen/arch/arm/include/as= m/arm64/mpu.h index f0ce344e78..17f62ccaf6 100644 --- a/xen/arch/arm/include/asm/arm64/mpu.h +++ b/xen/arch/arm/include/asm/arm64/mpu.h @@ -38,6 +38,8 @@ typedef union { typedef struct { prbar_t prbar; prlar_t prlar; + uint8_t refcount; + uint8_t pad[15]; /* Pad structure to 32 Bytes */ } pr_t; =20 #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/arm/include/asm/mpu/regions.inc b/xen/arch/arm/includ= e/asm/mpu/regions.inc index 23fead3b21..0cdbb17bc3 100644 --- a/xen/arch/arm/include/asm/mpu/regions.inc +++ b/xen/arch/arm/include/asm/mpu/regions.inc @@ -14,14 +14,12 @@ #define PRLAR_ELx_EN 0x1 =20 #ifdef CONFIG_ARM_64 -#define XEN_MPUMAP_ENTRY_SHIFT 0x4 /* 16 byte structure */ =20 .macro store_pair reg1, reg2, dst stp \reg1, \reg2, [\dst] .endm =20 #else -#define XEN_MPUMAP_ENTRY_SHIFT 0x3 /* 8 byte structure */ =20 .macro store_pair reg1, reg2, dst strd \reg1, \reg2, [\dst] @@ -97,6 +95,15 @@ =20 3: =20 + /* Clear the rest of the xen_mpumap entry. */ +#ifdef CONFIG_ARM_64 + stp xzr, xzr, [\base, #XEN_MPUMAP_ENTRY_ZERO_OFFSET] +#else + mov \prbar, #0 + mov \prlar, #0 + strd \prbar, \prlar, [\base, #XEN_MPUMAP_ENTRY_ZERO_OFFSET] +#endif + add \sel, \sel, #1 =20 1: diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c index b80edcf1ca..29dd8c4622 100644 --- a/xen/arch/arm/mpu/mm.c +++ b/xen/arch/arm/mpu/mm.c @@ -106,6 +106,7 @@ pr_t pr_of_addr(paddr_t base, paddr_t limit, unsigned i= nt flags) region =3D (pr_t) { .prbar =3D prbar, .prlar =3D prlar, + .refcount =3D 0, }; =20 /* Set base address and limit address. */ @@ -170,6 +171,35 @@ int mpumap_contains_region(pr_t *table, uint8_t nr_reg= ions, paddr_t base, return MPUMAP_REGION_NOTFOUND; } =20 +static bool is_mm_attr_match(pr_t *region, unsigned int attributes) +{ + if ( region->prbar.reg.ro !=3D PAGE_RO_MASK(attributes) ) + { + printk(XENLOG_WARNING + "Mismatched Access Permission attributes (%#x instead of %#= x)\n", + region->prbar.reg.ro, PAGE_RO_MASK(attributes)); + return false; + } + + if ( region->prbar.reg.xn !=3D PAGE_XN_MASK(attributes) ) + { + printk(XENLOG_WARNING + "Mismatched Execute Never attributes (%#x instead of %#x)\n= ", + region->prbar.reg.xn, PAGE_XN_MASK(attributes)); + return false; + } + + if ( region->prlar.reg.ai !=3D PAGE_AI_MASK(attributes) ) + { + printk(XENLOG_WARNING + "Mismatched Memory Attribute Index (%#x instead of %#x)\n", + region->prlar.reg.ai, PAGE_AI_MASK(attributes)); + return false; + } + + return true; +} + /* Map a frame table to cover physical addresses ps through pe */ void __init setup_frametable_mappings(paddr_t ps, paddr_t pe) { @@ -284,22 +314,26 @@ static int xen_mpumap_update_entry(paddr_t base, padd= r_t limit, =20 flags_has_page_present =3D flags & _PAGE_PRESENT; =20 - /* Currently we don't support modifying an existing entry. */ + /* + * Currently, we only support removing/modifying a *WHOLE* MPU memory + * region. Part-region removal/modification is not supported as in the = worst + * case it will leave two/three fragments behind. + */ if ( flags_has_page_present && (rc >=3D MPUMAP_REGION_FOUND) ) { - printk("Modifying an existing entry is not supported\n"); - return -EINVAL; - } + if ( !is_mm_attr_match(&xen_mpumap[idx], flags) ) + { + printk("Modifying an existing entry is not supported\n"); + return -EINVAL; + } =20 - /* - * Currently, we only support removing/modifying a *WHOLE* MPU memory - * region. Part-region removal/modification is not supported as in the= worst - * case it will leave two/three fragments behind. - */ - if ( rc =3D=3D MPUMAP_REGION_INCLUSIVE ) - { - printk("Part-region removal/modification is not supported\n"); - return -EINVAL; + /* Check for overflow of refcount before incrementing. */ + if ( xen_mpumap[idx].refcount =3D=3D 0xFF ) + { + printk("Cannot allocate region as it would cause refcount over= flow\n"); + return -ENOENT; + } + xen_mpumap[idx].refcount +=3D 1; } =20 /* We are inserting a mapping =3D> Create new region. */ @@ -323,7 +357,18 @@ static int xen_mpumap_update_entry(paddr_t base, paddr= _t limit, return -EINVAL; } =20 - disable_mpu_region_from_index(idx); + if ( xen_mpumap[idx].refcount =3D=3D 0 ) + { + if ( MPUMAP_REGION_FOUND =3D=3D rc ) + disable_mpu_region_from_index(idx); + else + { + printk("Cannot remove a partial region\n"); + return -EINVAL; + } + } + else + xen_mpumap[idx].refcount -=3D 1; } =20 return 0; --=20 2.43.0