Commit 033804e2 authored by Yong Cong Sin's avatar Yong Cong Sin Committed by Benjamin Cabé
Browse files

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: default avatarYong Cong Sin <ycsin@meta.com>
Signed-off-by: default avatarYong Cong Sin <yongcong.sin@gmail.com>
parent 1eeee010
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+3 −1
Original line number Diff line number Diff line
@@ -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)
+0 −1
Original line number Diff line number Diff line
CONFIG_ZTEST=y
CONFIG_RISCV_GP=y
CONFIG_TEST_USERSPACE=y
+42 −2
Original line number Diff line number Diff line
@@ -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);

	/* 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");
}

+9 −2
Original line number Diff line number Diff line
@@ -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