userspace: fix x86 issue with adding partitions
On x86, if a supervisor thread belonging to a memory domain adds a new partition to that domain, subsequent context switches to another thread in the same domain, or dropping itself to user mode, does not have the correct setup in the page tables. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
c5592de5ae
commit
6dc3fd8e50
5 changed files with 79 additions and 33 deletions
|
@ -143,6 +143,12 @@ void _arch_mem_domain_destroy(struct k_mem_domain *domain)
|
|||
arc_core_mpu_enable();
|
||||
}
|
||||
|
||||
void _arch_mem_domain_partition_add(struct k_mem_domain *domain,
|
||||
u32_t partition_id)
|
||||
{
|
||||
/* No-op on this architecture */
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the given buffer is user accessible or not
|
||||
*/
|
||||
|
|
|
@ -314,6 +314,12 @@ void _arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
|||
&domain->partitions[partition_id], &reset_attr);
|
||||
}
|
||||
|
||||
void _arch_mem_domain_partition_add(struct k_mem_domain *domain,
|
||||
u32_t partition_id)
|
||||
{
|
||||
/* No-op on this architecture */
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the given buffer is user accessible or not
|
||||
*/
|
||||
|
|
|
@ -236,6 +236,24 @@ void z_x86_reset_pages(void *start, size_t size)
|
|||
#endif /* CONFIG_X86_KPTI */
|
||||
}
|
||||
|
||||
static inline void activate_partition(struct k_mem_partition *partition)
|
||||
{
|
||||
/* Set the partition attributes */
|
||||
u64_t attr, mask;
|
||||
|
||||
#if CONFIG_X86_KPTI
|
||||
attr = partition->attr | MMU_ENTRY_PRESENT;
|
||||
mask = K_MEM_PARTITION_PERM_MASK | MMU_PTE_P_MASK;
|
||||
#else
|
||||
attr = partition->attr;
|
||||
mask = K_MEM_PARTITION_PERM_MASK;
|
||||
#endif /* CONFIG_X86_KPTI */
|
||||
|
||||
_x86_mmu_set_flags(&USER_PDPT,
|
||||
(void *)partition->start,
|
||||
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)
|
||||
|
@ -245,7 +263,7 @@ static inline void _x86_mem_domain_pages_update(struct k_mem_domain *mem_domain,
|
|||
{
|
||||
u32_t partition_index;
|
||||
u32_t total_partitions;
|
||||
struct k_mem_partition partition;
|
||||
struct k_mem_partition *partition;
|
||||
u32_t partitions_count;
|
||||
|
||||
/* If mem_domain doesn't point to a valid location return.*/
|
||||
|
@ -266,29 +284,16 @@ static inline void _x86_mem_domain_pages_update(struct k_mem_domain *mem_domain,
|
|||
partition_index++) {
|
||||
|
||||
/* Get the partition info */
|
||||
partition = mem_domain->partitions[partition_index];
|
||||
if (partition.size == 0) {
|
||||
partition = &mem_domain->partitions[partition_index];
|
||||
if (partition->size == 0) {
|
||||
continue;
|
||||
}
|
||||
partitions_count++;
|
||||
if (page_conf == X86_MEM_DOMAIN_SET_PAGES) {
|
||||
/* Set the partition attributes */
|
||||
u64_t attr, mask;
|
||||
|
||||
#if CONFIG_X86_KPTI
|
||||
attr = partition.attr | MMU_ENTRY_PRESENT;
|
||||
mask = K_MEM_PARTITION_PERM_MASK | MMU_PTE_P_MASK;
|
||||
#else
|
||||
attr = partition.attr;
|
||||
mask = K_MEM_PARTITION_PERM_MASK;
|
||||
#endif /* CONFIG_X86_KPTI */
|
||||
|
||||
_x86_mmu_set_flags(&USER_PDPT,
|
||||
(void *)partition.start,
|
||||
partition.size, attr, mask);
|
||||
activate_partition(partition);
|
||||
} else {
|
||||
z_x86_reset_pages((void *)partition.start,
|
||||
partition.size);
|
||||
z_x86_reset_pages((void *)partition->start,
|
||||
partition->size);
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
@ -314,19 +319,28 @@ void _arch_mem_domain_destroy(struct k_mem_domain *domain)
|
|||
void _arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
||||
u32_t partition_id)
|
||||
{
|
||||
struct k_mem_partition partition;
|
||||
|
||||
if (domain == NULL) {
|
||||
goto out;
|
||||
}
|
||||
struct k_mem_partition *partition;
|
||||
|
||||
__ASSERT_NO_MSG(domain != NULL);
|
||||
__ASSERT(partition_id <= domain->num_partitions,
|
||||
"invalid partitions");
|
||||
|
||||
partition = domain->partitions[partition_id];
|
||||
z_x86_reset_pages((void *)partition.start, partition.size);
|
||||
out:
|
||||
return;
|
||||
partition = &domain->partitions[partition_id];
|
||||
z_x86_reset_pages((void *)partition->start, partition->size);
|
||||
}
|
||||
|
||||
/* Reset/destroy one partition spcified in the argument of the API. */
|
||||
void _arch_mem_domain_partition_add(struct k_mem_domain *domain,
|
||||
u32_t partition_id)
|
||||
{
|
||||
struct k_mem_partition *partition;
|
||||
|
||||
__ASSERT_NO_MSG(domain != NULL);
|
||||
__ASSERT(partition_id <= domain->num_partitions,
|
||||
"invalid partitions");
|
||||
|
||||
partition = &domain->partitions[partition_id];
|
||||
activate_partition(partition);
|
||||
}
|
||||
|
||||
int _arch_mem_domain_max_partitions_get(void)
|
||||
|
|
|
@ -85,6 +85,7 @@ extern void _arch_mem_domain_configure(struct k_thread *thread);
|
|||
* 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.
|
||||
*
|
||||
* @param domain The memory domain structure
|
||||
* @param partition_id The partition that needs to be deleted
|
||||
|
@ -92,6 +93,20 @@ extern void _arch_mem_domain_configure(struct k_thread *thread);
|
|||
extern void _arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
||||
u32_t partition_id);
|
||||
|
||||
/**
|
||||
* @brief Remove a partition from 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.
|
||||
*
|
||||
* @param domain The memory domain structure
|
||||
* @param partition_id The partition that needs to be added
|
||||
*/
|
||||
extern void _arch_mem_domain_partition_add(struct k_mem_domain *domain,
|
||||
u32_t partition_id);
|
||||
|
||||
/**
|
||||
* @brief Remove the memory domain
|
||||
*
|
||||
|
@ -102,9 +117,7 @@ extern void _arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
|||
* @param domain The memory domain structure which needs to be deleted.
|
||||
*/
|
||||
extern void _arch_mem_domain_destroy(struct k_mem_domain *domain);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
/**
|
||||
* @brief Check memory region permissions
|
||||
*
|
||||
|
|
|
@ -178,6 +178,13 @@ void k_mem_domain_add_partition(struct k_mem_domain *domain,
|
|||
|
||||
domain->num_partitions++;
|
||||
|
||||
/* Handle architecture-specific remove
|
||||
* only if it is the current thread.
|
||||
*/
|
||||
if (_current->mem_domain_info.mem_domain == domain) {
|
||||
_arch_mem_domain_partition_add(domain, p_idx);
|
||||
}
|
||||
|
||||
k_spin_unlock(&lock, key);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue