All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] Second series for R82 MPU Support
@ 2025-07-15  7:45 Hari Limaye
  2025-07-15  7:45 ` [PATCH v3 1/6] arm/mpu: Find MPU region by range Hari Limaye
                   ` (5 more replies)
  0 siblings, 6 replies; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  7:45 UTC (permalink / raw)
  To: xen-devel
  Cc: luca.fancellu, Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Michal Orzel, Volodymyr Babchuk

Hi all,

This series is the second set of patches in the ongoing work to
introduce support for MPU systems and Cortex R82 in Xen.

The patches in this series implement the necessary logic to map and
unmap the Device Tree Blob in the early stages of the boot process.

Changes from v2:
- Changes mentioned in individual patches

Cheers,
Hari

Luca Fancellu (4):
  arm/mpu: Find MPU region by range
  xen/arm: Introduce flags_has_rwx helper
  arm/mpu: Implement early_fdt_map support in MPU systems
  arm/mpu: Implement remove_early_mappings for MPU systems

Penny Zheng (2):
  arm/mpu: Populate a new region in Xen MPU mapping table
  arm/mpu: Destroy an existing entry in Xen MPU memory mapping table

 xen/arch/arm/include/asm/mm.h         |   2 +
 xen/arch/arm/include/asm/mpu.h        |   2 +
 xen/arch/arm/include/asm/mpu/cpregs.h |   4 +
 xen/arch/arm/include/asm/mpu/mm.h     |  41 +++++
 xen/arch/arm/mm.c                     |  15 ++
 xen/arch/arm/mmu/pt.c                 |   9 +-
 xen/arch/arm/mpu/mm.c                 | 232 ++++++++++++++++++++++++++
 xen/arch/arm/mpu/setup.c              |  89 +++++++++-
 8 files changed, 383 insertions(+), 11 deletions(-)

-- 
2.34.1



^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v3 1/6] arm/mpu: Find MPU region by range
  2025-07-15  7:45 [PATCH v3 0/6] Second series for R82 MPU Support Hari Limaye
@ 2025-07-15  7:45 ` Hari Limaye
  2025-07-15  8:08   ` Orzel, Michal
  2025-07-15  7:45 ` [PATCH v3 2/6] xen/arm: Introduce flags_has_rwx helper Hari Limaye
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  7:45 UTC (permalink / raw)
  To: xen-devel
  Cc: luca.fancellu, Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Michal Orzel, Volodymyr Babchuk

From: Luca Fancellu <luca.fancellu@arm.com>

Implement a function to find the index of a MPU region in the xen_mpumap
MPU region array. This function will be used in future commits to
implement creating and destroying MPU regions.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Signed-off-by: Hari Limaye <hari.limaye@arm.com>
---
Changes from v1:
- Update commit message
- Remove internal _index variable
- Simplify logic by disallowing NULL index parameter
- Use normal printk
- Reorder conditional checks
- Update some comments

Changes from v2:
- Replace conditional with assert
- Improve comments regarding base and limit
- Space between ( and uint8_t.
---
 xen/arch/arm/include/asm/mpu/mm.h | 29 ++++++++++++++++
 xen/arch/arm/mpu/mm.c             | 55 +++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)

diff --git a/xen/arch/arm/include/asm/mpu/mm.h b/xen/arch/arm/include/asm/mpu/mm.h
index a7f970b465..5a2b9b498b 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -10,6 +10,13 @@
 #include <asm/mm.h>
 #include <asm/mpu.h>
 
+#define MPUMAP_REGION_OVERLAP      -1
+#define MPUMAP_REGION_NOTFOUND      0
+#define MPUMAP_REGION_FOUND         1
+#define MPUMAP_REGION_INCLUSIVE     2
+
+#define INVALID_REGION_IDX     0xFFU
+
 extern struct page_info *frame_table;
 
 extern uint8_t max_mpu_regions;
@@ -75,6 +82,28 @@ void write_protection_region(const pr_t *pr_write, uint8_t sel);
  */
 pr_t pr_of_addr(paddr_t base, paddr_t limit, unsigned int flags);
 
+/*
+ * Checks whether a given memory range is present in the provided table of
+ * MPU protection regions.
+ *
+ * @param table         Array of pr_t protection regions.
+ * @param r_regions     Number of elements in `table`.
+ * @param base          Start of the memory region to be checked (inclusive).
+ * @param limit         End of the memory region to be checked (exclusive).
+ * @param index         Set to the index of the region if an exact or inclusive
+ *                      match is found, and INVALID_REGION otherwise.
+ * @return: Return code indicating the result of the search:
+ *          MPUMAP_REGION_NOTFOUND: no part of the range is present in `table`
+ *          MPUMAP_REGION_FOUND: found an exact match in `table`
+ *          MPUMAP_REGION_INCLUSIVE: found an inclusive match in `table`
+ *          MPUMAP_REGION_OVERLAP: found an overlap with a mapping in `table`
+ *
+ * Note: make sure that the range [`base`, `limit`) refers to the memory region
+ * inclusive of `base` and exclusive of `limit`.
+ */
+int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
+                           paddr_t limit, uint8_t *index);
+
 #endif /* __ARM_MPU_MM_H__ */
 
 /*
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index ccfb37a67b..407264a88c 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -110,6 +110,61 @@ pr_t pr_of_addr(paddr_t base, paddr_t limit, unsigned int flags)
     return region;
 }
 
+int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
+                           paddr_t limit, uint8_t *index)
+{
+    ASSERT(index);
+    *index = INVALID_REGION_IDX;
+
+    /*
+     * The caller supplies a half-open interval [base, limit), i.e. limit is the
+     * first byte *after* the region. Require limit strictly greater than base,
+     * which is necessarily a non-empty region.
+     */
+    ASSERT(base < limit);
+
+    /*
+     * Internally we use inclusive bounds, so convert range to [base, limit-1].
+     * The prior assertion guarantees the subtraction will not underflow.
+     */
+    limit = limit - 1;
+
+    for ( uint8_t i = 0; i < nr_regions; i++ )
+    {
+        paddr_t iter_base = pr_get_base(&table[i]);
+        paddr_t iter_limit = pr_get_limit(&table[i]);
+
+        /* Skip invalid (disabled) regions */
+        if ( !region_is_valid(&table[i]) )
+            continue;
+
+        /* No match */
+        if ( (iter_limit < base) || (iter_base > limit) )
+            continue;
+
+        /* Exact match */
+        if ( (iter_base == base) && (iter_limit == limit) )
+        {
+            *index = i;
+            return MPUMAP_REGION_FOUND;
+        }
+
+        /* Inclusive match */
+        if ( (base >= iter_base) && (limit <= iter_limit) )
+        {
+            *index = i;
+            return MPUMAP_REGION_INCLUSIVE;
+        }
+
+        /* Overlap */
+        printk("Range %#"PRIpaddr" - %#"PRIpaddr" overlaps with the existing region %#"PRIpaddr" - %#"PRIpaddr"\n",
+               base, limit + 1, iter_base, iter_limit + 1);
+        return MPUMAP_REGION_OVERLAP;
+    }
+
+    return MPUMAP_REGION_NOTFOUND;
+}
+
 void __init setup_mm(void)
 {
     BUG_ON("unimplemented");
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 2/6] xen/arm: Introduce flags_has_rwx helper
  2025-07-15  7:45 [PATCH v3 0/6] Second series for R82 MPU Support Hari Limaye
  2025-07-15  7:45 ` [PATCH v3 1/6] arm/mpu: Find MPU region by range Hari Limaye
@ 2025-07-15  7:45 ` Hari Limaye
  2025-07-15  7:45 ` [PATCH v3 3/6] arm/mpu: Populate a new region in Xen MPU mapping table Hari Limaye
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  7:45 UTC (permalink / raw)
  To: xen-devel
  Cc: luca.fancellu, Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Michal Orzel, Volodymyr Babchuk, Ayan Kumar Halder

From: Luca Fancellu <luca.fancellu@arm.com>

Introduce flags_has_rwx() function that will check if a
mapping is both writable and executable when modifying
or updating the mapping.

This check was already present in pt.c but since it will
be used also for MPU systems, it's wrapped into a function
now.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Signed-off-by: Hari Limaye <hari.limaye@arm.com>
Reviewed-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
---
Changes from v1:
- Add Ayan and Michal's R-b
- Fix typos
---
 xen/arch/arm/include/asm/mm.h |  2 ++
 xen/arch/arm/mm.c             | 15 +++++++++++++++
 xen/arch/arm/mmu/pt.c         |  9 +--------
 3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h
index 011bc1fd30..fb79aeb088 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -192,6 +192,8 @@ extern unsigned long frametable_base_pdx;
 
 /* Boot-time pagetable setup */
 extern void setup_pagetables(void);
+/* Check that the mapping flag has no W and X together */
+bool flags_has_rwx(unsigned int flags);
 /* Map FDT in boot pagetable */
 extern void *early_fdt_map(paddr_t fdt_paddr);
 /* Remove early mappings */
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 0613c19169..77e21f5f29 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -24,6 +24,21 @@
 
 unsigned long frametable_base_pdx __read_mostly;
 
