1 /* 2 * Copyright (c) 2021, Commonwealth Scientific and Industrial Research 3 * Organisation (CSIRO) ABN 41 687 119 230. 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 * 7 * Generate memory regions from devicetree nodes. 8 */ 9 10 #ifndef ZEPHYR_INCLUDE_LINKER_DEVICETREE_REGIONS_H_ 11 #define ZEPHYR_INCLUDE_LINKER_DEVICETREE_REGIONS_H_ 12 13 #include <zephyr/devicetree.h> 14 #include <zephyr/sys/util.h> 15 #include <zephyr/toolchain.h> 16 17 /** 18 * @brief Get the linker memory-region name in a token form 19 * 20 * This attempts to use the zephyr,memory-region property (with 21 * non-alphanumeric characters replaced with underscores) returning a token. 22 * 23 * Example devicetree fragment: 24 * 25 * @code{.dts} 26 * / { 27 * soc { 28 * sram1: memory@2000000 { 29 * zephyr,memory-region = "MY_NAME"; 30 * }; 31 * sram2: memory@2001000 { 32 * zephyr,memory-region = "MY@OTHER@NAME"; 33 * }; 34 * }; 35 * }; 36 * @endcode 37 * 38 * Example usage: 39 * 40 * @code{.c} 41 * LINKER_DT_NODE_REGION_NAME_TOKEN(DT_NODELABEL(sram1)) // MY_NAME 42 * LINKER_DT_NODE_REGION_NAME_TOKEN(DT_NODELABEL(sram2)) // MY_OTHER_NAME 43 * @endcode 44 * 45 * @param node_id node identifier 46 * @return the name of the memory memory region the node will generate 47 */ 48 #define LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) \ 49 DT_STRING_TOKEN(node_id, zephyr_memory_region) 50 51 /** 52 * @brief Get the linker memory-region name 53 * 54 * This attempts to use the zephyr,memory-region property (with 55 * non-alphanumeric characters replaced with underscores). 56 * 57 * Example devicetree fragment: 58 * 59 * @code{.dts} 60 * / { 61 * soc { 62 * sram1: memory@2000000 { 63 * zephyr,memory-region = "MY_NAME"; 64 * }; 65 * sram2: memory@2001000 { 66 * zephyr,memory-region = "MY@OTHER@NAME"; 67 * }; 68 * }; 69 * }; 70 * @endcode 71 * 72 * Example usage: 73 * 74 * @code{.c} 75 * LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram1)) // "MY_NAME" 76 * LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(sram2)) // "MY_OTHER_NAME" 77 * @endcode 78 * 79 * @param node_id node identifier 80 * @return the name of the memory memory region the node will generate 81 */ 82 #define LINKER_DT_NODE_REGION_NAME(node_id) \ 83 STRINGIFY(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id)) 84 85 #define _DT_MEMORY_REGION_FLAGS_TOKEN(n) DT_STRING_TOKEN(n, zephyr_memory_region_flags) 86 #define _DT_MEMORY_REGION_FLAGS_UNQUOTED(n) DT_STRING_UNQUOTED(n, zephyr_memory_region_flags) 87 88 #define _LINKER_L_PAREN ( 89 #define _LINKER_R_PAREN ) 90 #define _LINKER_ENCLOSE_PAREN(x) _LINKER_L_PAREN x _LINKER_R_PAREN 91 92 #define _LINKER_IS_EMPTY_TOKEN_ 1 93 #define _LINKER_IS_EMPTY_TOKEN_EXPAND(x) _LINKER_IS_EMPTY_TOKEN_##x 94 #define _LINKER_IS_EMPTY_TOKEN(x) _LINKER_IS_EMPTY_TOKEN_EXPAND(x) 95 96 /** 97 * @brief Get the linker memory-region flags with parentheses. 98 * 99 * This attempts to return the zephyr,memory-region-flags property 100 * with parentheses. 101 * Return empty string if not set the property. 102 * 103 * Example devicetree fragment: 104 * 105 * @code{.dts} 106 * / { 107 * soc { 108 * rx: memory@2000000 { 109 * zephyr,memory-region = "READ_EXEC"; 110 * zephyr,memory-region-flags = "rx"; 111 * }; 112 * rx_not_w: memory@2001000 { 113 * zephyr,memory-region = "READ_EXEC_NOT_WRITE"; 114 * zephyr,memory-region-flags = "rx!w"; 115 * }; 116 * no_flags: memory@2001000 { 117 * zephyr,memory-region = "NO_FLAGS"; 118 * }; 119 * }; 120 * }; 121 * @endcode 122 * 123 * Example usage: 124 * 125 * @code{.c} 126 * LINKER_DT_NODE_REGION_FLAGS(DT_NODELABEL(rx)) // (rx) 127 * LINKER_DT_NODE_REGION_FLAGS(DT_NODELABEL(rx_not_w)) // (rx!w) 128 * LINKER_DT_NODE_REGION_FLAGS(DT_NODELABEL(no_flags)) // [flags will not be specified] 129 * @endcode 130 * 131 * @param node_id node identifier 132 * @return the value of the memory region flag specified in the device tree 133 * enclosed in parentheses. 134 */ 135 136 #define LINKER_DT_NODE_REGION_FLAGS(node_id) \ 137 COND_CODE_1(DT_NODE_HAS_PROP(node_id, zephyr_memory_region_flags), \ 138 (COND_CODE_1(_LINKER_IS_EMPTY_TOKEN(_DT_MEMORY_REGION_FLAGS_TOKEN(node_id)), \ 139 (), \ 140 (_LINKER_ENCLOSE_PAREN( \ 141 _DT_MEMORY_REGION_FLAGS_UNQUOTED(node_id)) \ 142 ))), \ 143 (_LINKER_ENCLOSE_PAREN(rw))) 144 145 /** @cond INTERNAL_HIDDEN */ 146 147 #define _DT_COMPATIBLE zephyr_memory_region 148 149 #define _DT_SECTION_PREFIX(node_id) UTIL_CAT(__, LINKER_DT_NODE_REGION_NAME_TOKEN(node_id)) 150 #define _DT_SECTION_START(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _start) 151 #define _DT_SECTION_END(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _end) 152 #define _DT_SECTION_SIZE(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _size) 153 #define _DT_SECTION_LOAD(node_id) UTIL_CAT(_DT_SECTION_PREFIX(node_id), _load_start) 154 155 /** 156 * @brief Declare a memory region 157 * 158 * Example devicetree fragment: 159 * 160 * @code{.dts} 161 * test_sram: sram@20010000 { 162 * compatible = "zephyr,memory-region", "mmio-sram"; 163 * reg = < 0x20010000 0x1000 >; 164 * zephyr,memory-region = "FOOBAR"; 165 * zephyr,memory-region-flags = "rw"; 166 * }; 167 * @endcode 168 * 169 * will result in: 170 * 171 * @code{.unparsed} 172 * FOOBAR (rw) : ORIGIN = (0x20010000), LENGTH = (0x1000) 173 * @endcode 174 * 175 * @param node_id devicetree node identifier 176 * @param attr region attributes 177 */ 178 #define _REGION_DECLARE(node_id) \ 179 LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) \ 180 LINKER_DT_NODE_REGION_FLAGS(node_id) \ 181 : ORIGIN = DT_REG_ADDR(node_id), \ 182 LENGTH = DT_REG_SIZE(node_id) 183 184 /** 185 * @brief Declare a memory section from the device tree nodes with 186 * compatible 'zephyr,memory-region' 187 * 188 * Example devicetree fragment: 189 * 190 * @code{.dts} 191 * test_sram: sram@20010000 { 192 * compatible = "zephyr,memory-region", "mmio-sram"; 193 * reg = < 0x20010000 0x1000 >; 194 * zephyr,memory-region = "FOOBAR"; 195 * }; 196 * @endcode 197 * 198 * will result in: 199 * 200 * @code{.unparsed} 201 * FOOBAR (NOLOAD) : 202 * { 203 * __FOOBAR_start = .; 204 * KEEP(*(FOOBAR)) 205 * KEEP(*(FOOBAR.*)) 206 * __FOOBAR_end = .; 207 * } > FOOBAR 208 * __FOOBAR_size = __FOOBAR_end - __FOOBAR_start; 209 * __FOOBAR_load_start = LOADADDR(FOOBAR); 210 * @endcode 211 * 212 * @param node_id devicetree node identifier 213 */ 214 #define _SECTION_DECLARE(node_id) \ 215 LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) (NOLOAD) : \ 216 { \ 217 _DT_SECTION_START(node_id) = .; \ 218 KEEP(*(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id))) \ 219 KEEP(*(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id).*)) \ 220 _DT_SECTION_END(node_id) = .; \ 221 } > LINKER_DT_NODE_REGION_NAME_TOKEN(node_id) \ 222 _DT_SECTION_SIZE(node_id) = _DT_SECTION_END(node_id) - _DT_SECTION_START(node_id); \ 223 _DT_SECTION_LOAD(node_id) = LOADADDR(LINKER_DT_NODE_REGION_NAME_TOKEN(node_id)); 224 225 /** @endcond */ 226 227 /** 228 * @brief Generate linker memory regions from the device tree nodes with 229 * compatible 'zephyr,memory-region' 230 * 231 * Note: for now we do not deal with MEMORY attributes since those are 232 * optional, not actually used by Zephyr and they will likely conflict with the 233 * MPU configuration. 234 */ 235 #define LINKER_DT_REGIONS() \ 236 DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _REGION_DECLARE) 237 238 /** 239 * @brief Generate linker memory sections from the device tree nodes with 240 * compatible 'zephyr,memory-region' 241 */ 242 #define LINKER_DT_SECTIONS() \ 243 DT_FOREACH_STATUS_OKAY(_DT_COMPATIBLE, _SECTION_DECLARE) 244 245 #endif /* ZEPHYR_INCLUDE_LINKER_DEVICETREE_REGIONS_H_ */ 246