kernel: mmu: add direct-map support in z_phys_map()

Many RTOS applications assume the virtual and physical address
is 1:1 mapping, so add the 1:1 mapping support in z_phys_map()
to easy adapt these applications.

Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
diff --git a/include/zephyr/sys/mem_manage.h b/include/zephyr/sys/mem_manage.h
index 7a87a95..562f65c 100644
--- a/include/zephyr/sys/mem_manage.h
+++ b/include/zephyr/sys/mem_manage.h
@@ -55,6 +55,13 @@
 #define K_MEM_PERM_USER		BIT(5)
 
 /*
+ * Region mapping behaviour attributes
+ */
+
+/** Region will be mapped to 1:1 virtual and physical address */
+#define K_MEM_DIRECT_MAP	BIT(6)
+
+/*
  * This is the offset to subtract from a virtual address mapped in the
  * kernel's permanent mapping of RAM, to obtain its physical address.
  *
diff --git a/kernel/Kconfig.vm b/kernel/Kconfig.vm
index 215eb98..1845c24 100644
--- a/kernel/Kconfig.vm
+++ b/kernel/Kconfig.vm
@@ -80,6 +80,22 @@
 	  implement a notion of "high" memory in Zephyr to work around physical
 	  RAM size larger than the defined bounds of the virtual address space.
 
+config KERNEL_DIRECT_MAP
+	bool "Memory region direct-map support"
+	depends on MMU
+	help
+	  This enables the direct-map support, namely the region can be 1:1
+	  mapping between virtual address and physical address.
+
+	  If the specific memory region is in the virtual memory space and
+	  there isn't overlap with the existed mappings, it will reserve the
+	  region from the virtual memory space and do the mapping, otherwise
+	  it will fail. And any attempt across the boundary of the virtual
+	  memory space will fail.
+
+	  Note that this is for compatibility and portable apps shouldn't
+	  be using it.
+
 endif # KERNEL_VM_SUPPORT
 
 menuconfig MMU
diff --git a/kernel/mmu.c b/kernel/mmu.c
index 21bc27d..09af04a 100644
--- a/kernel/mmu.c
+++ b/kernel/mmu.c
@@ -237,9 +237,11 @@
 		virt_region_init();
 	}
 
+#ifndef CONFIG_KERNEL_DIRECT_MAP
 	__ASSERT((vaddr_u8 >= Z_VIRT_REGION_START_ADDR)
 		 && ((vaddr_u8 + size - 1) < Z_VIRT_REGION_END_ADDR),
 		 "invalid virtual address region %p (%zu)", vaddr_u8, size);
+#endif
 	if (!((vaddr_u8 >= Z_VIRT_REGION_START_ADDR)
 	      && ((vaddr_u8 + size - 1) < Z_VIRT_REGION_END_ADDR))) {
 		return;
@@ -721,7 +723,12 @@
 	size_t aligned_size, align_boundary;
 	k_spinlock_key_t key;
 	uint8_t *dest_addr;
+	size_t num_bits;
+	size_t offset;
 
+#ifndef CONFIG_KERNEL_DIRECT_MAP
+	__ASSERT(!(flags & K_MEM_DIRECT_MAP), "The direct-map is not enabled");
+#endif
 	addr_offset = k_mem_region_align(&aligned_phys, &aligned_size,
 					 phys, size,
 					 CONFIG_MMU_PAGE_SIZE);
@@ -733,10 +740,23 @@
 	align_boundary = arch_virt_region_align(aligned_phys, aligned_size);
 
 	key = k_spin_lock(&z_mm_lock);
-	/* Obtain an appropriately sized chunk of virtual memory */
-	dest_addr = virt_region_alloc(aligned_size, align_boundary);
-	if (!dest_addr) {
-		goto fail;
+	if (flags & K_MEM_DIRECT_MAP) {
+		dest_addr = (uint8_t *)aligned_phys;
+		/* Reserve from the virtual memory space */
+		if (!(dest_addr + aligned_size < Z_VIRT_RAM_START ||
+		    dest_addr > Z_VIRT_RAM_END)) {
+			num_bits = aligned_size / CONFIG_MMU_PAGE_SIZE;
+			offset = virt_to_bitmap_offset(dest_addr, aligned_size);
+			if (sys_bitarray_test_and_set_region(
+			    &virt_region_bitmap, num_bits, offset, true))
+				goto fail;
+		}
+	} else {
+		/* Obtain an appropriately sized chunk of virtual memory */
+		dest_addr = virt_region_alloc(aligned_size, align_boundary);
+		if (!dest_addr) {
+			goto fail;
+		}
 	}
 
 	/* If this fails there's something amiss with virt_region_get */