xtensa: userspace: swap page tables via assembly code

Since the necessary register values are now pre-computed and
stored in the memory domain struct, we can use them directly
in various assembly locations, thus replacing the function
call to xtensa_swap_update_page_tables().

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2025-04-04 13:44:40 -07:00 committed by Benjamin Cabé
commit 277fa9e8ac
8 changed files with 77 additions and 13 deletions

View file

@ -71,6 +71,18 @@ GEN_OFFSET_SYM(_thread_arch_t, return_ps);
GEN_OFFSET_SYM(_thread_t, switch_handle); GEN_OFFSET_SYM(_thread_t, switch_handle);
#ifdef CONFIG_XTENSA_MMU #ifdef CONFIG_XTENSA_MMU
GEN_OFFSET_SYM(_thread_arch_t, ptables); GEN_OFFSET_SYM(_thread_arch_t, ptables);
GEN_OFFSET_SYM(_thread_t, mem_domain_info);
GEN_OFFSET_SYM(_mem_domain_info_t, mem_domain);
GEN_OFFSET_SYM(k_mem_domain_t, arch);
GEN_OFFSET_SYM(arch_mem_domain_t, reg_asid);
GEN_OFFSET_SYM(arch_mem_domain_t, reg_ptevaddr);
GEN_OFFSET_SYM(arch_mem_domain_t, reg_ptepin_as);
GEN_OFFSET_SYM(arch_mem_domain_t, reg_ptepin_at);
GEN_OFFSET_SYM(arch_mem_domain_t, reg_vecpin_as);
GEN_OFFSET_SYM(arch_mem_domain_t, reg_vecpin_at);
#endif #endif
#ifdef CONFIG_XTENSA_MPU #ifdef CONFIG_XTENSA_MPU
GEN_OFFSET_SYM(_thread_arch_t, mpu_map); GEN_OFFSET_SYM(_thread_arch_t, mpu_map);

View file

@ -1122,12 +1122,4 @@ int arch_buffer_validate(const void *addr, size_t size, int write)
return mem_buffer_validate(addr, size, write, XTENSA_MMU_USER_RING); return mem_buffer_validate(addr, size, write, XTENSA_MMU_USER_RING);
} }
void xtensa_swap_update_page_tables(struct k_thread *incoming)
{
struct arch_mem_domain *domain =
&(incoming->mem_domain_info.mem_domain->arch);
xtensa_mmu_set_paging(domain);
}
#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_USERSPACE */

View file

@ -271,7 +271,7 @@ xtensa_userspace_enter:
l32i a6, a1, 24 l32i a6, a1, 24
#ifdef CONFIG_XTENSA_MMU #ifdef CONFIG_XTENSA_MMU
call4 xtensa_swap_update_page_tables SWAP_PAGE_TABLE a6, a3, a7
#endif #endif
#ifdef CONFIG_XTENSA_MPU #ifdef CONFIG_XTENSA_MPU
call4 xtensa_mpu_map_write call4 xtensa_mpu_map_write

View file

@ -248,11 +248,10 @@ xtensa_switch:
s32i a6, a1, 8 s32i a6, a1, 8
s32i a7, a1, 12 s32i a7, a1, 12
/* Switch page tables */
rsr a6, ZSR_CPU rsr a6, ZSR_CPU
l32i a6, a6, ___cpu_t_current_OFFSET l32i a6, a6, ___cpu_t_current_OFFSET
#ifdef CONFIG_XTENSA_MMU #ifdef CONFIG_XTENSA_MMU
call4 xtensa_swap_update_page_tables SWAP_PAGE_TABLE a6, a4, a7
#endif #endif
#ifdef CONFIG_XTENSA_MPU #ifdef CONFIG_XTENSA_MPU
call4 xtensa_mpu_map_write call4 xtensa_mpu_map_write

View file

@ -17,6 +17,28 @@
#define _thread_offset_to_ptables \ #define _thread_offset_to_ptables \
(___thread_t_arch_OFFSET + ___thread_arch_t_ptables_OFFSET) (___thread_t_arch_OFFSET + ___thread_arch_t_ptables_OFFSET)
#define _thread_offset_to_mem_domain \
(___thread_t_mem_domain_info_OFFSET + ___mem_domain_info_t_mem_domain_OFFSET)
#define _k_mem_domain_offset_to_arch_reg_asid \
(__k_mem_domain_t_arch_OFFSET + __arch_mem_domain_t_reg_asid_OFFSET)
#define _k_mem_domain_offset_to_arch_reg_ptevaddr \
(__k_mem_domain_t_arch_OFFSET + __arch_mem_domain_t_reg_ptevaddr_OFFSET)
#define _k_mem_domain_offset_to_arch_reg_ptepin_as \
(__k_mem_domain_t_arch_OFFSET + __arch_mem_domain_t_reg_ptepin_as_OFFSET)
#define _k_mem_domain_offset_to_arch_reg_ptepin_at \
(__k_mem_domain_t_arch_OFFSET + __arch_mem_domain_t_reg_ptepin_at_OFFSET)
#define _k_mem_domain_offset_to_arch_reg_vecpin_as \
(__k_mem_domain_t_arch_OFFSET + __arch_mem_domain_t_reg_vecpin_as_OFFSET)
#define _k_mem_domain_offset_to_arch_reg_vecpin_at \
(__k_mem_domain_t_arch_OFFSET + __arch_mem_domain_t_reg_vecpin_at_OFFSET)
#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_USERSPACE */
#endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ */ #endif /* ZEPHYR_ARCH_XTENSA_INCLUDE_OFFSETS_SHORT_ARCH_H_ */

View file

@ -225,6 +225,44 @@
.endm .endm
#if defined(CONFIG_XTENSA_MMU) && defined(CONFIG_USERSPACE)
/*
* SWAP_PAGE_TABLE
*
* This swaps the page tables by using the pre-computed register values
* inside the architecture-specific memory domain struct.
*
* THREAD_PTR_REG is input containing pointer to the incoming thread struct.
* SC1_REG and SC2_REG are scratch registers.
*
* Note that all THREAD_PTR_REG, SC1_REG and SC2_REG are all clobbered.
* Restore the thread pointer after this if necessary.
*/
.macro SWAP_PAGE_TABLE THREAD_PTR_REG, SC1_REG, SC2_REG
l32i \THREAD_PTR_REG, \THREAD_PTR_REG, _thread_offset_to_mem_domain
j _swap_page_table_\@
.align 16
_swap_page_table_\@:
l32i \SC1_REG, \THREAD_PTR_REG, _k_mem_domain_offset_to_arch_reg_ptevaddr
l32i \SC2_REG, \THREAD_PTR_REG, _k_mem_domain_offset_to_arch_reg_asid
wsr \SC1_REG, PTEVADDR
wsr \SC2_REG, RASID
l32i \SC1_REG, \THREAD_PTR_REG, _k_mem_domain_offset_to_arch_reg_ptepin_as
l32i \SC2_REG, \THREAD_PTR_REG, _k_mem_domain_offset_to_arch_reg_ptepin_at
wdtlb \SC2_REG, \SC1_REG
l32i \SC1_REG, \THREAD_PTR_REG, _k_mem_domain_offset_to_arch_reg_vecpin_as
l32i \SC2_REG, \THREAD_PTR_REG, _k_mem_domain_offset_to_arch_reg_vecpin_at
wdtlb \SC2_REG, \SC1_REG
isync
.endm
#endif /* CONFIG_XTENSA_MMU && CONFIG_USERSPACE */
/* /*
* CROSS_STACK_CALL * CROSS_STACK_CALL
* *
@ -357,7 +395,7 @@ _xstack_call0_\@:
l32i a6, a6, ___cpu_t_current_OFFSET l32i a6, a6, ___cpu_t_current_OFFSET
#ifdef CONFIG_XTENSA_MMU #ifdef CONFIG_XTENSA_MMU
call4 xtensa_swap_update_page_tables SWAP_PAGE_TABLE a6, a3, a7
#endif #endif
#ifdef CONFIG_XTENSA_MPU #ifdef CONFIG_XTENSA_MPU
call4 xtensa_mpu_map_write call4 xtensa_mpu_map_write

View file

@ -81,6 +81,8 @@ struct arch_mem_domain {
sys_snode_t node; sys_snode_t node;
}; };
typedef struct arch_mem_domain arch_mem_domain_t;
/** /**
* @brief Generate hardware exception. * @brief Generate hardware exception.
* *

View file

@ -162,7 +162,6 @@ SECTIONS
/* Userspace related stuff */ /* Userspace related stuff */
LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,xtensa_do_syscall) LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,userspace.S.obj,xtensa_do_syscall)
LIB_OBJ_FUNC_IN_SECT(libarch__xtensa__core.a,ptables.c.obj,xtensa_swap_update_page_tables)
/* Below are to speed up execution by avoiding TLB misses /* Below are to speed up execution by avoiding TLB misses
* on frequently used functions. * on frequently used functions.