Skip to content

Commit

Permalink
arch: riscv: core: run zephyr completely in user/supervisor mode
Browse files Browse the repository at this point in the history
Before that fix, zephyr was able to start only in machine mode.
With that fix, zephyr can start (as guest) in user or supervisor mode.
Defined new board type qemu_riscv32/qemu_virt_riscv32/opensbi
Drivers for running zephyr in supervisor with qemu included.
Fixes zephyrproject-rtos#68133

Signed-off-by: Sven Ginka <s.ginka@sensry.de>
  • Loading branch information
tswaehn committed Aug 22, 2024
1 parent 34206f5 commit 0f77fd7
Show file tree
Hide file tree
Showing 39 changed files with 1,044 additions and 56 deletions.
19 changes: 19 additions & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,25 @@ config RISCV_GENERIC_TOOLCHAIN
Allow SOCs that have custom extended riscv ISA to still
compile with generic riscv32 toolchain.

config RISCV_KERNEL_IN_USER_MODE
bool "Start zephyr in user mode"
help
Replaces CSR access from machine mode to user mode.
Allows zephyr to run as guest in user mode only

config RISCV_KERNEL_IN_SUPERVISOR_MODE
bool "Start zephyr in supervisor mode"
help
Replaces CSR access from machine mode to supervisor mode.
Allows zephyr to run as guest in supervisor mode only

config RISCV_KERNEL_IN_MACHINE_MODE
bool "Start zephyr in supervisor mode"
default y if (!RISCV_KERNEL_IN_SUPERVISOR_MODE) && (!RISCV_KERNEL_IN_USER_MODE)
help
Presets CSR access to machine mode registers.
Allows zephyr to run in machine mode (default for riscv).

config GEN_ISR_TABLES
default y

Expand Down
2 changes: 1 addition & 1 deletion arch/riscv/core/cpu_idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ void arch_cpu_idle(void)
{
sys_trace_idle();
__asm__ volatile("wfi");
irq_unlock(MSTATUS_IEN);
irq_unlock(XSTATUS_IEN);
}
#endif

Expand Down
8 changes: 4 additions & 4 deletions arch/riscv/core/fatal.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ FUNC_NORETURN void z_riscv_fatal_error_csf(unsigned int reason, const struct arc
#endif /* CONFIG_RISCV_ISA_RV32E */
LOG_ERR(" sp: " PR_REG, z_riscv_get_sp_before_exc(esf));
LOG_ERR(" ra: " PR_REG, esf->ra);
LOG_ERR(" mepc: " PR_REG, esf->mepc);
LOG_ERR("mstatus: " PR_REG, esf->mstatus);
LOG_ERR(" xepc: " PR_REG, esf->xepc);
LOG_ERR("xstatus: " PR_REG, esf->xstatus);
LOG_ERR("");
}

Expand Down Expand Up @@ -209,11 +209,11 @@ void _Fault(struct arch_esf *esf)

unsigned long mcause;

__asm__ volatile("csrr %0, mcause" : "=r" (mcause));
__asm__ volatile("csrr %0," STRINGIFY(xcause) : "=r" (mcause));

#ifndef CONFIG_SOC_OPENISA_RV32M1
unsigned long mtval;
__asm__ volatile("csrr %0, mtval" : "=r" (mtval));
__asm__ volatile("csrr %0," STRINGIFY(xtval) : "=r" (mtval));
#endif

mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK;
Expand Down
8 changes: 4 additions & 4 deletions arch/riscv/core/irq_manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);

