[arch][riscv] move the iframe definitions into a separate header and add syscall support

This commit is contained in:
Travis Geiselbrecht
2021-04-11 03:38:03 -07:00
parent 38fa93cbbf
commit 1772e7e890
3 changed files with 142 additions and 90 deletions

View File

@@ -8,6 +8,7 @@
#include <lk/asm.h>
#include <arch/riscv.h>
#include <arch/riscv/asm.h>
#include <arch/riscv/iframe.h>
/* void riscv_context_switch(
struct riscv_context_switch_frame *oldcs,
@@ -49,17 +50,17 @@ FUNCTION(riscv_context_switch)
END_FUNCTION(riscv_context_switch)
.macro save_regs, user
addi sp, sp, -REGOFF(24) // subtract a multiple of 16 to align the stack in 32bit
addi sp, sp, -RISCV_IFRAME_LEN // subtract a multiple of 16 to align the stack in 32bit
.if \user == 1
// recover tp from the top of the stack (we saved it here before)
STR tp, REGOFF(18)(sp)
LDR tp, REGOFF(23)(sp) // this is where the top of the stack used to be
STR tp, RISCV_IFRAME_TP(sp)
LDR tp, (RISCV_IFRAME_LEN-__riscv_xlen / 8)(sp) // this is where the top of the stack used to be
STR gp, REGOFF(19)(sp)
STR gp, RISCV_IFRAME_GP(sp)
// save the user stack and zero scratch register
csrrw gp, RISCV_CSR_XSCRATCH, zero
STR gp, REGOFF(20)(sp)
STR gp, RISCV_IFRAME_SP(sp)
// recover gp for the kernel
.option push
@@ -67,27 +68,27 @@ END_FUNCTION(riscv_context_switch)
lla gp, __global_pointer$
.option pop
.endif
STR t6, REGOFF(17)(sp)
STR t5, REGOFF(16)(sp)
STR t4, REGOFF(15)(sp)
STR t3, REGOFF(14)(sp)
STR t2, REGOFF(13)(sp)
STR t1, REGOFF(12)(sp)
STR t0, REGOFF(11)(sp)
STR a7, REGOFF(10)(sp)
STR a6, REGOFF(9)(sp)
STR a5, REGOFF(8)(sp)
STR a4, REGOFF(7)(sp)
STR a3, REGOFF(6)(sp)
STR a2, REGOFF(5)(sp)
STR a1, REGOFF(4)(sp)
STR a0, REGOFF(3)(sp)
STR ra, REGOFF(2)(sp)
STR t6, RISCV_IFRAME_T(6)(sp)
STR t5, RISCV_IFRAME_T(5)(sp)
STR t4, RISCV_IFRAME_T(4)(sp)
STR t3, RISCV_IFRAME_T(3)(sp)
STR t2, RISCV_IFRAME_T(2)(sp)
STR t1, RISCV_IFRAME_T(1)(sp)
STR t0, RISCV_IFRAME_T(0)(sp)
STR a7, RISCV_IFRAME_A(7)(sp)
STR a6, RISCV_IFRAME_A(6)(sp)
STR a5, RISCV_IFRAME_A(5)(sp)
STR a4, RISCV_IFRAME_A(4)(sp)
STR a3, RISCV_IFRAME_A(3)(sp)
STR a2, RISCV_IFRAME_A(2)(sp)
STR a1, RISCV_IFRAME_A(1)(sp)
STR a0, RISCV_IFRAME_A(0)(sp)
STR ra, RISCV_IFRAME_RA(sp)
csrr t0, RISCV_CSR_XSTATUS
STR t0, REGOFF(1)(sp)
STR t0, RISCV_IFRAME_STATUS(sp)
csrr a0, RISCV_CSR_XCAUSE
csrr a1, RISCV_CSR_XEPC
STR a1, REGOFF(0)(sp)
STR a1, RISCV_IFRAME_EPC(sp)
mv a2, sp
// args are set up for a call into riscv_exception_handler()
// a0 = xcause
@@ -97,63 +98,63 @@ END_FUNCTION(riscv_context_switch)
.macro restore_regs, user
// put everything back
LDR t0, REGOFF(0)(sp)
LDR t0, RISCV_IFRAME_EPC(sp)
csrw RISCV_CSR_XEPC, t0
LDR t0, REGOFF(1)(sp)
LDR t0, RISCV_IFRAME_STATUS(sp)
csrw RISCV_CSR_XSTATUS, t0
LDR ra, REGOFF(2)(sp)
LDR a0, REGOFF(3)(sp)
LDR a1, REGOFF(4)(sp)
LDR a2, REGOFF(5)(sp)
LDR a3, REGOFF(6)(sp)
LDR a4, REGOFF(7)(sp)
LDR a5, REGOFF(8)(sp)
LDR a6, REGOFF(9)(sp)
LDR a7, REGOFF(10)(sp)
LDR t0, REGOFF(11)(sp)
LDR t1, REGOFF(12)(sp)
LDR t2, REGOFF(13)(sp)
LDR t3, REGOFF(14)(sp)
LDR t4, REGOFF(15)(sp)
LDR t5, REGOFF(16)(sp)
LDR t6, REGOFF(17)(sp)
LDR ra, RISCV_IFRAME_RA(sp)
LDR a0, RISCV_IFRAME_A(0)(sp)
LDR a1, RISCV_IFRAME_A(1)(sp)
LDR a2, RISCV_IFRAME_A(2)(sp)
LDR a3, RISCV_IFRAME_A(3)(sp)
LDR a4, RISCV_IFRAME_A(4)(sp)
LDR a5, RISCV_IFRAME_A(5)(sp)
LDR a6, RISCV_IFRAME_A(6)(sp)
LDR a7, RISCV_IFRAME_A(7)(sp)
LDR t0, RISCV_IFRAME_T(0)(sp)
LDR t1, RISCV_IFRAME_T(1)(sp)
LDR t2, RISCV_IFRAME_T(2)(sp)
LDR t3, RISCV_IFRAME_T(3)(sp)
LDR t4, RISCV_IFRAME_T(4)(sp)
LDR t5, RISCV_IFRAME_T(5)(sp)
LDR t6, RISCV_IFRAME_T(6)(sp)
.if \user == 1
// before we run out of registers, save tp to the top of the kernel stack
// and put the kernel stack in the scratch register
addi gp, sp, REGOFF(24)
addi gp, sp, RISCV_IFRAME_LEN
STR tp, REGOFF(-1)(gp)
csrw RISCV_CSR_XSCRATCH, sp
csrw RISCV_CSR_XSCRATCH, gp
LDR tp, REGOFF(18)(sp)
LDR gp, REGOFF(19)(sp)
LDR sp, REGOFF(20)(sp)
LDR tp, RISCV_IFRAME_TP(sp)
LDR gp, RISCV_IFRAME_GP(sp)
LDR sp, RISCV_IFRAME_SP(sp)
.else
addi sp, sp, REGOFF(24)
addi sp, sp, RISCV_IFRAME_LEN
.endif
.endm
/* top level exception handler for riscv in non vectored mode */
// top level exception handler for riscv in non vectored mode
.balign 4
FUNCTION(riscv_exception_entry)
/* check to see if we came from user space */
// check to see if we came from user space
csrrw sp, RISCV_CSR_XSCRATCH, sp
bnez sp, 1f
/* put the stack back */
// put the stack back
csrrw sp, RISCV_CSR_XSCRATCH, sp
j kernel_exception_entry
1:
/* came from user space */
// came from user space
j user_exception_entry
END_FUNCTION(riscv_exception_entry)
LOCAL_FUNCTION(kernel_exception_entry)
/* we came from kernel space so tp and gp are okay */
// we came from kernel space so tp and gp are okay
save_regs 0
/* bool kernel = true */
// bool kernel = true
li a3, 1
jal riscv_exception_handler
@@ -163,10 +164,10 @@ LOCAL_FUNCTION(kernel_exception_entry)
END_FUNCTION(kernel_exception_entry)
LOCAL_FUNCTION(user_exception_entry)
/* we came from user space, assume gp and tp have been trashed */
// we came from user space, assume gp and tp have been trashed
save_regs 1
/* bool kernel = false */
// bool kernel = false
li a3, 0
jal riscv_exception_handler