+bool flags_has_rwx(unsigned int flags)
+{
+    /*
+     * The hardware was configured to forbid mapping both writable and
+     * executable.
+     * When modifying/creating mapping (i.e _PAGE_PRESENT is set),
+     * prevent any update if this happen.
+     */
+    if ( (flags & _PAGE_PRESENT) && !PAGE_RO_MASK(flags) &&
+         !PAGE_XN_MASK(flags) )
+        return true;
+    else
+        return false;
+}
+
 void flush_page_to_ram(unsigned long mfn, bool sync_icache)
 {
     void *v = map_domain_page(_mfn(mfn));
diff --git a/xen/arch/arm/mmu/pt.c b/xen/arch/arm/mmu/pt.c
index 4726e713ef..621b47dbf5 100644
--- a/xen/arch/arm/mmu/pt.c
+++ b/xen/arch/arm/mmu/pt.c
@@ -610,14 +610,7 @@ static int xen_pt_update(unsigned long virt,
      */
     const mfn_t root = maddr_to_mfn(READ_SYSREG64(TTBR0_EL2));
 
-    /*
-     * The hardware was configured to forbid mapping both writeable and
-     * executable.
-     * When modifying/creating mapping (i.e _PAGE_PRESENT is set),
-     * prevent any update if this happen.
-     */
-    if ( (flags & _PAGE_PRESENT) && !PAGE_RO_MASK(flags) &&
-         !PAGE_XN_MASK(flags) )
+    if ( flags_has_rwx(flags) )
     {
         mm_printk("Mappings should not be both Writeable and Executable.\n");
         return -EINVAL;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 3/6] arm/mpu: Populate a new region in Xen MPU mapping table
  2025-07-15  7:45 [PATCH v3 0/6] Second series for R82 MPU Support Hari Limaye
  2025-07-15  7:45 ` [PATCH v3 1/6] arm/mpu: Find MPU region by range Hari Limaye
  2025-07-15  7:45 ` [PATCH v3 2/6] xen/arm: Introduce flags_has_rwx helper Hari Limaye
@ 2025-07-15  7:45 ` Hari Limaye
  2025-07-15  8:20   ` Orzel, Michal
  2025-07-15  7:45 ` [PATCH v3 4/6] arm/mpu: Destroy an existing entry in Xen MPU memory " Hari Limaye
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  7:45 UTC (permalink / raw)
  To: xen-devel
  Cc: luca.fancellu, Penny Zheng, Stefano Stabellini, Julien Grall,
	Bertrand Marquis, Michal Orzel, Volodymyr Babchuk, Penny Zheng,
	Wei Chen

From: Penny Zheng <Penny.Zheng@arm.com>

Introduce map_pages_to_xen() that is implemented using a new helper,
xen_mpumap_update(), which is responsible for updating Xen MPU memory
mapping table(xen_mpumap), including creating a new entry, updating
or destroying an existing one, it is equivalent to xen_pt_update in MMU.

This commit only implements populating a new entry in Xen MPU memory mapping
table(xen_mpumap).

Signed-off-by: Penny Zheng <penny.zheng@arm.com>
Signed-off-by: Wei Chen <wei.chen@arm.com>
Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Signed-off-by: Hari Limaye <hari.limaye@arm.com>
---
Changes from v1:
- Simplify if condition
- Use normal printk
- Use %# over 0x%
- Add same asserts as in Patch 4

Changes from v2:
- Improve clarity in xen_mpumap_alloc_entry comment
- Simplify if condition
- Remove redundant ASSERT statements
- Add check for `base >= limit`
- Pass virt directly in map_pages_to_xen
- Move call to `context_sync_mpu` inside locked section of `xen_mpumap_update`
- Move _PAGE_PRESENT check before calling `mpumap_contains_region`
---
 xen/arch/arm/include/asm/mpu/mm.h |  12 ++++
 xen/arch/arm/mpu/mm.c             | 103 ++++++++++++++++++++++++++++++
 2 files changed, 115 insertions(+)

diff --git a/xen/arch/arm/include/asm/mpu/mm.h b/xen/arch/arm/include/asm/mpu/mm.h
index 5a2b9b498b..c32fac8905 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -64,6 +64,7 @@ static inline void context_sync_mpu(void)
  * The following API requires context_sync_mpu() after being used to modify MPU
  * regions:
  *  - write_protection_region
+ *  - xen_mpumap_update
  */
 
 /* Reads the MPU region (into @pr_read) with index @sel from the HW */
@@ -72,6 +73,17 @@ void read_protection_region(pr_t *pr_read, uint8_t sel);
 /* Writes the MPU region (from @pr_write) with index @sel to the HW */
 void write_protection_region(const pr_t *pr_write, uint8_t sel);
 
+/*
+ * Maps an address range into the MPU data structure and updates the HW.
+ * Equivalent to xen_pt_update in an MMU system.
+ *
+ * @param base      Base address of the range to map (inclusive).
+ * @param limit     Limit address of the range to map (exclusive).
+ * @param flags     Flags for the memory range to map.
+ * @return          0 on success, negative on error.
+ */
+int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags);
+
 /*
  * Creates a pr_t structure describing a protection region.
  *
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index 407264a88c..d5426525af 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -6,6 +6,7 @@
 #include <xen/lib.h>
 #include <xen/mm.h>
 #include <xen/sizes.h>
+#include <xen/spinlock.h>
 #include <xen/types.h>
 #include <asm/mpu.h>
 #include <asm/mpu/mm.h>
@@ -29,6 +30,8 @@ DECLARE_BITMAP(xen_mpumap_mask, MAX_MPU_REGION_NR) \
 /* EL2 Xen MPU memory region mapping table. */
 pr_t __cacheline_aligned __section(".data") xen_mpumap[MAX_MPU_REGION_NR];
 
+static DEFINE_SPINLOCK(xen_mpumap_lock);
+
 static void __init __maybe_unused build_assertions(void)
 {
     /*
@@ -165,6 +168,106 @@ int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
     return MPUMAP_REGION_NOTFOUND;
 }
 
+/*
+ * Allocate an entry for a new EL2 MPU region in the bitmap xen_mpumap_mask.
+ * @param idx   Set to the index of the allocated EL2 MPU region on success.
+ * @return      0 on success, otherwise -ENOENT on failure.
+ */
+static int xen_mpumap_alloc_entry(uint8_t *idx)
+{
+    ASSERT(spin_is_locked(&xen_mpumap_lock));
+
+    *idx = find_first_zero_bit(xen_mpumap_mask, max_mpu_regions);
+    if ( *idx == max_mpu_regions )
+    {
+        printk(XENLOG_ERR "mpu: EL2 MPU memory region mapping pool exhausted\n");
+        return -ENOENT;
+    }
+
+    set_bit(*idx, xen_mpumap_mask);
+
+    return 0;
+}
+
+/*
+ * Update the entry in the MPU memory region mapping table (xen_mpumap) for the
+ * given memory range and flags, creating one if none exists.
+ *
+ * @param base  Base address (inclusive).
+ * @param limit Limit address (exclusive).
+ * @param flags Region attributes (a combination of PAGE_HYPERVISOR_XXX)
+ * @return      0 on success, otherwise negative on error.
+ */
+static int xen_mpumap_update_entry(paddr_t base, paddr_t limit,
+                                   unsigned int flags)
+{
+    uint8_t idx;
+    int rc;
+
+    ASSERT(spin_is_locked(&xen_mpumap_lock));
+
+    /* Currently only region creation is supported. */
+    if ( !(flags & _PAGE_PRESENT) )
+        return -EINVAL;
+
+    rc = mpumap_contains_region(xen_mpumap, max_mpu_regions, base, limit, &idx);
+    if ( rc != MPUMAP_REGION_NOTFOUND )
+        return -EINVAL;
+
+    /* We are inserting a mapping => Create new region. */
+    rc = xen_mpumap_alloc_entry(&idx);
+    if ( rc )
+        return -ENOENT;
+
+    xen_mpumap[idx] = pr_of_addr(base, limit, flags);
+
+    write_protection_region(&xen_mpumap[idx], idx);
+
+    return 0;
+}
+
+int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags)
+{
+    int rc;
+
+    if ( flags_has_rwx(flags) )
+    {
+        printk("Mappings should not be both Writeable and Executable\n");
+        return -EINVAL;
+    }
+
+    if ( base >= limit )
+    {
+        printk("Base address %#"PRIpaddr" must be smaller than limit address %#"PRIpaddr"\n",
+               base, limit);
+        return -EINVAL;
+    }
+
+    if ( !IS_ALIGNED(base, PAGE_SIZE) || !IS_ALIGNED(limit, PAGE_SIZE) )
+    {
+        printk("base address %#"PRIpaddr", or limit address %#"PRIpaddr" is not page aligned\n",
+               base, limit);
+        return -EINVAL;
+    }
+
+    spin_lock(&xen_mpumap_lock);
+
+    rc = xen_mpumap_update_entry(base, limit, flags);
+    if ( !rc )
+        context_sync_mpu();
+
+    spin_unlock(&xen_mpumap_lock);
+
+    return rc;
+}
+
+int map_pages_to_xen(unsigned long virt, mfn_t mfn, unsigned long nr_mfns,
+                     unsigned int flags)
+{
+    /* MPU systems have no translation, ma == va, so pass virt directly */
+    return xen_mpumap_update(virt, mfn_to_maddr(mfn_add(mfn, nr_mfns)), flags);
+}
+
 void __init setup_mm(void)
 {
     BUG_ON("unimplemented");
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 4/6] arm/mpu: Destroy an existing entry in Xen MPU memory mapping table
  2025-07-15  7:45 [PATCH v3 0/6] Second series for R82 MPU Support Hari Limaye
                   ` (2 preceding siblings ...)
  2025-07-15  7:45 ` [PATCH v3 3/6] arm/mpu: Populate a new region in Xen MPU mapping table Hari Limaye
@ 2025-07-15  7:45 ` Hari Limaye
  2025-07-15  8:51   ` Orzel, Michal
  2025-07-15  7:45 ` [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems Hari Limaye
  2025-07-15  7:45 ` [PATCH v3 6/6] arm/mpu: Implement remove_early_mappings for " Hari Limaye
  5 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  7:45 UTC (permalink / raw)
  To: xen-devel
  Cc: luca.fancellu, Penny Zheng, Stefano Stabellini, Julien Grall,
	Bertrand Marquis, Michal Orzel, Volodymyr Babchuk, Penny Zheng,
	Wei Chen

From: Penny Zheng <Penny.Zheng@arm.com>

This commit expands xen_mpumap_update/xen_mpumap_update_entry to include
destroying an existing entry.

We define a new helper "disable_mpu_region_from_index" to disable the MPU
region based on index. If region is within [0, 31], we could quickly
disable the MPU region through PRENR_EL2 which provides direct access to the
PRLAR_EL2.EN bits of EL2 MPU regions.

Rignt now, we only support destroying a *WHOLE* MPU memory region,
part-region removing is not supported, as in worst case, it will
leave two fragments behind.

Signed-off-by: Penny Zheng <penny.zheng@arm.com>
Signed-off-by: Wei Chen <wei.chen@arm.com>
Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Signed-off-by: Hari Limaye <hari.limaye@arm.com>
---
Changes from v1:
- Move check for part-region removal outside if condition
- Use normal printk

Changes from v2:
- Fix assert from `ASSERT(s <= e)` -> `ASSERT(s < e)`
- Remove call to context_sync_mpu
- Use register_t
- Improve sanity checking to catch modification & removing non-existent
  entries
- Update check for MPUMAP_REGION_INCLUSIVE to be generic
---
 xen/arch/arm/include/asm/mpu.h        |  2 +
 xen/arch/arm/include/asm/mpu/cpregs.h |  4 ++
 xen/arch/arm/mpu/mm.c                 | 92 ++++++++++++++++++++++++---
 3 files changed, 89 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/include/asm/mpu.h b/xen/arch/arm/include/asm/mpu.h
index 63560c613b..5053edaf63 100644
--- a/xen/arch/arm/include/asm/mpu.h
+++ b/xen/arch/arm/include/asm/mpu.h
@@ -23,6 +23,8 @@
 #define NUM_MPU_REGIONS_MASK    (NUM_MPU_REGIONS - 1)
 #define MAX_MPU_REGION_NR       NUM_MPU_REGIONS_MASK
 
+#define PRENR_MASK  GENMASK(31, 0)
+
 #ifndef __ASSEMBLY__
 
 /*
diff --git a/xen/arch/arm/include/asm/mpu/cpregs.h b/xen/arch/arm/include/asm/mpu/cpregs.h
index bb15e02df6..9f3b32acd7 100644
--- a/xen/arch/arm/include/asm/mpu/cpregs.h
+++ b/xen/arch/arm/include/asm/mpu/cpregs.h
@@ -6,6 +6,9 @@
 /* CP15 CR0: MPU Type Register */
 #define HMPUIR          p15,4,c0,c0,4
 
+/* CP15 CR6: Protection Region Enable Register */
+#define HPRENR          p15,4,c6,c1,1
+
 /* CP15 CR6: MPU Protection Region Base/Limit/Select Address Register */
 #define HPRSELR         p15,4,c6,c2,1
 #define HPRBAR          p15,4,c6,c3,0
@@ -82,6 +85,7 @@
 /* Alphabetically... */
 #define MPUIR_EL2       HMPUIR
 #define PRBAR_EL2       HPRBAR
+#define PRENR_EL2       HPRENR
 #define PRLAR_EL2       HPRLAR
 #define PRSELR_EL2      HPRSELR
 #endif /* CONFIG_ARM_32 */
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index d5426525af..a5b1c95793 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -189,6 +189,42 @@ static int xen_mpumap_alloc_entry(uint8_t *idx)
     return 0;
 }
 
+/*
+ * Disable and remove an MPU region from the data structure and MPU registers.
+ *
+ * @param index Index of the MPU region to be disabled.
+ */
+static void disable_mpu_region_from_index(uint8_t index)
+{
+    ASSERT(spin_is_locked(&xen_mpumap_lock));
+    ASSERT(index != INVALID_REGION_IDX);
+
+    if ( !region_is_valid(&xen_mpumap[index]) )
+    {
+        printk(XENLOG_WARNING
+               "mpu: MPU memory region[%u] is already disabled\n", index);
+        return;
+    }
+
+    /* Zeroing the region will also zero the region enable */
+    memset(&xen_mpumap[index], 0, sizeof(pr_t));
+    clear_bit(index, xen_mpumap_mask);
+
+    /*
+     * Both Armv8-R AArch64 and AArch32 have direct access to the enable bit for
+     * MPU regions numbered from 0 to 31.
+     */
+    if ( (index & PRENR_MASK) != 0 )
+    {
+        /* Clear respective bit */
+        register_t val = READ_SYSREG(PRENR_EL2) & (~(1UL << index));
+
+        WRITE_SYSREG(val, PRENR_EL2);
+    }
+    else
+        write_protection_region(&xen_mpumap[index], index);
+}
+
 /*
  * Update the entry in the MPU memory region mapping table (xen_mpumap) for the
  * given memory range and flags, creating one if none exists.
@@ -206,22 +242,51 @@ static int xen_mpumap_update_entry(paddr_t base, paddr_t limit,
 
     ASSERT(spin_is_locked(&xen_mpumap_lock));
 
-    /* Currently only region creation is supported. */
-    if ( !(flags & _PAGE_PRESENT) )
+    rc = mpumap_contains_region(xen_mpumap, max_mpu_regions, base, limit, &idx);
+    if ( rc < 0 )
         return -EINVAL;
 
-    rc = mpumap_contains_region(xen_mpumap, max_mpu_regions, base, limit, &idx);
-    if ( rc != MPUMAP_REGION_NOTFOUND )
+    /*
+     * 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 == MPUMAP_REGION_INCLUSIVE )
+    {
+        printk("mpu: part-region removal/modification is not supported\n");
         return -EINVAL;
+    }
+
+    /* Currently we don't support modifying an existing entry. */
+    if ( (flags & _PAGE_PRESENT) && (rc >= MPUMAP_REGION_FOUND) )
+    {
+        printk("mpu: modifying an existing entry is not supported\n");
+        return -EINVAL;
+    }
 
     /* We are inserting a mapping => Create new region. */
-    rc = xen_mpumap_alloc_entry(&idx);
-    if ( rc )
-        return -ENOENT;
+    if ( (flags & _PAGE_PRESENT) && (MPUMAP_REGION_NOTFOUND == rc) )
+    {
+        rc = xen_mpumap_alloc_entry(&idx);
+        if ( rc )
+            return -ENOENT;
 
-    xen_mpumap[idx] = pr_of_addr(base, limit, flags);
+        xen_mpumap[idx] = pr_of_addr(base, limit, flags);
 
-    write_protection_region(&xen_mpumap[idx], idx);
+        write_protection_region(&xen_mpumap[idx], idx);
+    }
+
+    /* Removing a mapping */
+    if ( !(flags & _PAGE_PRESENT) )
+    {
+        if ( rc == MPUMAP_REGION_NOTFOUND )
+        {
+            printk("mpu: cannot remove an entry that does not exist\n");
+            return -EINVAL;
+        }
+
+        disable_mpu_region_from_index(idx);
+    }
 
     return 0;
 }
@@ -261,6 +326,15 @@ int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags)
     return rc;
 }
 
+int destroy_xen_mappings(unsigned long s, unsigned long e)
+{
+    ASSERT(IS_ALIGNED(s, PAGE_SIZE));
+    ASSERT(IS_ALIGNED(e, PAGE_SIZE));
+    ASSERT(s < e);
+
+    return xen_mpumap_update(virt_to_maddr(s), virt_to_maddr(e), 0);
+}
+
 int map_pages_to_xen(unsigned long virt, mfn_t mfn, unsigned long nr_mfns,
                      unsigned int flags)
 {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems
  2025-07-15  7:45 [PATCH v3 0/6] Second series for R82 MPU Support Hari Limaye
                   ` (3 preceding siblings ...)
  2025-07-15  7:45 ` [PATCH v3 4/6] arm/mpu: Destroy an existing entry in Xen MPU memory " Hari Limaye
@ 2025-07-15  7:45 ` Hari Limaye
  2025-07-17 12:54   ` Orzel, Michal
  2025-07-15  7:45 ` [PATCH v3 6/6] arm/mpu: Implement remove_early_mappings for " Hari Limaye
  5 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  7:45 UTC (permalink / raw)
  To: xen-devel
  Cc: luca.fancellu, Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Michal Orzel, Volodymyr Babchuk, Ayan Kumar Halder

From: Luca Fancellu <luca.fancellu@arm.com>

Implement the function early_fdt_map(), which is responsible for mapping
the Device Tree Blob in the early stages of the boot process, for MPU
systems.

We make use of the map_pages_to_xen() and destroy_xen_mappings() APIs.
In particular the latter function is necessary in the case that the
initial mapping of the fdt_header is insufficient to cover the entire
DTB, as we must destroy and then remap the region due to the APIs no
providing support for extending the size of an existing region.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Signed-off-by: Hari Limaye <hari.limaye@arm.com>
Reviewed-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
---
Changes from v1:
- Add Ayan's R-b

Changes from v2:
- Rename mapped_fdt_paddr -> mapped_fdt_base
- Remove full stops
- Add sanity check for MAX_FDT_SIZE
- Improve comment regarding early return when DTB already mapped
---
 xen/arch/arm/mpu/setup.c | 83 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/mpu/setup.c b/xen/arch/arm/mpu/setup.c
index b4da77003f..a8cea0d9af 100644
--- a/xen/arch/arm/mpu/setup.c
+++ b/xen/arch/arm/mpu/setup.c
@@ -1,17 +1,96 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 
+#include <xen/bootfdt.h>
 #include <xen/bug.h>
 #include <xen/init.h>
+#include <xen/libfdt/libfdt.h>
 #include <xen/mm.h>
+#include <xen/pfn.h>
 #include <xen/types.h>
+#include <xen/sizes.h>
 #include <asm/setup.h>
 
+static paddr_t __initdata mapped_fdt_base = INVALID_PADDR;
+static paddr_t __initdata mapped_fdt_limit = INVALID_PADDR;
+
 void __init setup_pagetables(void) {}
 
 void * __init early_fdt_map(paddr_t fdt_paddr)
 {
-    BUG_ON("unimplemented");
-    return NULL;
+    /* Map at least a page containing the DTB address, exclusive range */
+    paddr_t base = round_pgdown(fdt_paddr);
+    paddr_t limit = round_pgup(fdt_paddr + sizeof(struct fdt_header));
+    unsigned int flags = PAGE_HYPERVISOR_RO;
+    void *fdt_virt = (void *)fdt_paddr; /* virt == paddr for MPU */
+    int rc;
+    uint32_t size;
+    unsigned long nr_mfns;
+
+    /*
+     * Check whether the physical FDT address is set and meets the minimum
+     * alignment requirement. Since we are relying on MIN_FDT_ALIGN to be at
+     * least 8 bytes so that we always access the magic and size fields
+     * of the FDT header after mapping the first chunk, double check if
+     * that is indeed the case.
+     */
+    BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
+    if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN )
+        return NULL;
+
+    /*
+     * DTB at this address has already been mapped.`start_xen` calls this twice,
+     * before and after `setup_page_tables`, which is a no-op on MPU.
+     */
+    if ( mapped_fdt_base == fdt_paddr )
+        return fdt_virt;
+
+    /*
+     * DTB starting at a different address has been mapped, so destroy this
+     * before continuing.
+     */
+    if ( mapped_fdt_base != INVALID_PADDR )
+    {
+        rc = destroy_xen_mappings(round_pgdown(mapped_fdt_base),
+                                  mapped_fdt_limit);
+        if ( rc )
+            panic("Unable to unmap existing device-tree\n");
+    }
+
+    nr_mfns = (limit - base) >> PAGE_SHIFT;
+
+    rc = map_pages_to_xen(base, maddr_to_mfn(base), nr_mfns, flags);
+    if ( rc )
+        panic("Unable to map the device-tree\n");
+
+    mapped_fdt_base = fdt_paddr;
+    mapped_fdt_limit = limit;
+
+    if ( fdt_magic(fdt_virt) != FDT_MAGIC )
+        return NULL;
+
+    size = fdt_totalsize(fdt_virt);
+    if ( size > MAX_FDT_SIZE )
+        return NULL;
+
+    limit = round_pgup(fdt_paddr + size);
+
+    /* If the mapped range is not enough, map the rest of the DTB. */
+    if ( limit > mapped_fdt_limit )
+    {
+        rc = destroy_xen_mappings(base, mapped_fdt_limit);
+        if ( rc )
+            panic("Unable to unmap the device-tree header\n");
+
+        nr_mfns = (limit - base) >> PAGE_SHIFT;
+
+        rc = map_pages_to_xen(base, maddr_to_mfn(base), nr_mfns, flags);
+        if ( rc )
+            panic("Unable to map the device-tree\n");
+
+        mapped_fdt_limit = limit;
+    }
+
+    return fdt_virt;
 }
 
 /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v3 6/6] arm/mpu: Implement remove_early_mappings for MPU systems
  2025-07-15  7:45 [PATCH v3 0/6] Second series for R82 MPU Support Hari Limaye
                   ` (4 preceding siblings ...)
  2025-07-15  7:45 ` [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems Hari Limaye
@ 2025-07-15  7:45 ` Hari Limaye
  2025-07-17 12:55   ` Orzel, Michal
  5 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  7:45 UTC (permalink / raw)
  To: xen-devel
  Cc: luca.fancellu, Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Michal Orzel, Volodymyr Babchuk, Ayan Kumar Halder

From: Luca Fancellu <luca.fancellu@arm.com>

Implement remove_early_mappings for MPU systems.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Signed-off-by: Hari Limaye <hari.limaye@arm.com>
Reviewed-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
---
Changes from v1:
- Add Ayan's R-b

Changes from v2:
- Remove full stop
- Remove sanity check for `mapped_fdt_paddr == INVALID_PADDR`
---
 xen/arch/arm/mpu/setup.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/mpu/setup.c b/xen/arch/arm/mpu/setup.c
index a8cea0d9af..efceb985e3 100644
--- a/xen/arch/arm/mpu/setup.c
+++ b/xen/arch/arm/mpu/setup.c
@@ -106,7 +106,11 @@ void __init copy_from_paddr(void *dst, paddr_t paddr, unsigned long len)
 
 void __init remove_early_mappings(void)
 {
-    BUG_ON("unimplemented");
+    int rc = destroy_xen_mappings(round_pgdown(mapped_fdt_base),
+                                  mapped_fdt_limit);
+
+    if ( rc )
+        panic("Unable to unmap the device-tree\n");
 }
 
 /*
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 1/6] arm/mpu: Find MPU region by range
  2025-07-15  7:45 ` [PATCH v3 1/6] arm/mpu: Find MPU region by range Hari Limaye
@ 2025-07-15  8:08   ` Orzel, Michal
  2025-07-15  8:36     ` Hari Limaye
  0 siblings, 1 reply; 21+ messages in thread
From: Orzel, Michal @ 2025-07-15  8:08 UTC (permalink / raw)
  To: Hari Limaye, xen-devel
  Cc: luca.fancellu, Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk



On 15/07/2025 09:45, Hari Limaye wrote:
> From: Luca Fancellu <luca.fancellu@arm.com>
> 
> Implement a function to find the index of a MPU region in the xen_mpumap
> MPU region array. This function will be used in future commits to
> implement creating and destroying MPU regions.
> 
> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
> Signed-off-by: Hari Limaye <hari.limaye@arm.com>
> ---
> Changes from v1:
> - Update commit message
> - Remove internal _index variable
> - Simplify logic by disallowing NULL index parameter
> - Use normal printk
> - Reorder conditional checks
> - Update some comments
> 
> Changes from v2:
> - Replace conditional with assert
> - Improve comments regarding base and limit
> - Space between ( and uint8_t.
> ---
>  xen/arch/arm/include/asm/mpu/mm.h | 29 ++++++++++++++++
>  xen/arch/arm/mpu/mm.c             | 55 +++++++++++++++++++++++++++++++
>  2 files changed, 84 insertions(+)
> 
> diff --git a/xen/arch/arm/include/asm/mpu/mm.h b/xen/arch/arm/include/asm/mpu/mm.h
> index a7f970b465..5a2b9b498b 100644
> --- a/xen/arch/arm/include/asm/mpu/mm.h
> +++ b/xen/arch/arm/include/asm/mpu/mm.h
> @@ -10,6 +10,13 @@
>  #include <asm/mm.h>
>  #include <asm/mpu.h>
>  
> +#define MPUMAP_REGION_OVERLAP      -1
> +#define MPUMAP_REGION_NOTFOUND      0
> +#define MPUMAP_REGION_FOUND         1
> +#define MPUMAP_REGION_INCLUSIVE     2
> +
> +#define INVALID_REGION_IDX     0xFFU
> +
>  extern struct page_info *frame_table;
>  
>  extern uint8_t max_mpu_regions;
> @@ -75,6 +82,28 @@ void write_protection_region(const pr_t *pr_write, uint8_t sel);
>   */
>  pr_t pr_of_addr(paddr_t base, paddr_t limit, unsigned int flags);
>  
> +/*
> + * Checks whether a given memory range is present in the provided table of
> + * MPU protection regions.
> + *
> + * @param table         Array of pr_t protection regions.
> + * @param r_regions     Number of elements in `table`.
> + * @param base          Start of the memory region to be checked (inclusive).
> + * @param limit         End of the memory region to be checked (exclusive).
> + * @param index         Set to the index of the region if an exact or inclusive
> + *                      match is found, and INVALID_REGION otherwise.
> + * @return: Return code indicating the result of the search:
> + *          MPUMAP_REGION_NOTFOUND: no part of the range is present in `table`
> + *          MPUMAP_REGION_FOUND: found an exact match in `table`
> + *          MPUMAP_REGION_INCLUSIVE: found an inclusive match in `table`
> + *          MPUMAP_REGION_OVERLAP: found an overlap with a mapping in `table`
> + *
> + * Note: make sure that the range [`base`, `limit`) refers to the memory region
> + * inclusive of `base` and exclusive of `limit`.
> + */
> +int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
> +                           paddr_t limit, uint8_t *index);
> +
>  #endif /* __ARM_MPU_MM_H__ */
>  
>  /*
> diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
> index ccfb37a67b..407264a88c 100644
> --- a/xen/arch/arm/mpu/mm.c
> +++ b/xen/arch/arm/mpu/mm.c
> @@ -110,6 +110,61 @@ pr_t pr_of_addr(paddr_t base, paddr_t limit, unsigned int flags)
>      return region;
>  }
>  
> +int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
> +                           paddr_t limit, uint8_t *index)
> +{
> +    ASSERT(index);
> +    *index = INVALID_REGION_IDX;
> +
> +    /*
> +     * The caller supplies a half-open interval [base, limit), i.e. limit is the
> +     * first byte *after* the region. Require limit strictly greater than base,
> +     * which is necessarily a non-empty region.
> +     */
> +    ASSERT(base < limit);
Well, that does not guarantee a non-empty region.
Consider passing [x, x+1). The assert will pass, even though the region is empty.

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 3/6] arm/mpu: Populate a new region in Xen MPU mapping table
  2025-07-15  7:45 ` [PATCH v3 3/6] arm/mpu: Populate a new region in Xen MPU mapping table Hari Limaye
@ 2025-07-15  8:20   ` Orzel, Michal
  2025-07-15  8:51     ` Hari Limaye
  0 siblings, 1 reply; 21+ messages in thread
From: Orzel, Michal @ 2025-07-15  8:20 UTC (permalink / raw)
  To: Hari Limaye, xen-devel
  Cc: luca.fancellu, Penny Zheng, Stefano Stabellini, Julien Grall,
	Bertrand Marquis, Volodymyr Babchuk, Wei Chen



On 15/07/2025 09:45, Hari Limaye wrote:
> From: Penny Zheng <Penny.Zheng@arm.com>
> 
> Introduce map_pages_to_xen() that is implemented using a new helper,
> xen_mpumap_update(), which is responsible for updating Xen MPU memory
> mapping table(xen_mpumap), including creating a new entry, updating
> or destroying an existing one, it is equivalent to xen_pt_update in MMU.
> 
> This commit only implements populating a new entry in Xen MPU memory mapping
> table(xen_mpumap).
> 
> Signed-off-by: Penny Zheng <penny.zheng@arm.com>
> Signed-off-by: Wei Chen <wei.chen@arm.com>
> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
> Signed-off-by: Hari Limaye <hari.limaye@arm.com>
> ---
> Changes from v1:
> - Simplify if condition
> - Use normal printk
> - Use %# over 0x%
> - Add same asserts as in Patch 4
> 
> Changes from v2:
> - Improve clarity in xen_mpumap_alloc_entry comment
> - Simplify if condition
> - Remove redundant ASSERT statements
> - Add check for `base >= limit`
> - Pass virt directly in map_pages_to_xen
> - Move call to `context_sync_mpu` inside locked section of `xen_mpumap_update`
> - Move _PAGE_PRESENT check before calling `mpumap_contains_region`
> ---
>  xen/arch/arm/include/asm/mpu/mm.h |  12 ++++
>  xen/arch/arm/mpu/mm.c             | 103 ++++++++++++++++++++++++++++++
>  2 files changed, 115 insertions(+)
> 
> diff --git a/xen/arch/arm/include/asm/mpu/mm.h b/xen/arch/arm/include/asm/mpu/mm.h
> index 5a2b9b498b..c32fac8905 100644
> --- a/xen/arch/arm/include/asm/mpu/mm.h
> +++ b/xen/arch/arm/include/asm/mpu/mm.h
> @@ -64,6 +64,7 @@ static inline void context_sync_mpu(void)
>   * The following API requires context_sync_mpu() after being used to modify MPU
>   * regions:
>   *  - write_protection_region
> + *  - xen_mpumap_update
>   */
>  
>  /* Reads the MPU region (into @pr_read) with index @sel from the HW */
> @@ -72,6 +73,17 @@ void read_protection_region(pr_t *pr_read, uint8_t sel);
>  /* Writes the MPU region (from @pr_write) with index @sel to the HW */
>  void write_protection_region(const pr_t *pr_write, uint8_t sel);
>  
> +/*
> + * Maps an address range into the MPU data structure and updates the HW.
> + * Equivalent to xen_pt_update in an MMU system.
> + *
> + * @param base      Base address of the range to map (inclusive).
> + * @param limit     Limit address of the range to map (exclusive).
> + * @param flags     Flags for the memory range to map.
> + * @return          0 on success, negative on error.
> + */
> +int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags);
> +
>  /*
>   * Creates a pr_t structure describing a protection region.
>   *
> diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
> index 407264a88c..d5426525af 100644
> --- a/xen/arch/arm/mpu/mm.c
> +++ b/xen/arch/arm/mpu/mm.c
> @@ -6,6 +6,7 @@
>  #include <xen/lib.h>
>  #include <xen/mm.h>
>  #include <xen/sizes.h>
> +#include <xen/spinlock.h>
>  #include <xen/types.h>
>  #include <asm/mpu.h>
>  #include <asm/mpu/mm.h>
> @@ -29,6 +30,8 @@ DECLARE_BITMAP(xen_mpumap_mask, MAX_MPU_REGION_NR) \
>  /* EL2 Xen MPU memory region mapping table. */
>  pr_t __cacheline_aligned __section(".data") xen_mpumap[MAX_MPU_REGION_NR];
>  
> +static DEFINE_SPINLOCK(xen_mpumap_lock);
> +
>  static void __init __maybe_unused build_assertions(void)
>  {
>      /*
> @@ -165,6 +168,106 @@ int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
>      return MPUMAP_REGION_NOTFOUND;
>  }
>  
> +/*
> + * Allocate an entry for a new EL2 MPU region in the bitmap xen_mpumap_mask.
> + * @param idx   Set to the index of the allocated EL2 MPU region on success.
> + * @return      0 on success, otherwise -ENOENT on failure.
> + */
> +static int xen_mpumap_alloc_entry(uint8_t *idx)
> +{
> +    ASSERT(spin_is_locked(&xen_mpumap_lock));
> +
> +    *idx = find_first_zero_bit(xen_mpumap_mask, max_mpu_regions);
> +    if ( *idx == max_mpu_regions )
> +    {
> +        printk(XENLOG_ERR "mpu: EL2 MPU memory region mapping pool exhausted\n");
> +        return -ENOENT;
> +    }
> +
> +    set_bit(*idx, xen_mpumap_mask);
> +
> +    return 0;
> +}
> +
> +/*
> + * Update the entry in the MPU memory region mapping table (xen_mpumap) for the
> + * given memory range and flags, creating one if none exists.
> + *
> + * @param base  Base address (inclusive).
> + * @param limit Limit address (exclusive).
> + * @param flags Region attributes (a combination of PAGE_HYPERVISOR_XXX)
> + * @return      0 on success, otherwise negative on error.
> + */
> +static int xen_mpumap_update_entry(paddr_t base, paddr_t limit,
> +                                   unsigned int flags)
> +{
> +    uint8_t idx;
> +    int rc;
> +
> +    ASSERT(spin_is_locked(&xen_mpumap_lock));
> +
> +    /* Currently only region creation is supported. */
> +    if ( !(flags & _PAGE_PRESENT) )
> +        return -EINVAL;
> +
> +    rc = mpumap_contains_region(xen_mpumap, max_mpu_regions, base, limit, &idx);
> +    if ( rc != MPUMAP_REGION_NOTFOUND )
> +        return -EINVAL;
> +
> +    /* We are inserting a mapping => Create new region. */
> +    rc = xen_mpumap_alloc_entry(&idx);
> +    if ( rc )
> +        return -ENOENT;
> +
> +    xen_mpumap[idx] = pr_of_addr(base, limit, flags);
> +
> +    write_protection_region(&xen_mpumap[idx], idx);
> +
> +    return 0;
> +}
> +
> +int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags)
> +{
> +    int rc;
> +
> +    if ( flags_has_rwx(flags) )
> +    {
> +        printk("Mappings should not be both Writeable and Executable\n");
> +        return -EINVAL;
> +    }
> +
> +    if ( base >= limit )
Given that limit is exclusive, to prevent empty regions, you would need to check
for base >= (limit - 1), even though it's not really possible because today we
require page aligned addresses (limit must be at least bigger or equal than base
+ PAGE_SIZE). That said, it can change one day, so I would suggest to modify the
check. With that:

Reviewed-by: Michal Orzel <michal.orzel@amd.com>

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 1/6] arm/mpu: Find MPU region by range
  2025-07-15  8:08   ` Orzel, Michal
@ 2025-07-15  8:36     ` Hari Limaye
  2025-07-15  8:45       ` Orzel, Michal
  0 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  8:36 UTC (permalink / raw)
  To: Orzel, Michal
  Cc: xen-devel@lists.xenproject.org, Luca Fancellu, Stefano Stabellini,
	Julien Grall, Bertrand Marquis, Volodymyr Babchuk

Hi Michal,

>> +int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
>> +                           paddr_t limit, uint8_t *index)
>> +{
>> +    ASSERT(index);
>> +    *index = INVALID_REGION_IDX;
>> +
>> +    /*
>> +     * The caller supplies a half-open interval [base, limit), i.e. limit is the
>> +     * first byte *after* the region. Require limit strictly greater than base,
>> +     * which is necessarily a non-empty region.
>> +     */
>> +    ASSERT(base < limit);
> Well, that does not guarantee a non-empty region.
> Consider passing [x, x+1). The assert will pass, even though the region is empty.
> 
> ~Michal
> 

Apologies, I may well be missing something here! Please could you suggest a code snippet to understand your expectation here / what you would prefer the assert to be?

As I understand it, with a half-open interval [base, limit) as is passed to this function, the size is  `limit - base` and so the region [x, x+1) will have size 1. The empty region starting at the same address would be [x, x). But perhaps I am making the off-by-one error here.

Many thanks,
Hari




^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 1/6] arm/mpu: Find MPU region by range
  2025-07-15  8:36     ` Hari Limaye
@ 2025-07-15  8:45       ` Orzel, Michal
  2025-07-15  9:48         ` Hari Limaye
  0 siblings, 1 reply; 21+ messages in thread
From: Orzel, Michal @ 2025-07-15  8:45 UTC (permalink / raw)
  To: Hari Limaye
  Cc: xen-devel@lists.xenproject.org, Luca Fancellu, Stefano Stabellini,
	Julien Grall, Bertrand Marquis, Volodymyr Babchuk



On 15/07/2025 10:36, Hari Limaye wrote:
> Hi Michal,
> 
>>> +int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
>>> +                           paddr_t limit, uint8_t *index)
>>> +{
>>> +    ASSERT(index);
>>> +    *index = INVALID_REGION_IDX;
>>> +
>>> +    /*
>>> +     * The caller supplies a half-open interval [base, limit), i.e. limit is the
>>> +     * first byte *after* the region. Require limit strictly greater than base,
>>> +     * which is necessarily a non-empty region.
>>> +     */
>>> +    ASSERT(base < limit);
>> Well, that does not guarantee a non-empty region.
>> Consider passing [x, x+1). The assert will pass, even though the region is empty.
>>
>> ~Michal
>>
> 
> Apologies, I may well be missing something here! Please could you suggest a code snippet to understand your expectation here / what you would prefer the assert to be?
> 
> As I understand it, with a half-open interval [base, limit) as is passed to this function, the size is  `limit - base` and so the region [x, x+1) will have size 1. The empty region starting at the same address would be [x, x). But perhaps I am making the off-by-one error here.
Hmm, I think I made a mistake here. Region of size 1B would have base == limit
in registers. All good then.

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 3/6] arm/mpu: Populate a new region in Xen MPU mapping table
  2025-07-15  8:20   ` Orzel, Michal
@ 2025-07-15  8:51     ` Hari Limaye
  2025-07-15  8:52       ` Orzel, Michal
  0 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  8:51 UTC (permalink / raw)
  To: Orzel, Michal
  Cc: xen-devel@lists.xenproject.org, Luca Fancellu, Penny Zheng,
	Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk, Wei Chen

Hi Michal.

>> +    if ( base >= limit )
> Given that limit is exclusive, to prevent empty regions, you would need to check
> for base >= (limit - 1), even though it's not really possible because today we
> require page aligned addresses (limit must be at least bigger or equal than base
> + PAGE_SIZE). That said, it can change one day, so I would suggest to modify the
> check. With that:
> 
> Reviewed-by: Michal Orzel <michal.orzel@amd.com>
> 
> ~Michal
> 

I think that this one is maybe also fine as-is?

Cheers,
Hari

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 4/6] arm/mpu: Destroy an existing entry in Xen MPU memory mapping table
  2025-07-15  7:45 ` [PATCH v3 4/6] arm/mpu: Destroy an existing entry in Xen MPU memory " Hari Limaye
@ 2025-07-15  8:51   ` Orzel, Michal
  0 siblings, 0 replies; 21+ messages in thread
From: Orzel, Michal @ 2025-07-15  8:51 UTC (permalink / raw)
  To: Hari Limaye, xen-devel
  Cc: luca.fancellu, Penny Zheng, Stefano Stabellini, Julien Grall,
	Bertrand Marquis, Volodymyr Babchuk, Wei Chen



