riscv: clarify stack size and alignment parameters
The StackGuard area is used to save the esf and run the exception code resulting from a StackGuard trap. Size it appropriately. Remove redundancy, clarify documentation, etc. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
parent
3997f7bed2
commit
6051ea7d3c
|
@ -169,10 +169,13 @@ config PMP_STACK_GUARD
|
|||
config PMP_STACK_GUARD_MIN_SIZE
|
||||
int "Guard size"
|
||||
depends on PMP_STACK_GUARD
|
||||
default 64
|
||||
default 1024 if 64BIT
|
||||
default 512
|
||||
help
|
||||
Size of the stack guard area. This should be large enough to
|
||||
accommodate the stack overflow exception stack usage.
|
||||
catch any sudden jump in stack pointer decrement, plus some
|
||||
wiggle room to accommodate the eventual overflow exception
|
||||
stack usage.
|
||||
|
||||
config PMP_POWER_OF_TWO_ALIGNMENT
|
||||
bool "Enforce power-of-two alignment on PMP memory areas"
|
||||
|
@ -190,6 +193,7 @@ endmenu
|
|||
|
||||
config MAIN_STACK_SIZE
|
||||
default 4096 if 64BIT
|
||||
default 2048 if PMP_STACK_GUARD
|
||||
|
||||
config TEST_EXTRA_STACK_SIZE
|
||||
default 1024
|
||||
|
|
|
@ -338,15 +338,18 @@ void z_riscv_pmp_init(void)
|
|||
void z_riscv_pmp_stackguard_prepare(struct k_thread *thread)
|
||||
{
|
||||
unsigned int index = global_pmp_end_index;
|
||||
uintptr_t stack_bottom = thread->stack_info.start;
|
||||
uintptr_t stack_bottom;
|
||||
|
||||
/* Retrieve pmpcfg0 partial content from global entries */
|
||||
thread->arch.m_mode_pmpcfg_regs[0] = global_pmp_cfg[0];
|
||||
|
||||
/* make the bottom addresses of our stack inaccessible */
|
||||
stack_bottom = thread->stack_info.start - K_KERNEL_STACK_RESERVED;
|
||||
#ifdef CONFIG_USERSPACE
|
||||
if (thread->arch.priv_stack_start != 0) {
|
||||
stack_bottom = thread->arch.priv_stack_start;
|
||||
} else if (z_stack_is_user_capable(thread->stack_obj)) {
|
||||
stack_bottom = thread->stack_info.start - K_THREAD_STACK_RESERVED;
|
||||
}
|
||||
#endif
|
||||
set_pmp_entry(&index, PMP_NONE,
|
||||
|
|
|
@ -217,12 +217,11 @@ FUNC_NORETURN void arch_user_mode_enter(k_thread_entry_t user_entry,
|
|||
_current->arch.priv_stack_start =
|
||||
(ulong_t)z_priv_stack_find(_current->stack_obj);
|
||||
#else
|
||||
_current->arch.priv_stack_start =
|
||||
(ulong_t)(_current->stack_obj) +
|
||||
Z_RISCV_STACK_GUARD_SIZE;
|
||||
_current->arch.priv_stack_start = (ulong_t)_current->stack_obj;
|
||||
#endif /* CONFIG_GEN_PRIV_STACKS */
|
||||
top_of_priv_stack = Z_STACK_PTR_ALIGN(_current->arch.priv_stack_start
|
||||
+ CONFIG_PRIVILEGED_STACK_SIZE);
|
||||
top_of_priv_stack = Z_STACK_PTR_ALIGN(_current->arch.priv_stack_start +
|
||||
K_KERNEL_STACK_RESERVED +
|
||||
CONFIG_PRIVILEGED_STACK_SIZE);
|
||||
|
||||
top_of_user_stack = Z_STACK_PTR_ALIGN(
|
||||
_current->stack_info.start +
|
||||
|
|
|
@ -28,17 +28,26 @@
|
|||
#include <soc.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/arch/riscv/csr.h>
|
||||
#include <zephyr/arch/riscv/exp.h>
|
||||
|
||||
/* stacks, for RISCV architecture stack should be 16byte-aligned */
|
||||
#define ARCH_STACK_PTR_ALIGN 16
|
||||
|
||||
#ifdef CONFIG_PMP_STACK_GUARD
|
||||
#define Z_RISCV_PMP_ALIGN CONFIG_PMP_STACK_GUARD_MIN_SIZE
|
||||
#define Z_RISCV_STACK_GUARD_SIZE Z_RISCV_PMP_ALIGN
|
||||
#else
|
||||
#define Z_RISCV_PMP_ALIGN 4
|
||||
#define Z_RISCV_STACK_GUARD_SIZE 0
|
||||
#endif
|
||||
/*
|
||||
* The StackGuard is an area at the bottom of the kernel-mode stack made to
|
||||
* fault when accessed. It is _not_ faulting when in exception mode as we rely
|
||||
* on that area to save the exception stack frame and to process said fault.
|
||||
* Therefore the guard area must be large enough to hold the esf, plus some
|
||||
* configurable stack wiggle room to execute the fault handling code off of,
|
||||
* as well as some guard size to cover possible sudden stack pointer
|
||||
* displacement before the fault.
|
||||
*
|
||||
* The m-mode PMP set is not overly used so no need to force NAPOT.
|
||||
*/
|
||||
#define Z_RISCV_STACK_GUARD_SIZE \
|
||||
ROUND_UP(sizeof(z_arch_esf_t) + CONFIG_PMP_STACK_GUARD_MIN_SIZE, \
|
||||
ARCH_STACK_PTR_ALIGN)
|
||||
|
||||
/* Kernel-only stacks have the following layout if a stack guard is enabled:
|
||||
*
|
||||
|
@ -52,31 +61,40 @@
|
|||
* | TLS | } thread.stack_info.delta
|
||||
* +------------+ <- thread.stack_info.start + thread.stack_info.size
|
||||
*/
|
||||
#ifdef CONFIG_PMP_STACK_GUARD
|
||||
#define ARCH_KERNEL_STACK_RESERVED Z_RISCV_STACK_GUARD_SIZE
|
||||
#define ARCH_KERNEL_STACK_OBJ_ALIGN \
|
||||
MAX(Z_RISCV_PMP_ALIGN, ARCH_STACK_PTR_ALIGN)
|
||||
|
||||
#else /* !CONFIG_PMP_STACK_GUARD */
|
||||
#define Z_RISCV_STACK_GUARD_SIZE 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
/* Any thread running In user mode will have full access to the region denoted
|
||||
* by thread.stack_info.
|
||||
*
|
||||
* Thread-local storage is at the very highest memory locations of this area.
|
||||
* Memory for TLS and any initial random stack pointer offset is captured
|
||||
* in thread.stack_info.delta.
|
||||
*/
|
||||
#ifdef CONFIG_PMP_STACK_GUARD
|
||||
#ifdef CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT
|
||||
/* Use defaults for everything. The privilege elevation stack is located
|
||||
* in another area of memory generated at build time by gen_kobject_list.py
|
||||
/* The privilege elevation stack is located in another area of memory
|
||||
* generated at build time by gen_kobject_list.py
|
||||
*
|
||||
* +------------+ <- thread.arch.priv_stack_start
|
||||
* | Guard | } Z_RISCV_STACK_GUARD_SIZE
|
||||
* +------------+
|
||||
* | Priv Stack | } CONFIG_PRIVILEGED_STACK_SIZE - Z_RISCV_STACK_GUARD_SIZE
|
||||
* | Priv Stack | } CONFIG_PRIVILEGED_STACK_SIZE
|
||||
* +------------+ <- thread.arch.priv_stack_start +
|
||||
* CONFIG_PRIVILEGED_STACK_SIZE
|
||||
* CONFIG_PRIVILEGED_STACK_SIZE +
|
||||
* Z_RISCV_STACK_GUARD_SIZE
|
||||
*
|
||||
* The main stack will be initially (or potentially only) used by kernel
|
||||
* mode so we need to make room for a possible stack guard area when enabled:
|
||||
*
|
||||
* +------------+ <- thread.stack_obj
|
||||
* | Guard | } Z_RISCV_STACK_GUARD_SIZE
|
||||
* +............| <- thread.stack_info.start
|
||||
* | Thread |
|
||||
* | stack |
|
||||
* | |
|
||||
* +............|
|
||||
* | TLS | } thread.stack_info.delta
|
||||
* +------------+ <- thread.stack_info.start + thread.stack_info.size
|
||||
*
|
||||
* When transitioning to user space, the guard area will be removed from
|
||||
* the main stack. Any thread running in user mode will have full access
|
||||
* to the region denoted by thread.stack_info. Make it PMP-NAPOT compatible.
|
||||
*
|
||||
* +------------+ <- thread.stack_obj = thread.stack_info.start
|
||||
* | Thread |
|
||||
|
@ -86,65 +104,20 @@
|
|||
* | TLS | } thread.stack_info.delta
|
||||
* +------------+ <- thread.stack_info.start + thread.stack_info.size
|
||||
*/
|
||||
#define ARCH_THREAD_STACK_RESERVED Z_RISCV_STACK_GUARD_SIZE
|
||||
#define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
|
||||
Z_POW2_CEIL(ROUND_UP((size), Z_RISCV_PMP_ALIGN))
|
||||
Z_POW2_CEIL(MAX(size, CONFIG_PRIVILEGED_STACK_SIZE))
|
||||
#define ARCH_THREAD_STACK_OBJ_ALIGN(size) \
|
||||
ARCH_THREAD_STACK_SIZE_ADJUST(size)
|
||||
#define ARCH_THREAD_STACK_RESERVED 0
|
||||
|
||||
#else /* !CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT */
|
||||
|
||||
/* The stack object will contain the PMP guard, the privilege stack, and then
|
||||
* the stack buffer in that order:
|
||||
* the usermode stack buffer in that order:
|
||||
*
|
||||
* +------------+ <- thread.stack_obj
|
||||
* | Guard | } Z_RISCV_STACK_GUARD_SIZE
|
||||
* +------------+ <- thread.arch.priv_stack_start
|
||||
* | Priv Stack | } CONFIG_PRIVILEGED_STACK_SIZE
|
||||
* +------------+ <- thread.stack_info.start
|
||||
* | Thread |
|
||||
* | stack |
|
||||
* | |
|
||||
* +............|
|
||||
* | TLS | } thread.stack_info.delta
|
||||
* +------------+ <- thread.stack_info.start + thread.stack_info.size
|
||||
*/
|
||||
#define ARCH_THREAD_STACK_RESERVED (Z_RISCV_STACK_GUARD_SIZE + \
|
||||
CONFIG_PRIVILEGED_STACK_SIZE)
|
||||
#define ARCH_THREAD_STACK_OBJ_ALIGN(size) Z_RISCV_PMP_ALIGN
|
||||
/* We need to be able to exactly cover the stack buffer with an PMP region,
|
||||
* so round its size up to the required granularity of the PMP
|
||||
*/
|
||||
#define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
|
||||
(ROUND_UP((size), Z_RISCV_PMP_ALIGN))
|
||||
|
||||
#endif /* CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT */
|
||||
#else /* !CONFIG_PMP_STACK_GUARD */
|
||||
#ifdef CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT
|
||||
/* Use defaults for everything. The privilege elevation stack is located
|
||||
* in another area of memory generated at build time by gen_kobject_list.py
|
||||
*
|
||||
* +------------+ <- thread.arch.priv_stack_start
|
||||
* | Priv Stack | } Z_KERNEL_STACK_LEN(CONFIG_PRIVILEGED_STACK_SIZE)
|
||||
* +------------+
|
||||
*
|
||||
* +------------+ <- thread.stack_obj = thread.stack_info.start
|
||||
* | Thread |
|
||||
* | stack |
|
||||
* | |
|
||||
* +............|
|
||||
* | TLS | } thread.stack_info.delta
|
||||
* +------------+ <- thread.stack_info.start + thread.stack_info.size
|
||||
*/
|
||||
#define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
|
||||
Z_POW2_CEIL(ROUND_UP((size), Z_RISCV_PMP_ALIGN))
|
||||
#define ARCH_THREAD_STACK_OBJ_ALIGN(size) \
|
||||
ARCH_THREAD_STACK_SIZE_ADJUST(size)
|
||||
#define ARCH_THREAD_STACK_RESERVED 0
|
||||
#else /* !CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT */
|
||||
/* Userspace enabled, but supervisor stack guards are not in use */
|
||||
|
||||
/* Reserved area of the thread object just contains the privilege stack:
|
||||
*
|
||||
* +------------+ <- thread.stack_obj = thread.arch.priv_stack_start
|
||||
* | Priv Stack | } CONFIG_PRIVILEGED_STACK_SIZE
|
||||
* +------------+ <- thread.stack_info.start
|
||||
* | Thread |
|
||||
|
@ -154,38 +127,11 @@
|
|||
* | TLS | } thread.stack_info.delta
|
||||
* +------------+ <- thread.stack_info.start + thread.stack_info.size
|
||||
*/
|
||||
#define ARCH_THREAD_STACK_RESERVED CONFIG_PRIVILEGED_STACK_SIZE
|
||||
#define ARCH_THREAD_STACK_SIZE_ADJUST(size) \
|
||||
(ROUND_UP((size), Z_RISCV_PMP_ALIGN))
|
||||
#define ARCH_THREAD_STACK_OBJ_ALIGN(size) Z_RISCV_PMP_ALIGN
|
||||
#define ARCH_THREAD_STACK_RESERVED \
|
||||
ROUND_UP(Z_RISCV_STACK_GUARD_SIZE + CONFIG_PRIVILEGED_STACK_SIZE, \
|
||||
ARCH_STACK_PTR_ALIGN)
|
||||
|
||||
#endif /* CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT */
|
||||
#endif /* CONFIG_PMP_STACK_GUARD */
|
||||
|
||||
#else /* !CONFIG_USERSPACE */
|
||||
|
||||
#ifdef CONFIG_PMP_STACK_GUARD
|
||||
/* Reserve some memory for the stack guard.
|
||||
* This is just a minimally-sized region at the beginning of the stack
|
||||
* object, which is programmed to produce an exception if written to.
|
||||
*
|
||||
* +------------+ <- thread.stack_obj
|
||||
* | Guard | } Z_RISCV_STACK_GUARD_SIZE
|
||||
* +------------+ <- thread.stack_info.start
|
||||
* | Thread |
|
||||
* | stack |
|
||||
* | |
|
||||
* +............|
|
||||
* | TLS | } thread.stack_info.delta
|
||||
* +------------+ <- thread.stack_info.start + thread.stack_info.size
|
||||
*/
|
||||
#define ARCH_THREAD_STACK_RESERVED Z_RISCV_STACK_GUARD_SIZE
|
||||
#define ARCH_THREAD_STACK_OBJ_ALIGN(size) Z_RISCV_PMP_ALIGN
|
||||
/* Default for ARCH_THREAD_STACK_SIZE_ADJUST */
|
||||
#else /* !CONFIG_PMP_STACK_GUARD */
|
||||
/* No stack guard, no userspace, Use defaults for everything. */
|
||||
#endif /* CONFIG_PMP_STACK_GUARD */
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define RV_REGSIZE 8
|
||||
|
|
|
@ -125,7 +125,7 @@ static inline void set_fault_valid(bool valid)
|
|||
#elif defined(CONFIG_ARM)
|
||||
#define MEM_REGION_ALLOC (Z_THREAD_MIN_STACK_ALIGN)
|
||||
#elif defined(CONFIG_RISCV)
|
||||
#define MEM_REGION_ALLOC (Z_RISCV_PMP_ALIGN)
|
||||
#define MEM_REGION_ALLOC (4)
|
||||
#else
|
||||
#error "Test suite not compatible for the given architecture"
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue