1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2018-2020 Intel Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #ifndef INCLUDE_APP_MEMORY_MEM_DOMAIN_H
9 #define INCLUDE_APP_MEMORY_MEM_DOMAIN_H
10 
11 #include <stdint.h>
12 #include <stddef.h>
13 #include <zephyr/sys/dlist.h>
14 #include <zephyr/toolchain.h>
15 #include <zephyr/kernel/thread.h>
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
21 /**
22  * @defgroup mem_domain_apis Memory domain APIs
23  * @ingroup kernel_apis
24  * @{
25  */
26 
27 #ifdef CONFIG_USERSPACE
28 /**
29  * @def K_MEM_PARTITION_DEFINE
30  *
31  * @brief Statically declare a memory partition
32  */
33 #ifdef _ARCH_MEM_PARTITION_ALIGN_CHECK
34 #define K_MEM_PARTITION_DEFINE(name, start, size, attr) \
35 	_ARCH_MEM_PARTITION_ALIGN_CHECK(start, size); \
36 	struct k_mem_partition name =\
37 		{ (uintptr_t)start, size, attr}
38 #else
39 #define K_MEM_PARTITION_DEFINE(name, start, size, attr) \
40 	struct k_mem_partition name =\
41 		{ (uintptr_t)start, size, attr}
42 #endif /* _ARCH_MEM_PARTITION_ALIGN_CHECK */
43 
44 /**
45  * @brief Memory Partition
46  *
47  * A memory partition is a region of memory in the linear address space
48  * with a specific access policy.
49  *
50  * The alignment of the starting address, and the alignment of the size
51  * value may have varying requirements based on the capabilities of the
52  * underlying memory management hardware; arbitrary values are unlikely
53  * to work.
54  */
55 struct k_mem_partition {
56 	/** start address of memory partition */
57 	uintptr_t start;
58 	/** size of memory partition */
59 	size_t size;
60 	/** attribute of memory partition */
61 	k_mem_partition_attr_t attr;
62 };
63 
64 /**
65  * @brief Memory Domain
66  *
67  * A memory domain is a collection of memory partitions, used to represent
68  * a user thread's access policy for the linear address space. A thread
69  * may be a member of only one memory domain, but any memory domain may
70  * have multiple threads that are members.
71  *
72  * Supervisor threads may also be a member of a memory domain; this has
73  * no implications on their memory access but can be useful as any child
74  * threads inherit the memory domain membership of the parent.
75  *
76  * A user thread belonging to a memory domain with no active partitions
77  * will have guaranteed access to its own stack buffer, program text,
78  * and read-only data.
79  */
80 struct k_mem_domain {
81 #ifdef CONFIG_ARCH_MEM_DOMAIN_DATA
82 	struct arch_mem_domain arch;
83 #endif /* CONFIG_ARCH_MEM_DOMAIN_DATA */
84 	/** partitions in the domain */
85 	struct k_mem_partition partitions[CONFIG_MAX_DOMAIN_PARTITIONS];
86 	/** Doubly linked list of member threads */
87 	sys_dlist_t mem_domain_q;
88 	/** number of active partitions in the domain */
89 	uint8_t num_partitions;
90 };
91 
92 /**
93  * Default memory domain
94  *
95  * All threads are a member of some memory domain, even if running in
96  * supervisor mode. Threads belong to this default memory domain if they
97  * haven't been added to or inherited membership from some other domain.
98  *
99  * This memory domain has the z_libc_partition partition for the C library
100  * added to it if exists.
101  */
102 extern struct k_mem_domain k_mem_domain_default;
103 #else
104 /* To support use of IS_ENABLED for the APIs below */
105 struct k_mem_domain;
106 struct k_mem_partition;
107 #endif /* CONFIG_USERSPACE */
108 
109 /**
110  * @brief Initialize a memory domain.
111  *
112  * Initialize a memory domain with given name and memory partitions.
113  *
114  * See documentation for k_mem_domain_add_partition() for details about
115  * partition constraints.
116  *
117  * Do not call k_mem_domain_init() on the same memory domain more than once,
118  * doing so is undefined behavior.
119  *
120  * @param domain The memory domain to be initialized.
121  * @param num_parts The number of array items of "parts" parameter.
122  * @param parts An array of pointers to the memory partitions. Can be NULL
123  *              if num_parts is zero.
124  *
125  * @retval 0 if successful
126  * @retval -EINVAL if invalid parameters supplied
127  * @retval -ENOMEM if insufficient memory
128  */
129 extern int k_mem_domain_init(struct k_mem_domain *domain, uint8_t num_parts,
130 			     struct k_mem_partition *parts[]);
131 
132 /**
133  * @brief Add a memory partition into a memory domain.
134  *
135  * Add a memory partition into a memory domain. Partitions must conform to
136  * the following constraints:
137  *
138  * - Partitions in the same memory domain may not overlap each other.
139  * - Partitions must not be defined which expose private kernel
140  *   data structures or kernel objects.
141  * - The starting address alignment, and the partition size must conform to
142  *   the constraints of the underlying memory management hardware, which
143  *   varies per architecture.
144  * - Memory domain partitions are only intended to control access to memory
145  *   from user mode threads.
146  * - If CONFIG_EXECUTE_XOR_WRITE is enabled, the partition must not allow
147  *   both writes and execution.
148  *
149  * Violating these constraints may lead to CPU exceptions or undefined
150  * behavior.
151  *
152  * @param domain The memory domain to be added a memory partition.
153  * @param part The memory partition to be added
154  *
155  * @retval 0 if successful
156  * @retval -EINVAL if invalid parameters supplied
157  * @retval -ENOSPC if no free partition slots available
158  */
159 extern int k_mem_domain_add_partition(struct k_mem_domain *domain,
160 				      struct k_mem_partition *part);
161 
162 /**
163  * @brief Remove a memory partition from a memory domain.
164  *
165  * Remove a memory partition from a memory domain.
166  *
167  * @param domain The memory domain to be removed a memory partition.
168  * @param part The memory partition to be removed
169  *
170  * @retval 0 if successful
171  * @retval -EINVAL if invalid parameters supplied
172  * @retval -ENOENT if no matching partition found
173  */
174 extern int k_mem_domain_remove_partition(struct k_mem_domain *domain,
175 					 struct k_mem_partition *part);
176 
177 /**
178  * @brief Add a thread into a memory domain.
179  *
180  * Add a thread into a memory domain. It will be removed from whatever
181  * memory domain it previously belonged to.
182  *
183  * @param domain The memory domain that the thread is going to be added into.
184  * @param thread ID of thread going to be added into the memory domain.
185  *
186  * @return 0 if successful, fails otherwise.
187  */
188 extern int k_mem_domain_add_thread(struct k_mem_domain *domain,
189 				   k_tid_t thread);
190 
191 #ifdef __cplusplus
192 }
193 #endif
194 
195 /** @} */
196 #endif /* INCLUDE_APP_MEMORY_MEM_DOMAIN_H */
197