This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 55cd85c9aba arch/arm64: Map a region that does not start at a page 
table boundary.
55cd85c9aba is described below

commit 55cd85c9aba7ec073250ccebddfb947290e8b3af
Author: Marco Casaroli <[email protected]>
AuthorDate: Fri Oct 9 00:17:03 2026 +0200

    arch/arm64: Map a region that does not start at a page table boundary.
    
    create_region() mapped up to ENTRIES_PER_PGT pages through one final
    level table, from whatever address the region started at.  The text
    region starts one page after the reserved area, so a region that
    crossed the end of the table wrapped around and mapped its last pages
    over the first entries of the same table.  In a program with more than
    about 2 MB of text, the reserved area became read-only and the kernel
    faulted in umm_initialize().
    
    Walk the region one final level table at a time.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 arch/arm64/src/common/arm64_addrenv_mmu.c | 40 ++++++++++++++++++++-----------
 1 file changed, 26 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/src/common/arm64_addrenv_mmu.c 
b/arch/arm64/src/common/arm64_addrenv_mmu.c
index 686ebb04ede..c4f4e3c79d0 100644
--- a/arch/arm64/src/common/arm64_addrenv_mmu.c
+++ b/arch/arm64/src/common/arm64_addrenv_mmu.c
@@ -267,14 +267,13 @@ static int create_region(arch_addrenv_t *addrenv, 
uintptr_t vaddr,
   uintptr_t ptlast;
   uintptr_t ptprev;
   uintptr_t paddr;
+  uintptr_t vend;
+  uintptr_t tend;
   uint32_t  ptlevel;
   int       npages;
-  int       nmapped;
-  int       i;
-  int       j;
 
-  nmapped   = 0;
   npages    = MM_NPAGES(size);
+  vend      = vaddr + ((uintptr_t)npages << MM_PGSHIFT);
   ptlevel   = MMU_PGT_LEVEL_MAX - 1;
   ptprev    = arm64_pgvaddr(addrenv->spgtables[ptlevel]);
 
@@ -284,8 +283,19 @@ static int create_region(arch_addrenv_t *addrenv, 
uintptr_t vaddr,
 
   /* Begin allocating memory for the page tables */
 
-  for (i = 0; i < npages; i += ENTRIES_PER_PGT)
+  while (vaddr < vend)
     {
+      /* One final level table maps ENTRIES_PER_PGT pages.  The region need
+       * not start at the beginning of a table, so stop at the end of this
+       * one and look up the next.
+       */
+
+      tend = (vaddr | ((ENTRIES_PER_PGT << MM_PGSHIFT) - 1)) + 1;
+      if (tend > vend || tend == 0)
+        {
+          tend = vend;
+        }
+
       /* Get the current final level entry corresponding to this vaddr */
 
       paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr));
@@ -313,13 +323,7 @@ static int create_region(arch_addrenv_t *addrenv, 
uintptr_t vaddr,
 
       /* Then allocate memory for the region data */
 
-      for (j = 0;
-#ifdef CONFIG_PAGING
-           j < 1;
-#else
-           j < ENTRIES_PER_PGT && nmapped < size;
-#endif
-           j++)
+      do
         {
           paddr = mm_pgalloc(1);
           if (!paddr)
@@ -334,9 +338,17 @@ static int create_region(arch_addrenv_t *addrenv, 
uintptr_t vaddr,
           /* Then map the virtual address to the physical address */
 
           mmu_ln_setentry(ptlevel + 1, ptlast, paddr, vaddr, mmuflags);
-          nmapped += MM_PGSIZE;
-          vaddr   += MM_PGSIZE;
+          vaddr += MM_PGSIZE;
         }
+#ifdef CONFIG_PAGING
+      while (0);
+
+      /* Only the first page of each table; the rest come on demand */
+
+      vaddr = tend;
+#else
+      while (vaddr < tend);
+#endif
     }
 
   /* Synchronize data and instruction pipelines */

Reply via email to