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>
This commit is contained in:
parent
fddd550824
commit
8915e41b7b
7 changed files with 131 additions and 67 deletions
|
@ -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,11 +378,8 @@ 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,
|
||||
void z_x86_mem_domain_pages_update(struct k_mem_domain *mem_domain,
|
||||
u32_t page_conf)
|
||||
{
|
||||
u32_t partition_index;
|
||||
|
@ -424,9 +422,13 @@ out:
|
|||
}
|
||||
|
||||
/* 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,
|
||||
if (_current != thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
z_x86_mem_domain_pages_update(thread->mem_domain_info.mem_domain,
|
||||
X86_MEM_DOMAIN_SET_PAGES);
|
||||
}
|
||||
|
||||
|
@ -435,7 +437,20 @@ void z_arch_mem_domain_configure(struct k_thread *thread)
|
|||
*/
|
||||
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,40 +73,48 @@ 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)
|
||||
*
|
||||
* 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.
|
||||
* Architecture-specific hook to manage internal data structures or hardware
|
||||
* state when the provided thread has been added to a memory domain.
|
||||
*
|
||||
* 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);
|
||||
|
@ -114,10 +122,8 @@ extern void z_arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
|||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue