Skip to content
Permalink
Browse files

userspace: adjust arch memory domain interface

The current API was assuming too much, in that it expected that
arch-specific memory domain configuration is only maintained
in some global area, and updates to domains that are not currently
active have no effect.

This was true when all memory domain state was tracked in page
tables or MPU registers, but no longer works when arch-specific
memory management information is stored in thread-specific areas.

This is needed for: #13441 #13074 #15135

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
  • Loading branch information...
andrewboie authored and carlescufi committed Jul 26, 2019
1 parent fddd550 commit 8915e41b7be19de9b73efabaecc1e6205acf3a1f
@@ -9,6 +9,7 @@
#include <kernel.h>
#include <soc.h>
#include <arch/arc/v2/mpu/arc_core_mpu.h>
#include <kernel_structs.h>

/*
* @brief Configure MPU for the thread
@@ -37,6 +38,10 @@ int z_arch_mem_domain_max_partitions_get(void)
void z_arch_mem_domain_partition_remove(struct k_mem_domain *domain,
u32_t partition_id)
{
if (_current->mem_domain_info.mem_domain != domain) {
return;
}

arc_core_mpu_disable();
arc_core_mpu_remove_mem_partition(domain, partition_id);
arc_core_mpu_enable();
@@ -45,8 +50,12 @@ void z_arch_mem_domain_partition_remove(struct k_mem_domain *domain,
/*
* Configure MPU memory domain
*/
void z_arch_mem_domain_configure(struct k_thread *thread)
void z_arch_mem_domain_thread_add(struct k_thread *thread)
{
if (_current != thread) {
return;
}

arc_core_mpu_disable();
arc_core_mpu_configure_mem_domain(thread);
arc_core_mpu_enable();
@@ -57,6 +66,10 @@ void z_arch_mem_domain_configure(struct k_thread *thread)
*/
void z_arch_mem_domain_destroy(struct k_mem_domain *domain)
{
if (_current->mem_domain_info.mem_domain != domain) {
return;
}

arc_core_mpu_disable();
arc_core_mpu_remove_mem_domain(domain);
arc_core_mpu_enable();
@@ -68,6 +81,15 @@ void z_arch_mem_domain_partition_add(struct k_mem_domain *domain,
/* No-op on this architecture */
}

void z_arch_mem_domain_thread_remove(struct k_thread *thread)
{
if (_current != thread) {
return;
}

z_arch_mem_domain_destroy(thread->mem_domain_info.mem_domain);
}

/*
* Validate the given buffer is user accessible or not
*/
@@ -8,6 +8,7 @@
#include <init.h>
#include <kernel.h>
#include <soc.h>
#include <kernel_structs.h>

#include "arm_core_mpu_dev.h"
#include <linker/linker-defs.h>
@@ -282,8 +283,12 @@ int z_arch_mem_domain_max_partitions_get(void)
/**
* @brief Configure the memory domain of the thread.
*/
void z_arch_mem_domain_configure(struct k_thread *thread)
void z_arch_mem_domain_thread_add(struct k_thread *thread)
{
if (_current != thread) {
return;
}

/* Request to configure memory domain for a thread.
* This triggers re-programming of the entire dynamic
* memory map.
@@ -304,6 +309,11 @@ void z_arch_mem_domain_destroy(struct k_mem_domain *domain)
*/
int i;
struct k_mem_partition partition;

if (_current->mem_domain_info.mem_domain != domain) {
return;
}

/* Partitions belonging to the memory domain will be reset
* to default (Privileged RW, Unprivileged NA) permissions.
*/
@@ -338,6 +348,10 @@ void z_arch_mem_domain_partition_remove(struct k_mem_domain *domain,
*/
k_mem_partition_attr_t reset_attr = K_MEM_PARTITION_P_RW_U_NA;

if (_current->mem_domain_info.mem_domain != domain) {
return;
}

arm_core_mpu_mem_partition_config_update(
&domain->partitions[partition_id], &reset_attr);
}
@@ -348,6 +362,15 @@ void z_arch_mem_domain_partition_add(struct k_mem_domain *domain,
/* No-op on this architecture */
}

void z_arch_mem_domain_thread_remove(struct k_thread *thread)
{
if (_current != thread) {
return;
}

z_arch_mem_domain_destroy(thread->mem_domain_info.mem_domain);
}

/*
* Validate the given buffer is user accessible or not
*/
@@ -159,8 +159,10 @@ void _x86_swap_update_page_tables(struct k_thread *incoming,
/* Ensure that the outgoing mem domain configuration
* is set back to default state.
*/
z_arch_mem_domain_destroy(outgoing->mem_domain_info.mem_domain);
z_arch_mem_domain_configure(incoming);
z_x86_mem_domain_pages_update(outgoing->mem_domain_info.mem_domain,
X86_MEM_DOMAIN_RESET_PAGES);
z_x86_mem_domain_pages_update(incoming->mem_domain_info.mem_domain,
X86_MEM_DOMAIN_SET_PAGES);
}
}

@@ -8,6 +8,7 @@
#include <ia32/mmustructs.h>
#include <linker/linker-defs.h>
#include <kernel_internal.h>
#include <kernel_structs.h>
#include <init.h>
#include <ctype.h>

@@ -377,12 +378,9 @@ static inline void activate_partition(struct k_mem_partition *partition)
partition->size, attr, mask);
}

/* Helper macros needed to be passed to x86_update_mem_domain_pages */
#define X86_MEM_DOMAIN_SET_PAGES (0U)
#define X86_MEM_DOMAIN_RESET_PAGES (1U)
/* Pass 1 to page_conf if reset of mem domain pages is needed else pass a 0*/
static inline void x86_mem_domain_pages_update(struct k_mem_domain *mem_domain,
u32_t page_conf)
void z_x86_mem_domain_pages_update(struct k_mem_domain *mem_domain,
u32_t page_conf)
{
u32_t partition_index;
u32_t total_partitions;
@@ -424,18 +422,35 @@ static inline void x86_mem_domain_pages_update(struct k_mem_domain *mem_domain,
}

/* Load the partitions of the thread. */
void z_arch_mem_domain_configure(struct k_thread *thread)
void z_arch_mem_domain_thread_add(struct k_thread *thread)
{
x86_mem_domain_pages_update(thread->mem_domain_info.mem_domain,
X86_MEM_DOMAIN_SET_PAGES);
if (_current != thread) {
return;
}

z_x86_mem_domain_pages_update(thread->mem_domain_info.mem_domain,
X86_MEM_DOMAIN_SET_PAGES);
}

/* Destroy or reset the mmu page tables when necessary.
* Needed when either swap takes place or k_mem_domain_destroy is called.
*/
void z_arch_mem_domain_destroy(struct k_mem_domain *domain)
{
x86_mem_domain_pages_update(domain, X86_MEM_DOMAIN_RESET_PAGES);
if (_current->mem_domain_info.mem_domain != domain) {
return;
}

z_x86_mem_domain_pages_update(domain, X86_MEM_DOMAIN_RESET_PAGES);
}

void z_arch_mem_domain_thread_remove(struct k_thread *thread)
{
if (_current != thread) {
return;
}

z_arch_mem_domain_destroy(thread->mem_domain_info.mem_domain);
}

/* Reset/destroy one partition specified in the argument of the API. */
@@ -444,6 +459,10 @@ void z_arch_mem_domain_partition_remove(struct k_mem_domain *domain,
{
struct k_mem_partition *partition;

if (_current->mem_domain_info.mem_domain != domain) {
return;
}

__ASSERT_NO_MSG(domain != NULL);
__ASSERT(partition_id <= domain->num_partitions,
"invalid partitions");
@@ -458,6 +477,10 @@ void z_arch_mem_domain_partition_add(struct k_mem_domain *domain,
{
struct k_mem_partition *partition;

if (_current->mem_domain_info.mem_domain != domain) {
return;
}

__ASSERT_NO_MSG(domain != NULL);
__ASSERT(partition_id <= domain->num_partitions,
"invalid partitions");
@@ -81,6 +81,13 @@ extern FUNC_NORETURN void z_x86_userspace_enter(k_thread_entry_t user_entry,
u32_t stack_end,
u32_t stack_start);

/* Helper macros needed to be passed to x86_update_mem_domain_pages */
#define X86_MEM_DOMAIN_SET_PAGES (0U)
#define X86_MEM_DOMAIN_RESET_PAGES (1U)

extern void z_x86_mem_domain_pages_update(struct k_mem_domain *mem_domain,
u32_t page_conf);

#include <stddef.h> /* For size_t */

#ifdef __cplusplus
@@ -73,51 +73,57 @@ extern int z_arch_float_disable(struct k_thread *thread);
/**
* @brief Get the maximum number of partitions for a memory domain
*
* A memory domain is a container data structure containing some number of
* memory partitions, where each partition represents a memory range with
* access policies.
*
* MMU-based systems don't have a limit here, but MPU-based systems will
* have an upper bound on how many different regions they can manage
* simultaneously.
*
* @return Max number of free regions, or -1 if there is no limit
* @return Max number of partitions, or -1 if there is no limit
*/
extern int z_arch_mem_domain_max_partitions_get(void);

/**
* @brief Configure the memory domain of the thread.
* @brief Add a thread to a memory domain (arch-specific)
*
* Architecture-specific hook to manage internal data structures or hardware
* state when the provided thread has been added to a memory domain.
*
* A memory domain is a container data structure containing some number of
* memory partitions, where each partition represents a memory range with
* access policies. This api will configure the appropriate hardware
* registers to make it work.
* The thread's memory domain pointer will be set to the domain to be added
* to.
*
* @param thread Thread which needs to be configured.
*/
extern void z_arch_mem_domain_configure(struct k_thread *thread);
extern void z_arch_mem_domain_thread_add(struct k_thread *thread);

/**
* @brief Remove a partition from the memory domain
* @brief Remove a thread from a memory domain (arch-specific)
*
* A memory domain contains multiple partitions and this API provides the
* freedom to remove a particular partition while keeping others intact.
* This API will handle any arch/HW specific changes that needs to be done.
* Only called if the active thread's domain was modified.
* Architecture-specific hook to manage internal data structures or hardware
* state when the provided thread has been removed from a memory domain.
*
* The thread's memory domain pointer will be the domain that the thread
* is being removed from.
*
* @param thread Thread being removed from its memory domain
*/
extern void z_arch_mem_domain_thread_remove(struct k_thread *thread);

/**
* @brief Remove a partition from the memory domain (arch-specific)
*
* Architecture-specific hook to manage internal data structures or hardware
* state when a memory domain has had a partition removed.
*
* The partition index data, and the number of partitions configured, are not
* respectively cleared and decremented in the domain until after this function
* runs.
*
* @param domain The memory domain structure
* @param partition_id The partition that needs to be deleted
* @param partition_id The partition index that needs to be deleted
*/
extern void z_arch_mem_domain_partition_remove(struct k_mem_domain *domain,
u32_t partition_id);

/**
* @brief Add a partition to the memory domain
*
* A memory domain contains multiple partitions and this API provides the
* freedom to add an additional partition to a memory domain.
* This API will handle any arch/HW specific changes that needs to be done.
* Only called if the active thread's domain was modified.
* Architecture-specific hook to manage internal data structures or hardware
* state when a memory domain has a partition added.
*
* @param domain The memory domain structure
* @param partition_id The partition that needs to be added
@@ -128,9 +134,11 @@ extern void z_arch_mem_domain_partition_add(struct k_mem_domain *domain,
/**
* @brief Remove the memory domain
*
* A memory domain contains multiple partitions and this API will traverse
* all these to reset them back to default setting.
* This API will handle any arch/HW specific changes that needs to be done.
* Architecture-specific hook to manage internal data structures or hardware
* state when a memory domain has been destroyed.
*
* Thread assignments to the memory domain are only cleared after this function
* runs.
*
* @param domain The memory domain structure which needs to be deleted.
*/
@@ -129,12 +129,7 @@ void k_mem_domain_destroy(struct k_mem_domain *domain)

key = k_spin_lock(&lock);

/* Handle architecture-specific destroy
* only if it is the current thread.
*/
if (_current->mem_domain_info.mem_domain == domain) {
z_arch_mem_domain_destroy(domain);
}
z_arch_mem_domain_destroy(domain);

SYS_DLIST_FOR_EACH_NODE_SAFE(&domain->mem_domain_q, node, next_node) {
struct k_thread *thread =
@@ -181,13 +176,7 @@ void k_mem_domain_add_partition(struct k_mem_domain *domain,

domain->num_partitions++;

/* Handle architecture-specific add
* only if it is the current thread.
*/
if (_current->mem_domain_info.mem_domain == domain) {
z_arch_mem_domain_partition_add(domain, p_idx);
}

z_arch_mem_domain_partition_add(domain, p_idx);
k_spin_unlock(&lock, key);
}

@@ -213,12 +202,7 @@ void k_mem_domain_remove_partition(struct k_mem_domain *domain,
/* Assert if not found */
__ASSERT(p_idx < max_partitions, "no matching partition found");

/* Handle architecture-specific remove
* only if it is the current thread.
*/
if (_current->mem_domain_info.mem_domain == domain) {
z_arch_mem_domain_partition_remove(domain, p_idx);
}
z_arch_mem_domain_partition_remove(domain, p_idx);

/* A zero-sized partition denotes it's a free partition */
domain->partitions[p_idx].size = 0U;
@@ -243,9 +227,7 @@ void k_mem_domain_add_thread(struct k_mem_domain *domain, k_tid_t thread)
&thread->mem_domain_info.mem_domain_q_node);
thread->mem_domain_info.mem_domain = domain;

if (_current == thread) {
z_arch_mem_domain_configure(thread);
}
z_arch_mem_domain_thread_add(thread);

k_spin_unlock(&lock, key);
}
@@ -258,13 +240,10 @@ void k_mem_domain_remove_thread(k_tid_t thread)
__ASSERT(thread->mem_domain_info.mem_domain != NULL, "mem domain set");

key = k_spin_lock(&lock);
if (_current == thread) {
z_arch_mem_domain_destroy(thread->mem_domain_info.mem_domain);
}
z_arch_mem_domain_thread_remove(thread);

sys_dlist_remove(&thread->mem_domain_info.mem_domain_q_node);
thread->mem_domain_info.mem_domain = NULL;

k_spin_unlock(&lock, key);
}

0 comments on commit 8915e41

Please sign in to comment.
You can’t perform that action at this time.