Skip to content

Commit 033804e

Browse files
ycsinkartben
authored andcommitted
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 <[email protected]> Signed-off-by: Yong Cong Sin <[email protected]>
1 parent 1eeee01 commit 033804e

File tree

5 files changed

+55
-7
lines changed

5 files changed

+55
-7
lines changed

arch/riscv/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ config RISCV_GP
3030

3131
config RISCV_CURRENT_VIA_GP
3232
bool "Store current thread into the global pointer (GP) register"
33-
depends on !RISCV_GP && !USERSPACE
33+
depends on !RISCV_GP
3434
depends on MP_MAX_NUM_CPUS > 1
3535
select ARCH_HAS_CUSTOM_CURRENT_IMPL
3636
help

arch/riscv/core/isr.S

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ SECTION_FUNC(exception.entry, _isr_wrapper)
169169
.option norelax
170170
la gp, __global_pointer$
171171
.option pop
172-
#endif /* CONFIG_RISCV_GP */
172+
#elif defined(CONFIG_RISCV_CURRENT_VIA_GP)
173+
lr gp, ___cpu_t_current_OFFSET(s0)
174+
#endif /* CONFIG_RISCV_GP / CONFIG_RISCV_CURRENT_VIA_GP */
173175

174176
/* Clear our per-thread usermode flag */
175177
lui t0, %tprel_hi(is_user_mode)
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
CONFIG_ZTEST=y
2-
CONFIG_RISCV_GP=y
32
CONFIG_TEST_USERSPACE=y

tests/arch/riscv/userspace/riscv_gp/src/main.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include <zephyr/kernel.h>
1111
#include <zephyr/ztest.h>
1212

13+
#if !defined(CONFIG_RISCV_GP) && !defined(CONFIG_RISCV_CURRENT_VIA_GP)
14+
#error "CONFIG_RISCV_GP or CONFIG_RISCV_CURRENT_VIA_GP must be enabled for this test"
15+
#endif
16+
1317
#define ROGUE_USER_STACK_SZ 2048
1418

1519
static struct k_thread rogue_user_thread;
@@ -18,22 +22,58 @@ static K_THREAD_STACK_DEFINE(rogue_user_stack, ROGUE_USER_STACK_SZ);
1822
static void rogue_user_fn(void *p1, void *p2, void *p3)
1923
{
2024
zassert_true(k_is_user_context());
25+
uintptr_t gp_val = reg_read(gp);
26+
uintptr_t gp_test_val;
2127

28+
/* Make sure that `gp` is as expected */
29+
if (IS_ENABLED(CONFIG_RISCV_GP)) {
30+
__asm__ volatile("la %0, __global_pointer$" : "=r" (gp_test_val));
31+
} else { /* CONFIG_RISCV_CURRENT_VIA_GP */
32+
gp_test_val = (uintptr_t)k_current_get();
33+
}
34+
35+
/* Corrupt `gp` reg */
2236
reg_write(gp, 0xbad);
23-
zassert_equal(reg_read(gp), 0xbad);
37+
38+
/* Make sure that `gp` is corrupted */
39+
if (IS_ENABLED(CONFIG_RISCV_GP)) {
40+
zassert_equal(reg_read(gp), 0xbad);
41+
} else { /* CONFIG_RISCV_CURRENT_VIA_GP */
42+
zassert_equal((uintptr_t)arch_current_thread(), 0xbad);
43+
}
44+
45+
/* Sleep to force a context switch, which will sanitize `gp` */
46+
k_msleep(50);
47+
48+
/* Make sure that `gp` is sane again */
49+
if (IS_ENABLED(CONFIG_RISCV_GP)) {
50+
__asm__ volatile("la %0, __global_pointer$" : "=r" (gp_test_val));
51+
} else { /* CONFIG_RISCV_CURRENT_VIA_GP */
52+
gp_test_val = (uintptr_t)k_current_get();
53+
}
54+
55+
zassert_equal(gp_val, gp_test_val);
2456
}
2557

2658
ZTEST_USER(riscv_gp, test_gp_value)
2759
{
2860
uintptr_t gp_val = reg_read(gp);
61+
uintptr_t gp_test_val;
2962
k_tid_t th;
3063

31-
zassert_not_equal(gp_val, 0);
64+
if (IS_ENABLED(CONFIG_RISCV_GP)) {
65+
__asm__ volatile("la %0, __global_pointer$" : "=r" (gp_test_val));
66+
} else { /* CONFIG_RISCV_CURRENT_VIA_GP */
67+
gp_test_val = (uintptr_t)k_current_get();
68+
}
69+
zassert_equal(gp_val, gp_test_val);
3270

71+
/* Create and run a rogue thread to corrupt the `gp` */
3372
th = k_thread_create(&rogue_user_thread, rogue_user_stack, ROGUE_USER_STACK_SZ,
3473
rogue_user_fn, NULL, NULL, NULL, -1, K_USER, K_NO_WAIT);
3574
zassert_ok(k_thread_join(th, K_FOREVER));
3675

76+
/* Make sure that `gp` is the same as before a rogue thread was executed */
3777
zassert_equal(reg_read(gp), gp_val, "`gp` corrupted by user thread");
3878
}
3979

tests/arch/riscv/userspace/riscv_gp/testcase.yaml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ common:
33
ignore_qemu_crash: true
44
tags: kernel riscv
55
platform_allow:
6-
- qemu_riscv64
6+
- qemu_riscv64/qemu_virt_riscv64/smp
77
tests:
8-
arch.riscv64.riscv_gp: {}
8+
arch.riscv64.riscv_gp.relative_addressing:
9+
extra_configs:
10+
- CONFIG_RISCV_GP=y
11+
- CONFIG_RISCV_CURRENT_VIA_GP=n
12+
arch.riscv64.riscv_gp.thread_pointer:
13+
extra_configs:
14+
- CONFIG_RISCV_CURRENT_VIA_GP=y
15+
- CONFIG_RISCV_GP=n

0 commit comments

Comments
 (0)