View File

@@ -11,37 +11,10 @@
#include <arch/riscv.h>
#include <kernel/thread.h>
#include <platform.h>
#include <arch/riscv/iframe.h>
#define LOCAL_TRACE 0
// keep in sync with asm.S
struct riscv_short_iframe {
ulong epc;
ulong status;
ulong ra;
ulong a0;
ulong a1;
ulong a2;
ulong a3;
ulong a4;
ulong a5;
ulong a6;
ulong a7;
ulong t0;
ulong t1;
ulong t2;
ulong t3;
ulong t4;
ulong t5;
ulong t6;
// if we came from user space these are valid
ulong tp;
ulong gp;
ulong sp;
ulong pad[3];
};
static_assert(sizeof(struct riscv_short_iframe) % 16 == 0, "");
extern enum handler_return riscv_platform_irq(void);
extern enum handler_return riscv_software_exception(void);
@@ -79,6 +52,16 @@ static const char *cause_to_string(long cause) {
return "Unknown";
}
static void dump_iframe(struct riscv_short_iframe *frame, bool kernel) {
printf("a0 %#16lx a1 %#16lx a2 %#16lx a3 %#16lx\n", frame->a0, frame->a1, frame->a2, frame->a3);
printf("a4 %#16lx a5 %#16lx a6 %#16lx a7 %#16lx\n", frame->a4, frame->a5, frame->a6, frame->a7);
printf("t0 %#16lx t1 %#16lx t2 %#16lx t3 %#16lx\n", frame->t0, frame->t1, frame->t2, frame->t3);
printf("t5 %#16lx t6 %#16lx\n", frame->t5, frame->t6);
if (!kernel) {
printf("gp %#16lx tp %#16lx sp %#lx\n", frame->gp, frame->tp, frame->sp);
}
}
__NO_RETURN __NO_INLINE
static void fatal_exception(long cause, ulong epc, struct riscv_short_iframe *frame, bool kernel) {
if (cause < 0) {
@@ -89,14 +72,15 @@ static void fatal_exception(long cause, ulong epc, struct riscv_short_iframe *fr
cause_to_string(cause), epc, riscv_csr_read(RISCV_CSR_XTVAL));
}
printf("a0 %#16lx a1 %#16lx a2 %#16lx a3 %#16lx\n", frame->a0, frame->a1, frame->a2, frame->a3);
printf("a4 %#16lx a5 %#16lx a6 %#16lx a7 %#16lx\n", frame->a4, frame->a5, frame->a6, frame->a7);
printf("t0 %#16lx t1 %#16lx t2 %#16lx t3 %#16lx\n", frame->t0, frame->t1, frame->t2, frame->t3);
printf("t5 %#16lx t6 %#16lx\n", frame->t5, frame->t6);
if (!kernel) {
printf("gp %#16lx tp %#16lx sp %#lx\n", frame->gp, frame->tp, frame->sp);
}
dump_iframe(frame, kernel);
platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC);
}
// weak reference, can override this somewhere else
__WEAK
void riscv_syscall_handler(struct riscv_short_iframe *frame) {
printf("unhandled syscall handler\n");
dump_iframe(frame, false);
platform_halt(HALT_ACTION_HALT, HALT_REASON_SW_PANIC);
}
@@ -126,6 +110,9 @@ void riscv_exception_handler(long cause, ulong epc, struct riscv_short_iframe *f
} else {
// all synchronous traps go here
switch (cause) {
case RISCV_EXCEPTION_ENV_CALL_U_MODE: // ecall from user mode
riscv_syscall_handler(frame);
break;
default:
fatal_exception(cause, epc, frame, kernel);
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2021 Travis Geiselbrecht
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT
*/
#pragma once
#define RISCV_IFRAME_EPC (0 * __riscv_xlen / 8)
#define RISCV_IFRAME_STATUS (1 * __riscv_xlen / 8)
#define RISCV_IFRAME_RA (2 * __riscv_xlen / 8)
#define RISCV_IFRAME_A_BASE (3 * __riscv_xlen / 8)
#define RISCV_IFRAME_A(n) (RISCV_IFRAME_A_BASE + (n) * __riscv_xlen / 8)
#define RISCV_IFRAME_T_BASE (11 * __riscv_xlen / 8)
#define RISCV_IFRAME_T(n) (RISCV_IFRAME_T_BASE + (n) * __riscv_xlen / 8)
#define RISCV_IFRAME_TP (18 * __riscv_xlen / 8)
#define RISCV_IFRAME_GP (19 * __riscv_xlen / 8)
#define RISCV_IFRAME_SP (20 * __riscv_xlen / 8)
#define RISCV_IFRAME_LEN (24 * __riscv_xlen / 8)
#ifndef ASSEMBLY
// keep in sync with asm.S
struct riscv_short_iframe {
unsigned long epc;
unsigned long status;
unsigned long ra;
unsigned long a0;
unsigned long a1;
unsigned long a2;
unsigned long a3;
unsigned long a4;
unsigned long a5;
unsigned long a6;
unsigned long a7;
unsigned long t0;
unsigned long t1;
unsigned long t2;
unsigned long t3;
unsigned long t4;
unsigned long t5;
unsigned long t6;
// if we came from user space these are valid
unsigned long tp;
unsigned long gp;
unsigned long sp;
unsigned long pad[3]; // always maintain a padding of a multiple of 16 bytes
};
static_assert(sizeof(struct riscv_short_iframe) % 16 == 0, "");
static_assert(sizeof(struct riscv_short_iframe) == RISCV_IFRAME_LEN, "");
static_assert(offsetof(struct riscv_short_iframe, epc) == RISCV_IFRAME_EPC, "");
static_assert(offsetof(struct riscv_short_iframe, status) == RISCV_IFRAME_STATUS, "");
static_assert(offsetof(struct riscv_short_iframe, ra) == RISCV_IFRAME_RA, "");
static_assert(offsetof(struct riscv_short_iframe, a0) == RISCV_IFRAME_A_BASE, "");
static_assert(offsetof(struct riscv_short_iframe, t0) == RISCV_IFRAME_T_BASE, "");
static_assert(offsetof(struct riscv_short_iframe, gp) == RISCV_IFRAME_GP, "");
static_assert(offsetof(struct riscv_short_iframe, sp) == RISCV_IFRAME_SP, "");
#endif // __ASSEMBLY__