1 /*
2  * Copyright (c) 2017 Linaro Limited.
3  * Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/device.h>
9 #include <zephyr/init.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/barrier.h>
12 #include "arm_core_mpu_dev.h"
13 #include <zephyr/linker/linker-defs.h>
14 #include <kernel_arch_data.h>
15 #include <zephyr/mem_mgmt/mem_attr.h>
16 #include <zephyr/dt-bindings/memory-attr/memory-attr-arm.h>
17 #include <zephyr/arch/arm/mpu/arm_mpu.h>
18 
19 #define LOG_LEVEL CONFIG_MPU_LOG_LEVEL
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_DECLARE(mpu);
22 
23 #if Z_ARM_CPU_HAS_PMSAV8_MPU
24 #define ATTRIBUTE_AND_SIZE_REG_NAME RLAR
25 #else
26 #define ATTRIBUTE_AND_SIZE_REG_NAME RASR
27 #endif
28 
29 #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)
30 /* The order here is on purpose since ARMv8-M SoCs may define
31  * CONFIG_ARMV6_M_ARMV8_M_BASELINE or CONFIG_ARMV7_M_ARMV8_M_MAINLINE
32  * so we want to check for ARMv8-M first.
33  */
34 #define MPU_NODEID DT_INST(0, arm_armv8m_mpu)
35 #elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
36 #define MPU_NODEID DT_INST(0, arm_armv7m_mpu)
37 #elif defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
38 #define MPU_NODEID DT_INST(0, arm_armv6m_mpu)
39 #endif
40 
41 #define NODE_HAS_PROP_AND_OR(node_id, prop) \
42 	DT_NODE_HAS_PROP(node_id, prop) ||
43 
44 BUILD_ASSERT((DT_FOREACH_STATUS_OKAY_NODE_VARGS(
45 	      NODE_HAS_PROP_AND_OR, zephyr_memory_region_mpu) false) == false,
46 	      "`zephyr,memory-region-mpu` was deprecated in favor of `zephyr,memory-attr`");
47 
48 #define NULL_PAGE_DETECT_NODE_FINDER(node_id, prop)                                                \
49 	(DT_NODE_HAS_PROP(node_id, prop) && (DT_REG_ADDR(node_id) == 0) &&                         \
50 	 (DT_REG_SIZE(node_id) >= CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE)) ||
51 
52 #define DT_NULL_PAGE_DETECT_NODE_EXIST                                                             \
53 	(DT_FOREACH_STATUS_OKAY_VARGS(zephyr_memory_region, NULL_PAGE_DETECT_NODE_FINDER,          \
54 				      zephyr_memory_attr) false)
55 
56 /*
57  * Global status variable holding the number of HW MPU region indices, which
58  * have been reserved by the MPU driver to program the static (fixed) memory
59  * regions.
60  */
61 static uint8_t static_regions_num;
62 
63 /* Include architecture-specific internal headers. */
64 #if defined(CONFIG_CPU_CORTEX_M0PLUS) || \
65 	defined(CONFIG_CPU_CORTEX_M3) || \
66 	defined(CONFIG_CPU_CORTEX_M4) || \
67 	defined(CONFIG_CPU_CORTEX_M7) || \
68 	defined(CONFIG_ARMV7_R)
69 #include "arm_mpu_v7_internal.h"
70 #elif defined(CONFIG_CPU_CORTEX_M23) || \
71 	defined(CONFIG_CPU_CORTEX_M33) || \
72 	defined(CONFIG_CPU_CORTEX_M52) || \
73 	defined(CONFIG_CPU_CORTEX_M55) || \
74 	defined(CONFIG_CPU_CORTEX_M85) || \
75 	defined(CONFIG_AARCH32_ARMV8_R)
76 #include "arm_mpu_v8_internal.h"
77 #else
78 #error "Unsupported ARM CPU"
79 #endif
80 
region_allocate_and_init(const uint8_t index,const struct arm_mpu_region * region_conf)81 static int region_allocate_and_init(const uint8_t index,
82 	const struct arm_mpu_region *region_conf)
83 {
84 	/* Attempt to allocate new region index. */
85 	if (index > (get_num_regions() - 1U)) {
86 
87 		/* No available MPU region index. */
88 		LOG_ERR("Failed to allocate new MPU region %u\n", index);
89 		return -EINVAL;
90 	}
91 
92 	LOG_DBG("Program MPU region at index 0x%x", index);
93 
94 	/* Program region */
95 	region_init(index, region_conf);
96 
97 	return index;
98 }
99 
100 #define _BUILD_REGION_CONF(reg, _ATTR)					\
101 	(struct arm_mpu_region) ARM_MPU_REGION_INIT((reg).dt_name,	\
102 						    (reg).dt_addr,	\
103 						    (reg).dt_size,	\
104 						    _ATTR)
105 #ifdef CONFIG_MEM_ATTR
106 /* This internal function programs the MPU regions defined in the DT when using
107  * the `zephyr,memory-attr = <( DT_MEM_ARM(...) )>` property.
108  */
mpu_configure_regions_from_dt(uint8_t * reg_index)109 static int mpu_configure_regions_from_dt(uint8_t *reg_index)
110 {
111 	const struct mem_attr_region_t *region;
112 	size_t num_regions;
113 
114 	num_regions = mem_attr_get_regions(&region);
115 
116 	for (size_t idx = 0; idx < num_regions; idx++) {
117 		struct arm_mpu_region region_conf;
118 
119 		switch (DT_MEM_ARM_GET(region[idx].dt_attr)) {
120 		case DT_MEM_ARM_MPU_RAM:
121 			region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_ATTR);
122 			break;
123 #ifdef CONFIG_ARM_MPU_PXN
124 		case DT_MEM_ARM_MPU_RAM_PXN:
125 			region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_ATTR_PXN);
126 			break;
127 #endif
128 #ifdef REGION_RAM_NOCACHE_ATTR
129 		case DT_MEM_ARM_MPU_RAM_NOCACHE:
130 			region_conf = _BUILD_REGION_CONF(region[idx], REGION_RAM_NOCACHE_ATTR);
131 			__ASSERT(!(region[idx].dt_attr & DT_MEM_CACHEABLE),
132 				 "RAM_NOCACHE with DT_MEM_CACHEABLE attribute\n");
133 			break;
134 #endif
135 #ifdef REGION_FLASH_ATTR
136 		case DT_MEM_ARM_MPU_FLASH:
137 			region_conf = _BUILD_REGION_CONF(region[idx], REGION_FLASH_ATTR);
138 			break;
139 #endif
140 #ifdef REGION_PPB_ATTR
141 		case DT_MEM_ARM_MPU_PPB:
142 			region_conf = _BUILD_REGION_CONF(region[idx], REGION_PPB_ATTR);
143 			break;
144 #endif
145 #ifdef REGION_IO_ATTR
146 		case DT_MEM_ARM_MPU_IO:
147 			region_conf = _BUILD_REGION_CONF(region[idx], REGION_IO_ATTR);
148 			break;
149 #endif
150 #ifdef REGION_EXTMEM_ATTR
151 		case DT_MEM_ARM_MPU_EXTMEM:
152 			region_conf = _BUILD_REGION_CONF(region[idx], REGION_EXTMEM_ATTR);
153 			break;
154 #endif
155 		default:
156 			/* Attribute other than ARM-specific is set.
157 			 * This region should not be configured in MPU.
158 			 */
159 			continue;
160 		}
161 #if defined(CONFIG_ARMV7_R)
162 		region_conf.size = size_to_mpu_rasr_size(region[idx].dt_size);
163 #endif
164 
165 		if (region_allocate_and_init((*reg_index),
166 					     (const struct arm_mpu_region *) &region_conf) < 0) {
167 			return -EINVAL;
168 		}
169 
170 		(*reg_index)++;
171 	}
172 
173 	return 0;
174 }
175 #endif /* CONFIG_MEM_ATTR */
176 /* This internal function programs an MPU region
177  * of a given configuration at a given MPU index.
178  */
mpu_configure_region(const uint8_t index,const struct z_arm_mpu_partition * new_region)179 static int mpu_configure_region(const uint8_t index,
180 	const struct z_arm_mpu_partition *new_region)
181 {
182 	struct arm_mpu_region region_conf;
183 
184 	LOG_DBG("Configure MPU region at index 0x%x", index);
185 
186 	/* Populate internal ARM MPU region configuration structure. */
187 	region_conf.base = new_region->start;
188 #if defined(CONFIG_ARMV7_R)
189 	region_conf.size = size_to_mpu_rasr_size(new_region->size);
190 #endif
191 	get_region_attr_from_mpu_partition_info(&region_conf.attr,
192 		&new_region->attr, new_region->start, new_region->size);
193 
194 	/* Allocate and program region */
195 	return region_allocate_and_init(index,
196 		(const struct arm_mpu_region *)&region_conf);
197 }
198 
199 #if !defined(CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS) || \
200 	!defined(CONFIG_MPU_GAP_FILLING)
201 /* This internal function programs a set of given MPU regions
202  * over a background memory area, optionally performing a
203  * sanity check of the memory regions to be programmed.
204  */
mpu_configure_regions(const struct z_arm_mpu_partition regions[],uint8_t regions_num,uint8_t start_reg_index,bool do_sanity_check)205 static int mpu_configure_regions(const struct z_arm_mpu_partition
206 	regions[], uint8_t regions_num, uint8_t start_reg_index,
207 	bool do_sanity_check)
208 {
209 	int i;
210 	int reg_index = start_reg_index;
211 
212 	for (i = 0; i < regions_num; i++) {
213 		if (regions[i].size == 0U) {
214 			continue;
215 		}
216 		/* Non-empty region. */
217 
218 		if (do_sanity_check &&
219 				(!mpu_partition_is_valid(&regions[i]))) {
220 			LOG_ERR("Partition %u: sanity check failed.", i);
221 			return -EINVAL;
222 		}
223 
224 		reg_index = mpu_configure_region(reg_index, &regions[i]);
225 
226 		if (reg_index == -EINVAL) {
227 			return reg_index;
228 		}
229 
230 		/* Increment number of programmed MPU indices. */
231 		reg_index++;
232 	}
233 
234 	return reg_index;
235 }
236 #endif
237 
238 /* ARM Core MPU Driver API Implementation for ARM MPU */
239 
240 
241 #if defined(CONFIG_CPU_AARCH32_CORTEX_R)
242 /**
243  * @brief enable the MPU by setting bit in SCTRL register
244  */
arm_core_mpu_enable(void)245 void arm_core_mpu_enable(void)
246 {
247 	uint32_t val;
248 
249 	val = __get_SCTLR();
250 	val |= SCTLR_MPU_ENABLE;
251 	__set_SCTLR(val);
252 
253 	/* Make sure that all the registers are set before proceeding */
254 	barrier_dsync_fence_full();
255 	barrier_isync_fence_full();
256 }
257 
258 /**
259  * @brief disable the MPU by clearing bit in SCTRL register
260  */
arm_core_mpu_disable(void)261 void arm_core_mpu_disable(void)
262 {
263 	uint32_t val;
264 
265 	/* Force any outstanding transfers to complete before disabling MPU */
266 	barrier_dsync_fence_full();
267 
268 	val = __get_SCTLR();
269 	val &= ~SCTLR_MPU_ENABLE;
270 	__set_SCTLR(val);
271 
272 	/* Make sure that all the registers are set before proceeding */
273 	barrier_dsync_fence_full();
274 	barrier_isync_fence_full();
275 }
276 #else
277 /**
278  * @brief enable the MPU
279  */
arm_core_mpu_enable(void)280 void arm_core_mpu_enable(void)
281 {
282 	/* Enable MPU and use the default memory map as a
283 	 * background region for privileged software access if desired.
284 	 */
285 #if defined(CONFIG_MPU_DISABLE_BACKGROUND_MAP)
286 	MPU->CTRL = MPU_CTRL_ENABLE_Msk;
287 #else
288 	MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk;
289 #endif
290 
291 	/* Make sure that all the registers are set before proceeding */
292 	barrier_dsync_fence_full();
293 	barrier_isync_fence_full();
294 }
295 
296 /**
297  * @brief disable the MPU
298  */
arm_core_mpu_disable(void)299 void arm_core_mpu_disable(void)
300 {
301 	/* Force any outstanding transfers to complete before disabling MPU */
302 	barrier_dmem_fence_full();
303 
304 	/* Disable MPU */
305 	MPU->CTRL = 0;
306 }
307 #endif
308 
309 #if defined(CONFIG_USERSPACE)
310 /**
311  * @brief update configuration of an active memory partition
312  */
arm_core_mpu_mem_partition_config_update(struct z_arm_mpu_partition * partition,k_mem_partition_attr_t * new_attr)313 void arm_core_mpu_mem_partition_config_update(
314 	struct z_arm_mpu_partition *partition,
315 	k_mem_partition_attr_t *new_attr)
316 {
317 	/* Find the partition. ASSERT if not found. */
318 	uint8_t i;
319 	uint8_t reg_index = get_num_regions();
320 
321 	for (i = get_dyn_region_min_index(); i < get_num_regions(); i++) {
322 		if (!is_enabled_region(i)) {
323 			continue;
324 		}
325 
326 		uint32_t base = mpu_region_get_base(i);
327 
328 		if (base != partition->start) {
329 			continue;
330 		}
331 
332 		uint32_t size = mpu_region_get_size(i);
333 
334 		if (size != partition->size) {
335 			continue;
336 		}
337 
338 		/* Region found */
339 		reg_index = i;
340 		break;
341 	}
342 	__ASSERT(reg_index != get_num_regions(),
343 		 "Memory domain partition %p size %zu not found\n",
344 		 (void *)partition->start, partition->size);
345 
346 	/* Modify the permissions */
347 	partition->attr = *new_attr;
348 	mpu_configure_region(reg_index, partition);
349 }
350 
351 /**
352  * @brief get the maximum number of available (free) MPU region indices
353  *        for configuring dynamic MPU partitions
354  */
arm_core_mpu_get_max_available_dyn_regions(void)355 int arm_core_mpu_get_max_available_dyn_regions(void)
356 {
357 	return get_num_regions() - static_regions_num;
358 }
359 
360 /**
361  * @brief validate the given buffer is user accessible or not
362  *
363  * Presumes the background mapping is NOT user accessible.
364  */
arm_core_mpu_buffer_validate(const void * addr,size_t size,int write)365 int arm_core_mpu_buffer_validate(const void *addr, size_t size, int write)
366 {
367 	return mpu_buffer_validate(addr, size, write);
368 }
369 
370 #endif /* CONFIG_USERSPACE */
371 
372 /**
373  * @brief configure fixed (static) MPU regions.
374  */
arm_core_mpu_configure_static_mpu_regions(const struct z_arm_mpu_partition * static_regions,const uint8_t regions_num,const uint32_t background_area_start,const uint32_t background_area_end)375 void arm_core_mpu_configure_static_mpu_regions(const struct z_arm_mpu_partition
376 	*static_regions, const uint8_t regions_num,
377 	const uint32_t background_area_start, const uint32_t background_area_end)
378 {
379 	if (mpu_configure_static_mpu_regions(static_regions, regions_num,
380 					       background_area_start, background_area_end) == -EINVAL) {
381 
382 		__ASSERT(0, "Configuring %u static MPU regions failed\n",
383 			regions_num);
384 	}
385 }
386 
387 #if defined(CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS)
388 /**
389  * @brief mark memory areas for dynamic region configuration
390  */
arm_core_mpu_mark_areas_for_dynamic_regions(const struct z_arm_mpu_partition dyn_region_areas[],const uint8_t dyn_region_areas_num)391 void arm_core_mpu_mark_areas_for_dynamic_regions(
392 	const struct z_arm_mpu_partition dyn_region_areas[],
393 	const uint8_t dyn_region_areas_num)
394 {
395 	if (mpu_mark_areas_for_dynamic_regions(dyn_region_areas,
396 						 dyn_region_areas_num) == -EINVAL) {
397 
398 		__ASSERT(0, "Marking %u areas for dynamic regions failed\n",
399 			dyn_region_areas_num);
400 	}
401 }
402 #endif /* CONFIG_MPU_REQUIRES_NON_OVERLAPPING_REGIONS */
403 
404 /**
405  * @brief configure dynamic MPU regions.
406  */
arm_core_mpu_configure_dynamic_mpu_regions(const struct z_arm_mpu_partition * dynamic_regions,uint8_t regions_num)407 void arm_core_mpu_configure_dynamic_mpu_regions(const struct z_arm_mpu_partition
408 	*dynamic_regions, uint8_t regions_num)
409 {
410 	if (mpu_configure_dynamic_mpu_regions(dynamic_regions, regions_num)
411 		== -EINVAL) {
412 
413 		__ASSERT(0, "Configuring %u dynamic MPU regions failed\n",
414 			regions_num);
415 	}
416 }
417 
418 #if defined(CONFIG_CPU_CORTEX_M)
419 /**
420  * @brief Save the current MPU configuration into the provided context struct.
421  */
z_arm_save_mpu_context(struct z_mpu_context_retained * ctx)422 void z_arm_save_mpu_context(struct z_mpu_context_retained *ctx)
423 {
424 	uint32_t regions = get_num_regions();
425 
426 	__ASSERT_NO_MSG(ctx != NULL);
427 
428 	if (regions == 0 || regions > Z_ARM_MPU_MAX_REGIONS) {
429 		LOG_DBG("Invalid MPU region count: %u", regions);
430 		ctx->num_valid_regions = 0;
431 		return;
432 	}
433 
434 	ctx->num_valid_regions = regions;
435 
436 	for (uint32_t i = 0; i < regions; i++) {
437 		MPU->RNR = i;
438 		__DSB(); /* Ensure MPU->RNR write completes before reading registers */
439 		__ISB();
440 		ctx->rbar[i] = MPU->RBAR;
441 		ctx->rasr_rlar[i] = MPU->ATTRIBUTE_AND_SIZE_REG_NAME;
442 	}
443 #if Z_ARM_CPU_HAS_PMSAV8_MPU
444 	ctx->mair[0] = MPU->MAIR0;
445 	ctx->mair[1] = MPU->MAIR1;
446 #endif
447 	ctx->ctrl = MPU->CTRL;
448 }
449 
450 /**
451  * @brief Restore the MPU configuration from the provided context struct.
452  */
z_arm_restore_mpu_context(const struct z_mpu_context_retained * ctx)453 void z_arm_restore_mpu_context(const struct z_mpu_context_retained *ctx)
454 {
455 	__ASSERT_NO_MSG(ctx != NULL);
456 
457 	if (ctx->num_valid_regions == 0 || ctx->num_valid_regions > Z_ARM_MPU_MAX_REGIONS) {
458 		LOG_DBG("Invalid MPU context num_valid_regions: %u", ctx->num_valid_regions);
459 		return;
460 	}
461 
462 	/* Disable MPU before reprogramming */
463 	arm_core_mpu_disable();
464 
465 	for (uint32_t i = 0; i < ctx->num_valid_regions; i++) {
466 		MPU->RNR = i;
467 		MPU->RBAR = ctx->rbar[i];
468 		MPU->ATTRIBUTE_AND_SIZE_REG_NAME = ctx->rasr_rlar[i];
469 	}
470 
471 #if Z_ARM_CPU_HAS_PMSAV8_MPU
472 	MPU->MAIR0 = ctx->mair[0];
473 	MPU->MAIR1 = ctx->mair[1];
474 #endif
475 	/* Restore MPU control register (including enable bit if set) */
476 	MPU->CTRL = ctx->ctrl;
477 
478 	/* Ensure MPU settings take effect before continuing */
479 	__DSB();
480 	__ISB();
481 }
482 #endif /* CONFIG_CPU_CORTEX_M */
483 
484 /* ARM MPU Driver Initial Setup */
485 
486 /*
487  * @brief MPU default configuration
488  *
489  * This function provides the default configuration mechanism for the Memory
490  * Protection Unit (MPU).
491  */
z_arm_mpu_init(void)492 int z_arm_mpu_init(void)
493 {
494 	uint32_t r_index;
495 
496 	if (mpu_config.num_regions > get_num_regions()) {
497 		/* Attempt to configure more MPU regions than
498 		 * what is supported by hardware. As this operation
499 		 * is executed during system (pre-kernel) initialization,
500 		 * we want to ensure we can detect an attempt to
501 		 * perform invalid configuration.
502 		 */
503 		__ASSERT(0,
504 			"Request to configure: %u regions (supported: %u)\n",
505 			mpu_config.num_regions,
506 			get_num_regions()
507 		);
508 		return -1;
509 	}
510 
511 	LOG_DBG("total region count: %d", get_num_regions());
512 
513 	arm_core_mpu_disable();
514 
515 #if defined(CONFIG_NOCACHE_MEMORY)
516 	/* Clean and invalidate data cache if it is enabled and
517 	 * that was not already done at boot
518 	 */
519 #if defined(CONFIG_CPU_AARCH32_CORTEX_R)
520 	if (__get_SCTLR() & SCTLR_C_Msk) {
521 		L1C_CleanInvalidateDCacheAll();
522 	}
523 #else
524 #if !defined(CONFIG_INIT_ARCH_HW_AT_BOOT)
525 	if (SCB->CCR & SCB_CCR_DC_Msk) {
526 		SCB_CleanInvalidateDCache();
527 	}
528 #endif
529 #endif
530 #endif /* CONFIG_NOCACHE_MEMORY */
531 
532 	/* Architecture-specific configuration */
533 	mpu_init();
534 
535 	/* Program fixed regions configured at SOC definition. */
536 	for (r_index = 0U; r_index < mpu_config.num_regions; r_index++) {
537 		region_init(r_index, &mpu_config.mpu_regions[r_index]);
538 	}
539 
540 	/* Update the number of programmed MPU regions. */
541 	static_regions_num = mpu_config.num_regions;
542 #ifdef CONFIG_MEM_ATTR
543 	/* DT-defined MPU regions. */
544 	if (mpu_configure_regions_from_dt(&static_regions_num) == -EINVAL) {
545 		__ASSERT(0, "Failed to allocate MPU regions from DT\n");
546 		return -EINVAL;
547 	}
548 #endif /* CONFIG_MEM_ATTR */
549 	/* Clear all regions before enabling MPU */
550 	for (int i = static_regions_num; i < get_num_regions(); i++) {
551 		mpu_clear_region(i);
552 	}
553 
554 	arm_core_mpu_enable();
555 
556 	/* Program additional fixed flash region for null-pointer
557 	 * dereferencing detection (debug feature)
558 	 */
559 #if defined(CONFIG_NULL_POINTER_EXCEPTION_DETECTION_MPU)
560 #if (defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)) && \
561 	(CONFIG_FLASH_BASE_ADDRESS > CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE) && \
562 	(!DT_NULL_PAGE_DETECT_NODE_EXIST)
563 
564 #pragma message "Null-Pointer exception detection cannot be configured on un-mapped flash areas"
565 #else
566 	const struct z_arm_mpu_partition unmap_region =	{
567 		.start = 0x0,
568 		.size = CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE,
569 #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)
570 		/* Overlapping region (with any permissions)
571 		 * will result in fault generation
572 		 */
573 		.attr = K_MEM_PARTITION_P_RO_U_NA,
574 #else
575 		/* Explicit no-access policy */
576 		.attr = K_MEM_PARTITION_P_NA_U_NA,
577 #endif
578 	};
579 
580 	/* The flash region for null pointer dereferencing detection shall
581 	 * comply with the regular MPU partition definition restrictions
582 	 * (size and alignment).
583 	 */
584 	_ARCH_MEM_PARTITION_ALIGN_CHECK(0x0,
585 		CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE);
586 
587 #if defined(CONFIG_ARMV8_M_BASELINE) || defined(CONFIG_ARMV8_M_MAINLINE)
588 	/* ARMv8-M requires that the area:
589 	 * 0x0 - CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE
590 	 * is not unmapped (belongs to a valid MPU region already).
591 	 */
592 	if ((arm_cmse_mpu_region_get(0x0) == -EINVAL) ||
593 		(arm_cmse_mpu_region_get(
594 			CONFIG_CORTEX_M_NULL_POINTER_EXCEPTION_PAGE_SIZE - 1)
595 		== -EINVAL)) {
596 		__ASSERT(0,
597 			"Null pointer detection page unmapped\n");
598 		}
599 #endif
600 
601 	if (mpu_configure_region(static_regions_num, &unmap_region) == -EINVAL) {
602 
603 		__ASSERT(0,
604 			"Programming null-pointer detection region failed\n");
605 		return -EINVAL;
606 	}
607 
608 	static_regions_num++;
609 
610 #endif
611 #endif /* CONFIG_NULL_POINTER_EXCEPTION_DETECTION_MPU */
612 
613 	/* Sanity check for number of regions in Cortex-M0+, M3, and M4. */
614 #if defined(CONFIG_CPU_CORTEX_M0PLUS) || \
615 	defined(CONFIG_CPU_CORTEX_M3) || \
616 	defined(CONFIG_CPU_CORTEX_M4)
617 	__ASSERT(
618 		(MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos == 8,
619 		"Invalid number of MPU regions\n");
620 #endif /* CORTEX_M0PLUS || CPU_CORTEX_M3 || CPU_CORTEX_M4 */
621 
622 	return 0;
623 }
624