diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 399fc8a2ecf..2ba4587c9ca 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -30,7 +30,7 @@ config RISCV_GP config RISCV_CURRENT_VIA_GP bool "Store current thread into the global pointer (GP) register" - depends on !RISCV_GP && !USERSPACE + depends on !RISCV_GP depends on MP_MAX_NUM_CPUS > 1 select ARCH_HAS_CUSTOM_CURRENT_IMPL help diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index ae8f63357a5..193f4820871 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -169,7 +169,9 @@ SECTION_FUNC(exception.entry, _isr_wrapper) .option norelax la gp, __global_pointer$ .option pop -#endif /* CONFIG_RISCV_GP */ +#elif defined(CONFIG_RISCV_CURRENT_VIA_GP) + lr gp, ___cpu_t_current_OFFSET(s0) +#endif /* CONFIG_RISCV_GP / CONFIG_RISCV_CURRENT_VIA_GP */ /* Clear our per-thread usermode flag */ lui t0, %tprel_hi(is_user_mode) diff --git a/tests/arch/riscv/userspace/riscv_gp/prj.conf b/tests/arch/riscv/userspace/riscv_gp/prj.conf index 1f8e1275be3..e39776e7067 100644 --- a/tests/arch/riscv/userspace/riscv_gp/prj.conf +++ b/tests/arch/riscv/userspace/riscv_gp/prj.conf @@ -1,3 +1,2 @@ CONFIG_ZTEST=y -CONFIG_RISCV_GP=y CONFIG_TEST_USERSPACE=y diff --git a/tests/arch/riscv/userspace/riscv_gp/src/main.c b/tests/arch/riscv/userspace/riscv_gp/src/main.c index 76a9ecffc22..738ba94b968 100644 --- a/tests/arch/riscv/userspace/riscv_gp/src/main.c +++ b/tests/arch/riscv/userspace/riscv_gp/src/main.c @@ -10,6 +10,10 @@ #include #include +#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"); } diff --git a/tests/arch/riscv/userspace/riscv_gp/testcase.yaml b/tests/arch/riscv/userspace/riscv_gp/testcase.yaml index 5b1345abc54..cedec864a2e 100644 --- a/tests/arch/riscv/userspace/riscv_gp/testcase.yaml +++ b/tests/arch/riscv/userspace/riscv_gp/testcase.yaml @@ -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