Memory Domain¶
The memory domain APIs are used by unprivileged threads to share data to the threads in the same memory domain and protect sensitive data from threads outside their domain. Memory domains are not only used for improving security, but are also useful for debugging (unexpected access would cause an exception).
An alternative to using memory domains is the
CONFIG_APPLICATION_MEMORY
option, which will grant access to user
threads at boot to all global memory defined in object files that are not
part of the core kernel. This is useful for very simple applications which
will allow all threads to use global data defined within the application, but
each thread’s stack is still protected from other user threads and there is
no access to private kernel data structures.
Since architectures generally have constraints on how many partitions can be defined, and the size/alignment of each partition, users may need to group related data together using linker sections.
Concepts¶
A memory domain contains some number of memory partitions. A memory partition is a memory region (might be RAM, peripheral registers, or flash, for example) with specific attributes (access permission, e.g. privileged read/write, unprivileged read-only, or execute never). Memory partitions are defined by a set of underlying MPU regions or MMU tables. A thread belongs to a single memory domain at any point in time but a memory domain may contain multiple threads. Threads in the same memory domain have the same access permissions to the memory partitions belonging to the memory domain. New threads will inherit any memory domain configuration from the parent thread.
Implementation¶
Create a Memory Domain¶
A memory domain is defined using a variable of type
struct k_mem_domain
. It must then be initialized by calling
k_mem_domain_init()
.
The following code defines and initializes an empty memory domain.
struct k_mem_domain app0_domain;
k_mem_domain_init(&app0_domain, 0, NULL);
Add Memory Partitions into a Memory Domain¶
There are two ways to add memory partitions into a memory domain.
This first code sample shows how to add memory partitions while creating a memory domain.
/* the start address of the MPU region needs to align with its size */
u8_t __aligned(32) app0_buf[32];
u8_t __aligned(32) app1_buf[32];
K_MEM_PARTITION_DEFINE(app0_part0, app0_buf, sizeof(app0_buf),
K_MEM_PARTITION_P_RW_U_RW);
K_MEM_PARTITION_DEFINE(app0_part1, app1_buf, sizeof(app1_buf),
K_MEM_PARTITION_P_RW_U_RO);
struct k_mem_partition *app0_parts[] = {
app0_part0,
app0_part1
};
k_mem_domain_init(&app0_domain, ARRAY_SIZE(app0_parts), app0_parts);
This second code sample shows how to add memory partitions into an initialized memory domain one by one.
/* the start address of the MPU region needs to align with its size */
u8_t __aligned(32) app0_buf[32];
u8_t __aligned(32) app1_buf[32];
K_MEM_PARTITION_DEFINE(app0_part0, app0_buf, sizeof(app0_buf),
K_MEM_PARTITION_P_RW_U_RW);
K_MEM_PARTITION_DEFINE(app0_part1, app1_buf, sizeof(app1_buf),
K_MEM_PARTITION_P_RW_U_RO);
k_mem_domain_add_partition(&app0_domain, &app0_part0);
k_mem_domain_add_partition(&app0_domain, &app0_part1);
Note
The maximum number of memory partitions is limited by the maximum number of MPU regions or the maximum number of MMU tables.
Add Threads into a Memory Domain¶
Adding threads into a memory domain grants threads permission to access the memory partitions in the memory domain.
The following code shows how to add threads into a memory domain.
k_mem_domain_add_thread(&app0_domain, app_thread_id);
Remove a Memory Partition from a Memory Domain¶
The following code shows how to remove a memory partition from a memory domain.
k_mem_domain_remove_partition(&app0_domain, &app0_part1);
The k_mem_domain_remove_partition() API finds the memory partition that matches the given parameter and removes that partition from the memory domain.
Remove a Thread from the Memory Domain¶
The following code shows how to remove a thread from the memory domain.
k_mem_domain_remove_thread(app_thread_id);
Destroy a Memory Domain¶
The following code shows how to destroy a memory domain.
k_mem_domain_destroy(&app0_domain);
Available Partition Attributes¶
When defining a partition, we need to set access permission attributes to the partition. Since the access control of memory partitions relies on either an MPU or MMU, the available partition attributes would be architecture dependent.
The complete list of available partition attributes for a specific architecture
is found in the architecture-specific include file
include/arch/<arch name>/arch.h
, (for example, include/arch/arm/arch.h
.)
Some examples of partition attributes are:
/* Denote partition is privileged read/write, unprivileged read/write */
K_MEM_PARTITION_P_RW_U_RW
/* Denote partition is privileged read/write, unprivileged read-only */
K_MEM_PARTITION_P_RW_U_RO