FUNC_NORETURN void z_irq_spurious(const void *unused)
{
unsigned long mcause;
unsigned long xcause;

ARG_UNUSED(unused);

mcause = csr_read(mcause);
xcause = csr_read(xcause);

mcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK;
xcause &= CONFIG_RISCV_MCAUSE_EXCEPTION_MASK;

LOG_ERR("Spurious interrupt detected! IRQ: %ld", mcause);
LOG_ERR("Spurious interrupt detected! IRQ: %ld", xcause);
#if defined(CONFIG_RISCV_HAS_PLIC)
if (mcause == RISCV_IRQ_MEXT) {
unsigned int save_irq = riscv_plic_get_irq();
Expand Down
35 changes: 18 additions & 17 deletions arch/riscv/core/isr.S
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright (c) 2016 Jean-Paul Etienne <fractalclone@gmail.com>
* Copyright (c) 2018 Foundries.io Ltd
* Copyright (c) 2020 BayLibre, SAS
* Copyright (c) 2024 sensry.io
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -189,12 +190,12 @@ SECTION_FUNC(exception.entry, _isr_wrapper)
get_current_cpu s0

/* Save MEPC register */
csrr t0, mepc
sr t0, __struct_arch_esf_mepc_OFFSET(sp)
csrr t0, xepc
sr t0, __struct_arch_esf_xepc_OFFSET(sp)

/* Save MSTATUS register */
csrr t2, mstatus
sr t2, __struct_arch_esf_mstatus_OFFSET(sp)
csrr t2, xstatus
sr t2, __struct_arch_esf_xstatus_OFFSET(sp)

#if defined(CONFIG_FPU_SHARING)
/* determine if FPU access was disabled */
Expand Down Expand Up @@ -319,7 +320,7 @@ no_fp: /* increment _current->arch.exception_depth */
jal ra, __soc_is_irq
bnez a0, is_interrupt
#else
csrr t0, mcause
csrr t0, xcause
srli t0, t0, RISCV_MCAUSE_IRQ_POS
bnez t0, is_interrupt
#endif
Expand All @@ -329,7 +330,7 @@ no_fp: /* increment _current->arch.exception_depth */
* perform a context-switch or an IRQ offload. Otherwise call _Fault
* to report the exception.
*/
csrr t0, mcause
csrr t0, xcause
li t2, CONFIG_RISCV_MCAUSE_EXCEPTION_MASK
and t0, t0, t2

Expand Down Expand Up @@ -385,9 +386,9 @@ is_kernel_syscall:
* It's safe to always increment by 4, even with compressed
* instructions, because the ecall instruction is always 4 bytes.
*/
lr t0, __struct_arch_esf_mepc_OFFSET(sp)
lr t0, __struct_arch_esf_xepc_OFFSET(sp)
addi t0, t0, 4
sr t0, __struct_arch_esf_mepc_OFFSET(sp)
sr t0, __struct_arch_esf_xepc_OFFSET(sp)

#ifdef CONFIG_PMP_STACK_GUARD
/* Re-activate PMP for m-mode */
Expand Down Expand Up @@ -505,9 +506,9 @@ is_user_syscall:
* Same as for is_kernel_syscall: increment saved MEPC by 4 to
* prevent triggering the same ecall again upon exiting the ISR.
*/
lr t1, __struct_arch_esf_mepc_OFFSET(sp)
lr t1, __struct_arch_esf_xepc_OFFSET(sp)
addi t1, t1, 4
sr t1, __struct_arch_esf_mepc_OFFSET(sp)
sr t1, __struct_arch_esf_xepc_OFFSET(sp)

/* Restore argument registers from user stack */
lr a0, __struct_arch_esf_a0_OFFSET(sp)
Expand Down Expand Up @@ -565,7 +566,7 @@ is_interrupt:
* If we came from userspace then we need to reconfigure the
* PMP for kernel mode stack guard.
*/
lr t0, __struct_arch_esf_mstatus_OFFSET(sp)
lr t0, __struct_arch_esf_xstatus_OFFSET(sp)
li t1, MSTATUS_MPP
and t0, t0, t1
bnez t0, 1f
Expand Down Expand Up @@ -609,7 +610,7 @@ on_irq_stack:
#endif

/* Get IRQ causing interrupt */
csrr a0, mcause
csrr a0, xcause
li t0, CONFIG_RISCV_MCAUSE_EXCEPTION_MASK
and a0, a0, t0

Expand Down Expand Up @@ -714,10 +715,10 @@ fp_trap_exit:
#endif

/* Restore MEPC and MSTATUS registers */
lr t0, __struct_arch_esf_mepc_OFFSET(sp)
lr t2, __struct_arch_esf_mstatus_OFFSET(sp)
csrw mepc, t0
csrw mstatus, t2
lr t0, __struct_arch_esf_xepc_OFFSET(sp)
lr t2, __struct_arch_esf_xstatus_OFFSET(sp)
csrw xepc, t0
csrw xstatus, t2

#ifdef CONFIG_USERSPACE
/*
Expand Down Expand Up @@ -775,4 +776,4 @@ fp_trap_exit:

#endif /* CONFIG_RISCV_SOC_HAS_ISR_STACKING */

mret
xret
6 changes: 3 additions & 3 deletions arch/riscv/core/offsets/offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
* structures.
*/

#include <zephyr/arch/exception.h>
#include <zephyr/kernel.h>
#include <kernel_arch_data.h>
#include <zephyr/arch/exception.h>
#include <gen_offset.h>

#ifdef CONFIG_RISCV_SOC_CONTEXT_SAVE
Expand Down Expand Up @@ -109,8 +109,8 @@ GEN_OFFSET_STRUCT(arch_esf, a6);
GEN_OFFSET_STRUCT(arch_esf, a7);
#endif /* !CONFIG_RISCV_ISA_RV32E */

GEN_OFFSET_STRUCT(arch_esf, mepc);
GEN_OFFSET_STRUCT(arch_esf, mstatus);
GEN_OFFSET_STRUCT(arch_esf, xepc);
GEN_OFFSET_STRUCT(arch_esf, xstatus);

GEN_OFFSET_STRUCT(arch_esf, s0);

Expand Down
6 changes: 5 additions & 1 deletion arch/riscv/core/reset.S
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ SECTION_FUNC(reset, __reset)
* the C domain
*/
SECTION_FUNC(TEXT, __initialize)
csrr a0, mhartid
#ifdef CONFIG_RISCV_HAS_HART_ID
csrr a0, xhartid
#else
li a0, CONFIG_RV_BOOT_HART
#endif
li t0, CONFIG_RV_BOOT_HART
beq a0, t0, boot_first_core
j boot_secondary_core
Expand Down
2 changes: 1 addition & 1 deletion arch/riscv/core/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ static void walk_stackframe(stack_trace_callback_fn cb, void *cookie, const stru
if (esf != NULL) {
/* Unwind the provided exception stack frame */
sp = z_riscv_get_sp_before_exc(esf);
ra = esf->mepc;
ra = esf->xepc;
} else if ((csf == NULL) || (csf == &_current->callee_saved)) {
/* Unwind current thread (default case when nothing is provided ) */
sp = current_stack_pointer;
Expand Down
6 changes: 3 additions & 3 deletions arch/riscv/core/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
* counter will be restored following the MEPC value set within the
* thread stack.
*/
stack_init->mstatus = MSTATUS_DEF_RESTORE;
stack_init->xstatus = XSTATUS_DEF_RESTORE;

#if defined(CONFIG_FPU_SHARING)
/* thread birth happens through the exception return path */
Expand All @@ -83,11 +83,11 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
if (IS_ENABLED(CONFIG_USERSPACE)
&& (thread->base.user_options & K_USER)) {
/* User thread */
stack_init->mepc = (unsigned long)k_thread_user_mode_enter;
stack_init->xepc = (unsigned long)k_thread_user_mode_enter;

} else {
/* Supervisor thread */
stack_init->mepc = (unsigned long)z_thread_entry;
stack_init->xepc = (unsigned long)z_thread_entry;

#if defined(CONFIG_PMP_STACK_GUARD)
/* Enable PMP in mstatus.MPRV mode for RISC-V machine mode
Expand Down
1 change: 1 addition & 0 deletions boards/qemu/riscv32/board.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ board:
- name: qemu_virt_riscv32
variants:
- name: smp
- name: opensbi
40 changes: 40 additions & 0 deletions boards/qemu/riscv32/qemu_riscv32_qemu_virt_riscv32_opensbi.dts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2024 sensry.io
*
* SPDX-License-Identifier: Apache-2.0
*/

/dts-v1/;

#include <qemu/virt-riscv32.dtsi>

/ {
console0: console {
compatible = "opensbi,console-uart";
foo = "abc";
status = "okay";
};

chosen {
zephyr,console = &console0;
zephyr,shell-uart = &console0;
zephyr,sram = &ram0;
};
};

&ram0 {
device_type = "memory";
reg = < 0x80400000 0x100000 >;
};

&uart0 {
status = "disabled";
};

&plic {
status = "disabled";
};

&clint{
status = "disabled";
};
15 changes: 15 additions & 0 deletions boards/qemu/riscv32/qemu_riscv32_qemu_virt_riscv32_opensbi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
identifier: qemu_riscv32/qemu_virt_riscv32/opensbi
name: QEMU Emulation for RISC-V 32-bit openSBI
type: qemu
simulation: qemu
arch: riscv
toolchain:
- zephyr
- xtools
supported:
- netif
testing:
default: true
ignore_tags:
- net
- bluetooth
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright (c) 2024 sensry.io
# SPDX-License-Identifier: Apache-2.0

CONFIG_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y
CONFIG_STACK_SENTINEL=y
CONFIG_XIP=n
CONFIG_RISCV_PMP=y
CONFIG_SMP=y
CONFIG_MP_MAX_NUM_CPUS=1
CONFIG_IDLE_STACK_SIZE=1024
CONFIG_QEMU_ICOUNT=n

# enable the openSBI support, requires a compiled version of openSBI binary in machine mode
CONFIG_RISCV_OPENSBI=y

# we run zephyr in supervisor mode
CONFIG_RISCV_KERNEL_IN_SUPERVISOR_MODE=y
CONFIG_RISCV_MACHINE_TIMER=n

# options that have to be disabled by now
CONFIG_USERSPACE=n
CONFIG_RISCV_HAS_HART_ID=n
CONFIG_SMP=n
CONFIG_RISCV_PMP=n

# build output for qemu
CONFIG_BUILD_OUTPUT_BIN=y


CONFIG_THREAD_MONITOR=n
1 change: 1 addition & 0 deletions drivers/serial/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_RZT2M uart_rzt2m.c)
zephyr_library_sources_ifdef(CONFIG_UART_RA8_SCI_B uart_renesas_ra8_sci_b.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE uart_handlers.c)
zephyr_library_sources_ifdef(CONFIG_UART_SCI_RA uart_renesas_ra_sci.c)
zephyr_library_sources_ifdef(CONFIG_UART_OPENSBI_CONSOLE uart_opensbi_console.c)

if(CONFIG_UART_NATIVE_POSIX)
zephyr_library_compile_definitions(NO_POSIX_CHEATS)
Expand Down
2 changes: 2 additions & 0 deletions drivers/serial/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -280,4 +280,6 @@ rsource "Kconfig.rzt2m"

rsource "Kconfig.renesas_ra8"

rsource "Kconfig.opensbi_console"

endif # SERIAL
17 changes: 17 additions & 0 deletions drivers/serial/Kconfig.opensbi_console
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# openSBI Console UART driver configuration options

# Copyright (c) 2024 sensry.io
# SPDX-License-Identifier: Apache-2.0


if RISCV_OPENSBI

config UART_OPENSBI_CONSOLE
bool "openSBI console serial driver"
default y
select SERIAL_HAS_DRIVER
help
This option enables the console driver for openSBI based RISCV family of
processors.

endif # RISCV_OPENSBI
Loading

0 comments on commit 0f77fd7

Please sign in to comment.