1 /*
2  * Copyright (c) 2023 Carlo Caione, <ccaione@baylibre.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/mem_mgmt/mem_attr.h>
9 
10 #define _BUILD_MEM_ATTR_REGION(node_id)					\
11 	{								\
12 		.dt_name = DT_NODE_FULL_NAME(node_id),			\
13 		.dt_addr = DT_REG_ADDR(node_id),			\
14 		.dt_size = DT_REG_SIZE(node_id),			\
15 		.dt_attr = DT_PROP(node_id, zephyr_memory_attr),	\
16 	},
17 
18 static const struct mem_attr_region_t mem_attr_region[] = {
19 	DT_MEMORY_ATTR_FOREACH_STATUS_OKAY_NODE(_BUILD_MEM_ATTR_REGION)
20 };
21 
mem_attr_get_regions(const struct mem_attr_region_t ** region)22 size_t mem_attr_get_regions(const struct mem_attr_region_t **region)
23 {
24 	*region = mem_attr_region;
25 
26 	return ARRAY_SIZE(mem_attr_region);
27 }
28 
mem_attr_check_buf(void * v_addr,size_t size,uint32_t attr)29 int mem_attr_check_buf(void *v_addr, size_t size, uint32_t attr)
30 {
31 	uintptr_t addr = (uintptr_t) v_addr;
32 
33 	/*
34 	 * If MMU is enabled the address of the buffer is a virtual address
35 	 * while the addresses in the DT are physical addresses. Given that we
36 	 * have no way of knowing whether a mapping exists, we simply bail out.
37 	 */
38 	if (IS_ENABLED(CONFIG_MMU)) {
39 		return -ENOSYS;
40 	}
41 
42 	if (size == 0) {
43 		return -ENOTSUP;
44 	}
45 
46 	for (size_t idx = 0; idx < ARRAY_SIZE(mem_attr_region); idx++) {
47 		const struct mem_attr_region_t *region = &mem_attr_region[idx];
48 		size_t region_end = region->dt_addr + region->dt_size;
49 
50 		/* Check if the buffer is in the region */
51 		if ((addr >= region->dt_addr) && (addr < region_end)) {
52 			/* Check if the buffer is entirely contained in the region */
53 			if ((addr + size) <= region_end) {
54 				/* check if the attribute is correct */
55 				return (region->dt_attr & attr) == attr ? 0 : -EINVAL;
56 			}
57 			return -ENOSPC;
58 		}
59 	}
60 	return -ENOBUFS;
61 }
62