linker: Create sections from zephyr,memory-region nodes

Currently when a node has a 'zephyr,memory-region' compatible and a
'zephyr,memory-region' string property, a new memory region is created
in the linker script.

Having a memory region without a section to place variables in could be
not that useful. With this patch we extend the memory-region mechanism
to also create sections.

The user can then place variables in the sections as usual by using for
example the GCC attributes.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
diff --git a/cmake/linker_script/arm/linker.cmake b/cmake/linker_script/arm/linker.cmake
index c557dfb..231c9df 100644
--- a/cmake/linker_script/arm/linker.cmake
+++ b/cmake/linker_script/arm/linker.cmake
@@ -195,3 +195,8 @@
 zephyr_linker_section_configure(SECTION .bss ANY FLAGS "+ZI")
 
 include(${COMMON_ZEPHYR_LINKER_DIR}/debug-sections.cmake)
+
+dt_comp_path(paths COMPATIBLE "zephyr,memory-region")
+foreach(path IN LISTS paths)
+  zephyr_linker_dts_section(PATH ${path})
+endforeach()
diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake
index 0b1ee6b..efcbb98 100644
--- a/cmake/modules/extensions.cmake
+++ b/cmake/modules/extensions.cmake
@@ -3334,6 +3334,53 @@
 endmacro()
 
 # Usage:
+#   zephyr_linker_dts_section(PATH <path>)
+#
+# Zephyr linker devicetree memory section from path.
+#
+# This function specifies an output section for the platform in use based on its
+# devicetree configuration.
+#
+# The section will only be defined if the devicetree exists and has status okay.
+#
+# PATH <path>      : Devicetree node path.
+#
+function(zephyr_linker_dts_section)
+  set(single_args "PATH")
+  cmake_parse_arguments(DTS_SECTION "" "${single_args}" "" ${ARGN})
+
+  if(DTS_SECTION_UNPARSED_ARGUMENTS)
+    message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) given unknown "
+	    "arguments: ${DTS_SECTION_UNPARSED_ARGUMENTS}"
+    )
+  endif()
+
+  if(NOT DEFINED DTS_SECTION_PATH)
+    message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) missing "
+                        "required argument: PATH"
+    )
+  endif()
+
+  dt_node_exists(exists PATH ${DTS_SECTION_PATH})
+  if(NOT ${exists})
+    return()
+  endif()
+
+  dt_prop(name PATH ${DTS_SECTION_PATH} PROPERTY "zephyr,memory-region")
+  if(NOT DEFINED name)
+    message(FATAL_ERROR "zephyr_linker_dts_section(${ARGV0} ...) missing "
+                        "\"zephyr,memory-region\" property"
+    )
+  endif()
+  zephyr_string(SANITIZE name ${name})
+
+  dt_reg_addr(addr PATH ${DTS_SECTION_PATH})
+
+  zephyr_linker_section(NAME ${name} ADDRESS ${addr} VMA ${name} TYPE NOLOAD)
+
+endfunction()
+
+# Usage:
 #   zephyr_linker_dts_memory(PATH <path> FLAGS <flags>)
 #   zephyr_linker_dts_memory(NODELABEL <nodelabel> FLAGS <flags>)
 #   zephyr_linker_dts_memory(CHOSEN <prop> FLAGS <flags>)
diff --git a/include/arch/arm/aarch32/cortex_a_r/scripts/linker.ld b/include/arch/arm/aarch32/cortex_a_r/scripts/linker.ld
index e231b6d..5c9ab3f 100644
--- a/include/arch/arm/aarch32/cortex_a_r/scripts/linker.ld
+++ b/include/arch/arm/aarch32/cortex_a_r/scripts/linker.ld
@@ -383,6 +383,9 @@
         KEEP(*(.gnu.attributes))
     }
 