On 15/07/2025 09:45, Hari Limaye wrote:
> From: Penny Zheng <Penny.Zheng@arm.com>
> 
> This commit expands xen_mpumap_update/xen_mpumap_update_entry to include
> destroying an existing entry.
> 
> We define a new helper "disable_mpu_region_from_index" to disable the MPU
> region based on index. If region is within [0, 31], we could quickly
> disable the MPU region through PRENR_EL2 which provides direct access to the
> PRLAR_EL2.EN bits of EL2 MPU regions.
> 
> Rignt now, we only support destroying a *WHOLE* MPU memory region,
> part-region removing is not supported, as in worst case, it will
> leave two fragments behind.
> 
> Signed-off-by: Penny Zheng <penny.zheng@arm.com>
> Signed-off-by: Wei Chen <wei.chen@arm.com>
> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
> Signed-off-by: Hari Limaye <hari.limaye@arm.com>
> ---
> Changes from v1:
> - Move check for part-region removal outside if condition
> - Use normal printk
> 
> Changes from v2:
> - Fix assert from `ASSERT(s <= e)` -> `ASSERT(s < e)`
> - Remove call to context_sync_mpu
> - Use register_t
> - Improve sanity checking to catch modification & removing non-existent
>   entries
> - Update check for MPUMAP_REGION_INCLUSIVE to be generic
> ---
>  xen/arch/arm/include/asm/mpu.h        |  2 +
>  xen/arch/arm/include/asm/mpu/cpregs.h |  4 ++
>  xen/arch/arm/mpu/mm.c                 | 92 ++++++++++++++++++++++++---
>  3 files changed, 89 insertions(+), 9 deletions(-)
> 
> diff --git a/xen/arch/arm/include/asm/mpu.h b/xen/arch/arm/include/asm/mpu.h
> index 63560c613b..5053edaf63 100644
> --- a/xen/arch/arm/include/asm/mpu.h
> +++ b/xen/arch/arm/include/asm/mpu.h
> @@ -23,6 +23,8 @@
>  #define NUM_MPU_REGIONS_MASK    (NUM_MPU_REGIONS - 1)
>  #define MAX_MPU_REGION_NR       NUM_MPU_REGIONS_MASK
>  
> +#define PRENR_MASK  GENMASK(31, 0)
> +
>  #ifndef __ASSEMBLY__
>  
>  /*
> diff --git a/xen/arch/arm/include/asm/mpu/cpregs.h b/xen/arch/arm/include/asm/mpu/cpregs.h
> index bb15e02df6..9f3b32acd7 100644
> --- a/xen/arch/arm/include/asm/mpu/cpregs.h
> +++ b/xen/arch/arm/include/asm/mpu/cpregs.h
> @@ -6,6 +6,9 @@
>  /* CP15 CR0: MPU Type Register */
>  #define HMPUIR          p15,4,c0,c0,4
>  
> +/* CP15 CR6: Protection Region Enable Register */
> +#define HPRENR          p15,4,c6,c1,1
> +
>  /* CP15 CR6: MPU Protection Region Base/Limit/Select Address Register */
>  #define HPRSELR         p15,4,c6,c2,1
>  #define HPRBAR          p15,4,c6,c3,0
> @@ -82,6 +85,7 @@
>  /* Alphabetically... */
>  #define MPUIR_EL2       HMPUIR
>  #define PRBAR_EL2       HPRBAR
> +#define PRENR_EL2       HPRENR
>  #define PRLAR_EL2       HPRLAR
>  #define PRSELR_EL2      HPRSELR
>  #endif /* CONFIG_ARM_32 */
> diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
> index d5426525af..a5b1c95793 100644
> --- a/xen/arch/arm/mpu/mm.c
> +++ b/xen/arch/arm/mpu/mm.c
> @@ -189,6 +189,42 @@ static int xen_mpumap_alloc_entry(uint8_t *idx)
>      return 0;
>  }
>  
> +/*
> + * Disable and remove an MPU region from the data structure and MPU registers.
> + *
> + * @param index Index of the MPU region to be disabled.
> + */
> +static void disable_mpu_region_from_index(uint8_t index)
> +{
> +    ASSERT(spin_is_locked(&xen_mpumap_lock));
> +    ASSERT(index != INVALID_REGION_IDX);
> +
> +    if ( !region_is_valid(&xen_mpumap[index]) )
> +    {
> +        printk(XENLOG_WARNING
> +               "mpu: MPU memory region[%u] is already disabled\n", index);
> +        return;
> +    }
> +
> +    /* Zeroing the region will also zero the region enable */
> +    memset(&xen_mpumap[index], 0, sizeof(pr_t));
> +    clear_bit(index, xen_mpumap_mask);
> +
> +    /*
> +     * Both Armv8-R AArch64 and AArch32 have direct access to the enable bit for
> +     * MPU regions numbered from 0 to 31.
> +     */
> +    if ( (index & PRENR_MASK) != 0 )
> +    {
> +        /* Clear respective bit */
> +        register_t val = READ_SYSREG(PRENR_EL2) & (~(1UL << index));
> +
> +        WRITE_SYSREG(val, PRENR_EL2);
> +    }
> +    else
> +        write_protection_region(&xen_mpumap[index], index);
> +}
> +
>  /*
>   * Update the entry in the MPU memory region mapping table (xen_mpumap) for the
>   * given memory range and flags, creating one if none exists.
> @@ -206,22 +242,51 @@ static int xen_mpumap_update_entry(paddr_t base, paddr_t limit,
>  
>      ASSERT(spin_is_locked(&xen_mpumap_lock));
>  
> -    /* Currently only region creation is supported. */
> -    if ( !(flags & _PAGE_PRESENT) )
> +    rc = mpumap_contains_region(xen_mpumap, max_mpu_regions, base, limit, &idx);
> +    if ( rc < 0 )
>          return -EINVAL;
>  
> -    rc = mpumap_contains_region(xen_mpumap, max_mpu_regions, base, limit, &idx);
> -    if ( rc != MPUMAP_REGION_NOTFOUND )
> +    /*
> +     * 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 == MPUMAP_REGION_INCLUSIVE )
> +    {
> +        printk("mpu: part-region removal/modification is not supported\n");
>          return -EINVAL;
> +    }
> +
> +    /* Currently we don't support modifying an existing entry. */
> +    if ( (flags & _PAGE_PRESENT) && (rc >= MPUMAP_REGION_FOUND) )
This check should be above ( rc == MPUMAP_REGION_INCLUSIVE ). Otherwise you
might end up printing a message about removal in modifying case.

