arch: riscv: support CONFIG_USERSPACE in CONFIG_RISCV_CURRENT_VIA_GP
Reset the the `gp` register to `_kernel->cpus[i].current` when `CONFIG_USERSPACE` is enabled on exception to keep it sane. Updated the testcase to test both `CONFIG_RISCV_GP` and `CONFIG_RISCV_CURRENT_VIA_GP`. Signed-off-by: Yong Cong Sin <ycsin@meta.com> Signed-off-by: Yong Cong Sin <yongcong.sin@gmail.com>
This commit is contained in:
parent
1eeee010bd
commit
033804e266
5 changed files with 55 additions and 7 deletions
|
@ -1,3 +1,2 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_RISCV_GP=y
|
||||
CONFIG_TEST_USERSPACE=y
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/ztest.h>
|
||||
|
||||
#if !defined(CONFIG_RISCV_GP) && !defined(CONFIG_RISCV_CURRENT_VIA_GP)
|
||||
#error "CONFIG_RISCV_GP or CONFIG_RISCV_CURRENT_VIA_GP must be enabled for this test"
|
||||
#endif
|
||||
|
||||
#define ROGUE_USER_STACK_SZ 2048
|
||||
|
||||
static struct k_thread rogue_user_thread;
|
||||
|
@ -18,22 +22,58 @@ static K_THREAD_STACK_DEFINE(rogue_user_stack, ROGUE_USER_STACK_SZ);
|
|||
static void rogue_user_fn(void *p1, void *p2, void *p3)
|
||||
{
|
||||
zassert_true(k_is_user_context());
|
||||
uintptr_t gp_val = reg_read(gp);
|
||||
uintptr_t gp_test_val;
|
||||
|
||||
/* Make sure that `gp` is as expected */
|
||||
if (IS_ENABLED(CONFIG_RISCV_GP)) {
|
||||
__asm__ volatile("la %0, __global_pointer$" : "=r" (gp_test_val));
|
||||
} else { /* CONFIG_RISCV_CURRENT_VIA_GP */
|
||||
gp_test_val = (uintptr_t)k_current_get();
|
||||
}
|
||||
|
||||
/* Corrupt `gp` reg */
|
||||
reg_write(gp, 0xbad);
|
||||
zassert_equal(reg_read(gp), 0xbad);
|
||||
|
||||
/* Make sure that `gp` is corrupted */
|
||||
if (IS_ENABLED(CONFIG_RISCV_GP)) {
|
||||
zassert_equal(reg_read(gp), 0xbad);
|
||||
} else { /* CONFIG_RISCV_CURRENT_VIA_GP */
|
||||
zassert_equal((uintptr_t)arch_current_thread(), 0xbad);
|
||||
}
|
||||
|
||||
/* Sleep to force a context switch, which will sanitize `gp` */
|
||||
k_msleep(50);
|
||||
|
||||
/* Make sure that `gp` is sane again */
|
||||
if (IS_ENABLED(CONFIG_RISCV_GP)) {
|
||||
__asm__ volatile("la %0, __global_pointer$" : "=r" (gp_test_val));
|
||||
} else { /* CONFIG_RISCV_CURRENT_VIA_GP */
|
||||
gp_test_val = (uintptr_t)k_current_get();
|
||||
}
|
||||
|
||||
zassert_equal(gp_val, gp_test_val);
|
||||
}
|
||||
|
||||
ZTEST_USER(riscv_gp, test_gp_value)
|
||||
{
|
||||
uintptr_t gp_val = reg_read(gp);
|
||||
uintptr_t gp_test_val;
|
||||
k_tid_t th;
|
||||
|
||||
zassert_not_equal(gp_val, 0);
|
||||
if (IS_ENABLED(CONFIG_RISCV_GP)) {
|
||||
__asm__ volatile("la %0, __global_pointer$" : "=r" (gp_test_val));
|
||||
} else { /* CONFIG_RISCV_CURRENT_VIA_GP */
|
||||
gp_test_val = (uintptr_t)k_current_get();
|
||||
}
|
||||
zassert_equal(gp_val, gp_test_val);
|
||||
|
||||
/* Create and run a rogue thread to corrupt the `gp` */
|
||||
th = k_thread_create(&rogue_user_thread, rogue_user_stack, ROGUE_USER_STACK_SZ,
|
||||
rogue_user_fn, NULL, NULL, NULL, -1, K_USER, K_NO_WAIT);
|
||||
zassert_ok(k_thread_join(th, K_FOREVER));
|
||||
|
||||
/* Make sure that `gp` is the same as before a rogue thread was executed */
|
||||
zassert_equal(reg_read(gp), gp_val, "`gp` corrupted by user thread");
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,13 @@ common:
|
|||
ignore_qemu_crash: true
|
||||
tags: kernel riscv
|
||||
platform_allow:
|
||||
- qemu_riscv64
|
||||
- qemu_riscv64/qemu_virt_riscv64/smp
|
||||
tests:
|
||||
arch.riscv64.riscv_gp: {}
|
||||
arch.riscv64.riscv_gp.relative_addressing:
|
||||
extra_configs:
|
||||
- CONFIG_RISCV_GP=y
|
||||
- CONFIG_RISCV_CURRENT_VIA_GP=n
|
||||
arch.riscv64.riscv_gp.thread_pointer:
|
||||
extra_configs:
|
||||
- CONFIG_RISCV_CURRENT_VIA_GP=y
|
||||
- CONFIG_RISCV_GP=n
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue