x86: userspace: page in stack before starting user thread

If generic section is not present at boot, the thread stack
may not be in physical memory. Unconditionally page in the stack
instead of relying on page fault to speed up a little bit
on starting the thread.

Also, this prevents a double fault during thread setup when
setting up stack permission in z_x86_userspace_enter().

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2021-07-15 12:52:21 -07:00 committed by Christopher Friedt
commit 7605619c1e

View file

@ -106,6 +106,42 @@ FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry,
stack_end -= 8;
#endif
#if defined(CONFIG_DEMAND_PAGING) && \
!defined(CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT)
/* If generic section is not present at boot,
* the thread stack may not be in physical memory.
* Unconditionally page in the stack instead of
* relying on page fault to speed up a little bit
* on starting the thread.
*
* Note that this also needs to page in the reserved
* portion of the stack (which is usually the page just
* before the beginning of stack in
* _current->stack_info.start.
*/
uintptr_t stack_start;
size_t stack_size;
uintptr_t stack_aligned_start;
size_t stack_aligned_size;
stack_start = POINTER_TO_UINT(_current->stack_obj);
stack_size = Z_THREAD_STACK_SIZE_ADJUST(_current->stack_info.size);
#if defined(CONFIG_HW_STACK_PROTECTION)
/* With hardware stack protection, the first page of stack
* is a guard page. So need to skip it.
*/
stack_start += CONFIG_MMU_PAGE_SIZE;
stack_size -= CONFIG_MMU_PAGE_SIZE;
#endif
(void)k_mem_region_align(&stack_aligned_start, &stack_aligned_size,
stack_start, stack_size,
CONFIG_MMU_PAGE_SIZE);
k_mem_page_in(UINT_TO_POINTER(stack_aligned_start),
stack_aligned_size);
#endif
z_x86_userspace_enter(user_entry, p1, p2, p3, stack_end,
_current->stack_info.start);
CODE_UNREACHABLE;