> +    {
> +        printk("mpu: modifying an existing entry is not supported\n");
> +        return -EINVAL;
> +    }
>  
>      /* We are inserting a mapping => Create new region. */
> -    rc = xen_mpumap_alloc_entry(&idx);
> -    if ( rc )
> -        return -ENOENT;
> +    if ( (flags & _PAGE_PRESENT) && (MPUMAP_REGION_NOTFOUND == rc) )
You check for flags & _PAGE_PRESENT 3 times. I suggest to add a bool variable at
the top storing this result for better readability.

> +    {
> +        rc = xen_mpumap_alloc_entry(&idx);
> +        if ( rc )
> +            return -ENOENT;
>  
> -    xen_mpumap[idx] = pr_of_addr(base, limit, flags);
> +        xen_mpumap[idx] = pr_of_addr(base, limit, flags);
>  
> -    write_protection_region(&xen_mpumap[idx], idx);
> +        write_protection_region(&xen_mpumap[idx], idx);
> +    }
> +
> +    /* Removing a mapping */
> +    if ( !(flags & _PAGE_PRESENT) )
> +    {
> +        if ( rc == MPUMAP_REGION_NOTFOUND )
> +        {
> +            printk("mpu: cannot remove an entry that does not exist\n");
> +            return -EINVAL;
> +        }
> +
> +        disable_mpu_region_from_index(idx);
> +    }
>  
>      return 0;
>  }
> @@ -261,6 +326,15 @@ int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags)
>      return rc;
>  }
>  
> +int destroy_xen_mappings(unsigned long s, unsigned long e)
> +{
> +    ASSERT(IS_ALIGNED(s, PAGE_SIZE));
> +    ASSERT(IS_ALIGNED(e, PAGE_SIZE));
> +    ASSERT(s < e);
> +
> +    return xen_mpumap_update(virt_to_maddr(s), virt_to_maddr(e), 0);
If virt == madr on MPU, why do you need conversion?

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 3/6] arm/mpu: Populate a new region in Xen MPU mapping table
  2025-07-15  8:51     ` Hari Limaye
@ 2025-07-15  8:52       ` Orzel, Michal
  0 siblings, 0 replies; 21+ messages in thread
