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 */