arm64: demand_paging: add support for on-demand mappings

This makes ARM64 compatible with K_MEM_MAP_UNPAGED.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
diff --git a/arch/arm64/core/mmu.c b/arch/arm64/core/mmu.c
index 85bae34..a914916 100644
--- a/arch/arm64/core/mmu.c
+++ b/arch/arm64/core/mmu.c
@@ -243,8 +243,15 @@
 
 static void set_pte_block_desc(uint64_t *pte, uint64_t desc, unsigned int level)
 {
-	if (desc) {
-		desc |= (level == XLAT_LAST_LEVEL) ? PTE_PAGE_DESC : PTE_BLOCK_DESC;
+	if (level != XLAT_LAST_LEVEL) {
+		desc |= PTE_BLOCK_DESC;
+	} else if (!IS_ENABLED(CONFIG_DEMAND_PAGING) || (desc & PTE_BLOCK_DESC_AF) != 0) {
+		desc |= PTE_PAGE_DESC;
+	} else {
+		/*
+		 * Demand paging configured and AF unset: leave the descriptor
+		 * type to "invalid" as in arch_mem_page_out().
+		 */
 	}
 	*pte = desc;
 	debug_show_pte(pte, level);
@@ -677,6 +684,11 @@
 
 	/* the access flag */
 	desc |= PTE_BLOCK_DESC_AF;
+	if (IS_ENABLED(CONFIG_DEMAND_PAGING) && (attrs & MT_PAGED_OUT) != 0) {
+		/* set it up for demand paging like arch_mem_page_out() */
+		desc &= ~PTE_BLOCK_DESC_AF;
+		desc |= PTE_BLOCK_DESC_AP_RO;
+	}
 
 	/* memory attribute index field */
 	mem_type = MT_TYPE(attrs);
@@ -1090,6 +1102,10 @@
 		entry_flags |= MT_RW_AP_ELx;
 	}
 
+	if (IS_ENABLED(CONFIG_DEMAND_PAGING) && (flags & K_MEM_MAP_UNPAGED) != 0) {
+		entry_flags |= MT_PAGED_OUT;
+	}
+
 	return add_map(ptables, "generic", phys, (uintptr_t)virt, size, entry_flags);
 }
 
diff --git a/include/zephyr/arch/arm64/arm_mmu.h b/include/zephyr/arch/arm64/arm_mmu.h
index 7b6ce32..450a823 100644
--- a/include/zephyr/arch/arm64/arm_mmu.h
+++ b/include/zephyr/arch/arm64/arm_mmu.h
@@ -45,6 +45,7 @@
  * attrs[7] : Mirror RO/RW permissions to EL0
  * attrs[8] : Overwrite existing mapping if any
  * attrs[9] : non-Global mapping (nG)
+ * attrs[10]: Paged-out mapping
  *
  */
 #define MT_PERM_SHIFT		3U
@@ -54,6 +55,7 @@
 #define MT_RW_AP_SHIFT		7U
 #define MT_NO_OVERWRITE_SHIFT	8U
 #define MT_NON_GLOBAL_SHIFT	9U
+#define MT_PAGED_OUT_SHIFT	10U
 
 #define MT_RO			(0U << MT_PERM_SHIFT)
 #define MT_RW			(1U << MT_PERM_SHIFT)
@@ -75,6 +77,8 @@
 #define MT_G			(0U << MT_NON_GLOBAL_SHIFT)
 #define MT_NG			(1U << MT_NON_GLOBAL_SHIFT)
 
+#define MT_PAGED_OUT		(1U << MT_PAGED_OUT_SHIFT)
+
 #define MT_P_RW_U_RW		(MT_RW | MT_RW_AP_ELx | MT_P_EXECUTE_NEVER | MT_U_EXECUTE_NEVER)
 #define MT_P_RW_U_NA		(MT_RW | MT_RW_AP_EL_HIGHER  | MT_P_EXECUTE_NEVER | MT_U_EXECUTE_NEVER)
 #define MT_P_RO_U_RO		(MT_RO | MT_RW_AP_ELx | MT_P_EXECUTE_NEVER | MT_U_EXECUTE_NEVER)
@@ -95,6 +99,13 @@
 #define ARCH_DATA_PAGE_DIRTY		BIT(2)
 #define ARCH_DATA_PAGE_NOT_MAPPED	BIT(3)
 
+/*
+ * Special unpaged "location" tags (highest possible descriptor physical
+ * address values unlikely to conflict with backing store locations)
+ */
+#define ARCH_UNPAGED_ANON_ZERO		0x0000fffffffff000
+#define ARCH_UNPAGED_ANON_UNINIT	0x0000ffffffffe000
+
 #ifndef _ASMLANGUAGE
 
 /* Region definition data structure */