+    /* Sections generated from 'zephyr,memory-region' nodes */
+    LINKER_DT_SECTIONS()
+
     /* Must be last in romable region */
     SECTION_PROLOGUE(.last_section,(NOLOAD),)
     {
diff --git a/include/arch/arm/aarch32/cortex_m/scripts/linker.ld b/include/arch/arm/aarch32/cortex_m/scripts/linker.ld
index 3681ccb..82d46ef 100644
--- a/include/arch/arm/aarch32/cortex_m/scripts/linker.ld
+++ b/include/arch/arm/aarch32/cortex_m/scripts/linker.ld
@@ -437,6 +437,9 @@
 	KEEP(*(.gnu.attributes))
 	}
 
+    /* Sections generated from 'zephyr,memory-region' nodes */
+    LINKER_DT_SECTIONS()
+
 /* Must be last in romable region */
 SECTION_PROLOGUE(.last_section,(NOLOAD),)
 {
diff --git a/include/linker/devicetree_regions.h b/include/linker/devicetree_regions.h
index 5307c34..638e9d1 100644
--- a/include/linker/devicetree_regions.h
+++ b/include/linker/devicetree_regions.h
@@ -39,6 +39,13 @@
 
 #define _DT_COMPATIBLE	zephyr_memory_region
 
+#define _DT_SECTION_NAME(node_id)	DT_STRING_TOKEN(node_id, zephyr_memory_region)
+#define _DT_SECTION_PREFIX(node_id)	UTIL_CAT(__, _DT_SECTION_NAME(node_id))
+#define _DT_SECTION_START(node_id)	UTIL_CAT(_DT_SECTION_PREFIX(node_id), _start)
+#define _DT_SECTION_END(node_id)	UTIL_CAT(_DT_SECTION_PREFIX(node_id), _end)
+#define _DT_SECTION_SIZE(node_id)	UTIL_CAT(_DT_SECTION_PREFIX(node_id), _size)
+#define _DT_SECTION_LOAD(node_id)	UTIL_CAT(_DT_SECTION_PREFIX(node_id), _load_start)
+
 /**
  * @brief Declare a memory region
  *
@@ -50,6 +57,23 @@
 	ORIGIN = DT_REG_ADDR(node_id),	      \
 	LENGTH = DT_REG_SIZE(node_id)
 
+/**
+ * @brief Declare a memory section from the device tree nodes with
+ *	  compatible 'zephyr,memory-region'
+ *
+ * @param node_id devicetree node identifier
+ */
+#define _SECTION_DECLARE(node_id)								\
+	_DT_SECTION_NAME(node_id) DT_REG_ADDR(node_id) (NOLOAD) :				\
+	{											\
+		_DT_SECTION_START(node_id) = .;							\
+		KEEP(*(_DT_SECTION_NAME(node_id)))						\
+		KEEP(*(_DT_SECTION_NAME(node_id).*))						\
+		_DT_SECTION_END(node_id) = .;							\
+	} > _DT_SECTION_NAME(node_id)								\
+	_DT_SECTION_SIZE(node_id) = _DT_SECTION_END(node_id) - _DT_SECTION_START(node_id);	\
+	_DT_SECTION_LOAD(node_id) = LOADADDR(_DT_SECTION_NAME(node_id));
+
 /** @endcond */
 
 /**
@@ -62,3 +86,10 @@
  */
 #define LINKER_DT_REGIONS() \
 	DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _REGION_DECLARE)
+
+/**
+ * @brief Generate linker memory sections from the device tree nodes with
+ *        compatible 'zephyr,memory-region'
+ */
+#define LINKER_DT_SECTIONS() \
+	DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _SECTION_DECLARE)
diff --git a/scripts/dts/gen_dts_cmake.py b/scripts/dts/gen_dts_cmake.py
index f3be6a0..8dc0f2e4 100755
--- a/scripts/dts/gen_dts_cmake.py
+++ b/scripts/dts/gen_dts_cmake.py
@@ -148,6 +148,9 @@
         for path in compatible2paths[comp]:
             cmake_path = f'{cmake_path}{path};'
 
+        # Remove the last ';'
+        cmake_path = cmake_path[:-1]
+
         cmake_comp = f'DT_COMP|{comp}'
         cmake_props.append(f'"{cmake_comp}" "{cmake_path}"')