From: Orzel, Michal @ 2025-07-15  8:52 UTC (permalink / raw)
  To: Hari Limaye
  Cc: xen-devel@lists.xenproject.org, Luca Fancellu, Penny Zheng,
	Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk, Wei Chen



On 15/07/2025 10:51, Hari Limaye wrote:
> Hi Michal.
> 
>>> +    if ( base >= limit )
>> Given that limit is exclusive, to prevent empty regions, you would need to check
>> for base >= (limit - 1), even though it's not really possible because today we
>> require page aligned addresses (limit must be at least bigger or equal than base
>> + PAGE_SIZE). That said, it can change one day, so I would suggest to modify the
>> check. With that:
>>
>> Reviewed-by: Michal Orzel <michal.orzel@amd.com>
>>
>> ~Michal
>>
> 
> I think that this one is maybe also fine as-is?
Yes.

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 1/6] arm/mpu: Find MPU region by range
  2025-07-15  8:45       ` Orzel, Michal
@ 2025-07-15  9:48         ` Hari Limaye
  2025-07-15  9:59           ` Orzel, Michal
  0 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-15  9:48 UTC (permalink / raw)
  To: Orzel, Michal
  Cc: xen-devel@lists.xenproject.org, Luca Fancellu, Stefano Stabellini,
	Julien Grall, Bertrand Marquis, Volodymyr Babchuk

Hi Michal,

> On 15 Jul 2025, at 09:45, Orzel, Michal <michal.orzel@amd.com> wrote:
> 
> 
> 
> On 15/07/2025 10:36, Hari Limaye wrote:
>> Hi Michal,
>> 
>>>> +int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
>>>> +                           paddr_t limit, uint8_t *index)
>>>> +{
>>>> +    ASSERT(index);
>>>> +    *index = INVALID_REGION_IDX;
>>>> +
>>>> +    /*
>>>> +     * The caller supplies a half-open interval [base, limit), i.e. limit is the
>>>> +     * first byte *after* the region. Require limit strictly greater than base,
>>>> +     * which is necessarily a non-empty region.
>>>> +     */
>>>> +    ASSERT(base < limit);
>>> Well, that does not guarantee a non-empty region.
>>> Consider passing [x, x+1). The assert will pass, even though the region is empty.
>>> 
>>> ~Michal
>>> 
>> 
>> Apologies, I may well be missing something here! Please could you suggest a code snippet to understand your expectation here / what you would prefer the assert to be?
>> 
>> As I understand it, with a half-open interval [base, limit) as is passed to this function, the size is  `limit - base` and so the region [x, x+1) will have size 1. The empty region starting at the same address would be [x, x). But perhaps I am making the off-by-one error here.
> Hmm, I think I made a mistake here. Region of size 1B would have base == limit
> in registers. All good then.
> 
> ~Michal
> 

Thanks for double checking. I notice you did not add your tag here, I wanted to check if you think this patch is reviewed from your perspective?

Many thanks,
Hari

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 1/6] arm/mpu: Find MPU region by range
  2025-07-15  9:48         ` Hari Limaye
@ 2025-07-15  9:59           ` Orzel, Michal
  0 siblings, 0 replies; 21+ messages in thread
From: Orzel, Michal @ 2025-07-15  9:59 UTC (permalink / raw)
  To: Hari Limaye
  Cc: xen-devel@lists.xenproject.org, Luca Fancellu, Stefano Stabellini,
	Julien Grall, Bertrand Marquis, Volodymyr Babchuk



On 15/07/2025 11:48, Hari Limaye wrote:
> Hi Michal,
> 
>> On 15 Jul 2025, at 09:45, Orzel, Michal <michal.orzel@amd.com> wrote:
>>
>>
>>
>> On 15/07/2025 10:36, Hari Limaye wrote:
>>> Hi Michal,
>>>
>>>>> +int mpumap_contains_region(pr_t *table, uint8_t nr_regions, paddr_t base,
>>>>> +                           paddr_t limit, uint8_t *index)
>>>>> +{
>>>>> +    ASSERT(index);
>>>>> +    *index = INVALID_REGION_IDX;
>>>>> +
>>>>> +    /*
>>>>> +     * The caller supplies a half-open interval [base, limit), i.e. limit is the
>>>>> +     * first byte *after* the region. Require limit strictly greater than base,
>>>>> +     * which is necessarily a non-empty region.
>>>>> +     */
>>>>> +    ASSERT(base < limit);
>>>> Well, that does not guarantee a non-empty region.
>>>> Consider passing [x, x+1). The assert will pass, even though the region is empty.
>>>>
>>>> ~Michal
>>>>
>>>
>>> Apologies, I may well be missing something here! Please could you suggest a code snippet to understand your expectation here / what you would prefer the assert to be?
>>>
>>> As I understand it, with a half-open interval [base, limit) as is passed to this function, the size is  `limit - base` and so the region [x, x+1) will have size 1. The empty region starting at the same address would be [x, x). But perhaps I am making the off-by-one error here.
>> Hmm, I think I made a mistake here. Region of size 1B would have base == limit
>> in registers. All good then.
>>
>> ~Michal
>>
> 
> Thanks for double checking. I notice you did not add your tag here, I wanted to check if you think this patch is reviewed from your perspective?
Yes.

Reviewed-by: Michal Orzel <michal.orzel@amd.com>

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems
  2025-07-15  7:45 ` [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems Hari Limaye
@ 2025-07-17 12:54   ` Orzel, Michal
  2025-07-17 12:58     ` Hari Limaye
  0 siblings, 1 reply; 21+ messages in thread
From: Orzel, Michal @ 2025-07-17 12:54 UTC (permalink / raw)
  To: Hari Limaye, xen-devel
  Cc: luca.fancellu, Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk, Ayan Kumar Halder



On 15/07/2025 09:45, Hari Limaye wrote:
> From: Luca Fancellu <luca.fancellu@arm.com>
> 
> Implement the function early_fdt_map(), which is responsible for mapping
> the Device Tree Blob in the early stages of the boot process, for MPU
> systems.
> 
> We make use of the map_pages_to_xen() and destroy_xen_mappings() APIs.
> In particular the latter function is necessary in the case that the
> initial mapping of the fdt_header is insufficient to cover the entire
> DTB, as we must destroy and then remap the region due to the APIs no
> providing support for extending the size of an existing region.
> 
> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
> Signed-off-by: Hari Limaye <hari.limaye@arm.com>
> Reviewed-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
> ---
> Changes from v1:
> - Add Ayan's R-b
> 
> Changes from v2:
> - Rename mapped_fdt_paddr -> mapped_fdt_base
> - Remove full stops
> - Add sanity check for MAX_FDT_SIZE
> - Improve comment regarding early return when DTB already mapped
> ---
>  xen/arch/arm/mpu/setup.c | 83 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 81 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/mpu/setup.c b/xen/arch/arm/mpu/setup.c
> index b4da77003f..a8cea0d9af 100644
> --- a/xen/arch/arm/mpu/setup.c
> +++ b/xen/arch/arm/mpu/setup.c
> @@ -1,17 +1,96 @@
>  /* SPDX-License-Identifier: GPL-2.0-only */
>  
> +#include <xen/bootfdt.h>
>  #include <xen/bug.h>
>  #include <xen/init.h>
> +#include <xen/libfdt/libfdt.h>
>  #include <xen/mm.h>
> +#include <xen/pfn.h>
>  #include <xen/types.h>
> +#include <xen/sizes.h>
>  #include <asm/setup.h>
>  
> +static paddr_t __initdata mapped_fdt_base = INVALID_PADDR;
> +static paddr_t __initdata mapped_fdt_limit = INVALID_PADDR;
> +
>  void __init setup_pagetables(void) {}
>  
>  void * __init early_fdt_map(paddr_t fdt_paddr)
>  {
> -    BUG_ON("unimplemented");
> -    return NULL;
> +    /* Map at least a page containing the DTB address, exclusive range */
> +    paddr_t base = round_pgdown(fdt_paddr);
> +    paddr_t limit = round_pgup(fdt_paddr + sizeof(struct fdt_header));
> +    unsigned int flags = PAGE_HYPERVISOR_RO;
> +    void *fdt_virt = (void *)fdt_paddr; /* virt == paddr for MPU */
> +    int rc;
> +    uint32_t size;
> +    unsigned long nr_mfns;
> +
> +    /*
> +     * Check whether the physical FDT address is set and meets the minimum
> +     * alignment requirement. Since we are relying on MIN_FDT_ALIGN to be at
> +     * least 8 bytes so that we always access the magic and size fields
> +     * of the FDT header after mapping the first chunk, double check if
> +     * that is indeed the case.
> +     */
> +    BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
> +    if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN )
> +        return NULL;
> +
> +    /*
> +     * DTB at this address has already been mapped.`start_xen` calls this twice,
> +     * before and after `setup_page_tables`, which is a no-op on MPU.
> +     */
> +    if ( mapped_fdt_base == fdt_paddr )
> +        return fdt_virt;
> +
> +    /*
> +     * DTB starting at a different address has been mapped, so destroy this
> +     * before continuing.
I don't understand this scenario. Can you describe it in more details?
I know that early_fdt_map will be called twice. First time, mapped_fdt_base ==
INVALID_PADDR and second time, mapped_fdt_base == fdt_paddr. What's the other
option?

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 6/6] arm/mpu: Implement remove_early_mappings for MPU systems
  2025-07-15  7:45 ` [PATCH v3 6/6] arm/mpu: Implement remove_early_mappings for " Hari Limaye
@ 2025-07-17 12:55   ` Orzel, Michal
  0 siblings, 0 replies; 21+ messages in thread
From: Orzel, Michal @ 2025-07-17 12:55 UTC (permalink / raw)
  To: Hari Limaye, xen-devel
  Cc: luca.fancellu, Stefano Stabellini, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk, Ayan Kumar Halder



On 15/07/2025 09:45, Hari Limaye wrote:
> From: Luca Fancellu <luca.fancellu@arm.com>
> 
> Implement remove_early_mappings for MPU systems.
> 
> Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
> Signed-off-by: Hari Limaye <hari.limaye@arm.com>
> Reviewed-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
> ---
> Changes from v1:
> - Add Ayan's R-b
> 
> Changes from v2:
> - Remove full stop
> - Remove sanity check for `mapped_fdt_paddr == INVALID_PADDR`
NIT: Usually such changes should result in dropping tags

Reviewed-by: Michal Orzel <michal.orzel@amd.com>

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems
  2025-07-17 12:54   ` Orzel, Michal
@ 2025-07-17 12:58     ` Hari Limaye
  2025-07-17 13:00       ` Orzel, Michal
  0 siblings, 1 reply; 21+ messages in thread
From: Hari Limaye @ 2025-07-17 12:58 UTC (permalink / raw)
  To: Orzel, Michal
  Cc: xen-devel@lists.xenproject.org, Luca Fancellu, Stefano Stabellini,
	Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Ayan Kumar Halder

Hi Michal,

> On 17 Jul 2025, at 13:54, Orzel, Michal <michal.orzel@amd.com> wrote:
>> +    /*
>> +     * DTB starting at a different address has been mapped, so destroy this
>> +     * before continuing.
> I don't understand this scenario. Can you describe it in more details?
> I know that early_fdt_map will be called twice. First time, mapped_fdt_base ==
> INVALID_PADDR and second time, mapped_fdt_base == fdt_paddr. What's the other
> option?
> 
> ~Michal
> 

This was intended as more of a sanity check than a situation that was expected to occur. Maybe you think it makes more sense to remove this and just add an assert that `mapped_fdt_base == INVALID_PADDR` here?

Cheers,
Hari

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems
  2025-07-17 12:58     ` Hari Limaye
@ 2025-07-17 13:00       ` Orzel, Michal
  2025-07-17 13:05         ` Luca Fancellu
  0 siblings, 1 reply; 21+ messages in thread
From: Orzel, Michal @ 2025-07-17 13:00 UTC (permalink / raw)
  To: Hari Limaye
  Cc: xen-devel@lists.xenproject.org, Luca Fancellu, Stefano Stabellini,
	Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Ayan Kumar Halder



On 17/07/2025 14:58, Hari Limaye wrote:
> Hi Michal,
> 
>> On 17 Jul 2025, at 13:54, Orzel, Michal <michal.orzel@amd.com> wrote:
>>> +    /*
>>> +     * DTB starting at a different address has been mapped, so destroy this
>>> +     * before continuing.
>> I don't understand this scenario. Can you describe it in more details?
>> I know that early_fdt_map will be called twice. First time, mapped_fdt_base ==
>> INVALID_PADDR and second time, mapped_fdt_base == fdt_paddr. What's the other
>> option?
>>
>> ~Michal
>>
> 
> This was intended as more of a sanity check than a situation that was expected to occur. Maybe you think it makes more sense to remove this and just add an assert that `mapped_fdt_base == INVALID_PADDR` here?
Yes, assert would be much better here. I can't think of a scenario, where
fdt_paddr would differ depending on the call.

~Michal



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems
  2025-07-17 13:00       ` Orzel, Michal
@ 2025-07-17 13:05         ` Luca Fancellu
  0 siblings, 0 replies; 21+ messages in thread
From: Luca Fancellu @ 2025-07-17 13:05 UTC (permalink / raw)
  To: Orzel, Michal
  Cc: Hari Limaye, xen-devel@lists.xenproject.org, Stefano Stabellini,
	Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Ayan Kumar Halder

Hi Michal,

> On 17 Jul 2025, at 14:00, Orzel, Michal <michal.orzel@amd.com> wrote:
> 
> 
> 
> On 17/07/2025 14:58, Hari Limaye wrote:
>> Hi Michal,
>> 
>>> On 17 Jul 2025, at 13:54, Orzel, Michal <michal.orzel@amd.com> wrote:
>>>> +    /*
>>>> +     * DTB starting at a different address has been mapped, so destroy this
>>>> +     * before continuing.
>>> I don't understand this scenario. Can you describe it in more details?
>>> I know that early_fdt_map will be called twice. First time, mapped_fdt_base ==
>>> INVALID_PADDR and second time, mapped_fdt_base == fdt_paddr. What's the other
>>> option?
>>> 
>>> ~Michal
>>> 
>> 
>> This was intended as more of a sanity check than a situation that was expected to occur. Maybe you think it makes more sense to remove this and just add an assert that `mapped_fdt_base == INVALID_PADDR` here?
> Yes, assert would be much better here. I can't think of a scenario, where
> fdt_paddr would differ depending on the call.

so you are right it can’t happen today, this was put in place in case between two different call the DTB was relocated somewhere else in the future.
It’s not the case right now, but we thought about that when doing this function.

Anyway if you think the complexity is not worth we can add just an assert there.

Cheers,
Luca


^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2025-07-17 13:06 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-15  7:45 [PATCH v3 0/6] Second series for R82 MPU Support Hari Limaye
2025-07-15  7:45 ` [PATCH v3 1/6] arm/mpu: Find MPU region by range Hari Limaye
2025-07-15  8:08   ` Orzel, Michal
2025-07-15  8:36     ` Hari Limaye
2025-07-15  8:45       ` Orzel, Michal
2025-07-15  9:48         ` Hari Limaye
2025-07-15  9:59           ` Orzel, Michal
2025-07-15  7:45 ` [PATCH v3 2/6] xen/arm: Introduce flags_has_rwx helper Hari Limaye
2025-07-15  7:45 ` [PATCH v3 3/6] arm/mpu: Populate a new region in Xen MPU mapping table Hari Limaye
2025-07-15  8:20   ` Orzel, Michal
2025-07-15  8:51     ` Hari Limaye
2025-07-15  8:52       ` Orzel, Michal
2025-07-15  7:45 ` [PATCH v3 4/6] arm/mpu: Destroy an existing entry in Xen MPU memory " Hari Limaye
2025-07-15  8:51   ` Orzel, Michal
2025-07-15  7:45 ` [PATCH v3 5/6] arm/mpu: Implement early_fdt_map support in MPU systems Hari Limaye
2025-07-17 12:54   ` Orzel, Michal
2025-07-17 12:58     ` Hari Limaye
2025-07-17 13:00       ` Orzel, Michal
2025-07-17 13:05         ` Luca Fancellu
2025-07-15  7:45 ` [PATCH v3 6/6] arm/mpu: Implement remove_early_mappings for " Hari Limaye
2025-07-17 12:55   ` Orzel, Michal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.