diff --git a/arch/riscv/core/isr.S b/arch/riscv/core/isr.S index 65c40e63456e15..5ac71fe17b4734 100644 --- a/arch/riscv/core/isr.S +++ b/arch/riscv/core/isr.S @@ -163,6 +163,14 @@ SECTION_FUNC(exception.entry, _isr_wrapper) lr t0, ___cpu_t_current_OFFSET(s0) lr tp, _thread_offset_to_tls(t0) + /* Make sure global pointer is sane */ +#ifdef CONFIG_RISCV_GP + .option push + .option norelax + la gp, __global_pointer$ + .option pop +#endif /* CONFIG_RISCV_GP */ + /* Clear our per-thread usermode flag */ lui t0, %tprel_hi(is_user_mode) add t0, t0, tp, %tprel_add(is_user_mode) diff --git a/include/zephyr/arch/riscv/reg.h b/include/zephyr/arch/riscv/reg.h new file mode 100644 index 00000000000000..6d3b2d88b1755b --- /dev/null +++ b/include/zephyr/arch/riscv/reg.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_ARCH_RISCV_REG_H_ +#define ZEPHYR_INCLUDE_ZEPHYR_ARCH_RISCV_REG_H_ + +#define reg_read(reg) \ + ({ \ + register unsigned long __rv; \ + __asm__ volatile("mv %0, " STRINGIFY(reg) : "=r"(__rv)); \ + __rv; \ + }) + +#define reg_write(reg, val) ({ __asm__("mv " STRINGIFY(reg) ", %0" : : "r"(val)); }) + +#endif /* ZEPHYR_INCLUDE_ZEPHYR_ARCH_RISCV_REG_H_ */ diff --git a/tests/arch/riscv/userspace/riscv_gp/CMakeLists.txt b/tests/arch/riscv/userspace/riscv_gp/CMakeLists.txt new file mode 100644 index 00000000000000..04987303450f54 --- /dev/null +++ b/tests/arch/riscv/userspace/riscv_gp/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(riscv_gp) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/arch/riscv/userspace/riscv_gp/prj.conf b/tests/arch/riscv/userspace/riscv_gp/prj.conf new file mode 100644 index 00000000000000..1f8e1275be3e24 --- /dev/null +++ b/tests/arch/riscv/userspace/riscv_gp/prj.conf @@ -0,0 +1,3 @@ +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 new file mode 100644 index 00000000000000..76a9ecffc22f7f --- /dev/null +++ b/tests/arch/riscv/userspace/riscv_gp/src/main.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024 Meta Platforms + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#define ROGUE_USER_STACK_SZ 2048 + +static struct k_thread rogue_user_thread; +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()); + + reg_write(gp, 0xbad); + zassert_equal(reg_read(gp), 0xbad); +} + +ZTEST_USER(riscv_gp, test_gp_value) +{ + uintptr_t gp_val = reg_read(gp); + k_tid_t th; + + zassert_not_equal(gp_val, 0); + + 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)); + + zassert_equal(reg_read(gp), gp_val, "`gp` corrupted by user thread"); +} + +static void *userspace_setup(void) +{ + k_thread_access_grant(k_current_get(), &rogue_user_thread, &rogue_user_stack); + + return NULL; +} + +ZTEST_SUITE(riscv_gp, NULL, userspace_setup, NULL, NULL, NULL); diff --git a/tests/arch/riscv/userspace/riscv_gp/testcase.yaml b/tests/arch/riscv/userspace/riscv_gp/testcase.yaml new file mode 100644 index 00000000000000..5b1345abc5475d --- /dev/null +++ b/tests/arch/riscv/userspace/riscv_gp/testcase.yaml @@ -0,0 +1,8 @@ +common: + ignore_faults: true + ignore_qemu_crash: true + tags: kernel riscv + platform_allow: + - qemu_riscv64 +tests: + arch.riscv64.riscv_gp: {}