feat: riscv64 linux support

This commit is contained in:
kingfish404 2024-07-14 16:43:25 +08:00 committed by Zihao Yu
parent 0e37b47498
commit a7b830fedd
5 changed files with 52 additions and 29 deletions

View file

@ -11,8 +11,10 @@ struct Context {
uintptr_t ksp;
void *vm_head;
ucontext_t uc;
#ifdef __x86_64__
// skip the red zone of the stack frame, see the amd64 ABI manual for details
uint8_t redzone[128];
#endif
};
#ifdef __x86_64__
@ -21,12 +23,21 @@ struct Context {
#define GPR3 uc.uc_mcontext.gregs[REG_RDX]
#define GPR4 uc.uc_mcontext.gregs[REG_RCX]
#define GPRx uc.uc_mcontext.gregs[REG_RAX]
#elif __aarch64__
#elif defined(__aarch64__)
#define GPR1 uc.uc_mcontext.regs[0]
#define GPR2 uc.uc_mcontext.regs[1]
#define GPR3 uc.uc_mcontext.regs[2]
#define GPR4 uc.uc_mcontext.regs[3]
#define GPRx uc.uc_mcontext.regs[0]
#elif defined(__riscv)
// FIXME: may be wrong
#define GPR1 uc.uc_mcontext.__gregs[REG_A0]
#define GPR2 uc.uc_mcontext.__gregs[REG_A0+1]
#define GPR3 uc.uc_mcontext.__gregs[REG_A0+2]
#define GPR4 uc.uc_mcontext.__gregs[REG_A0+3]
#define GPRx uc.uc_mcontext.__gregs[REG_A0+4]
#else
#error Unsupported architecture
#endif
#undef __USE_GNU

View file

@ -21,7 +21,7 @@ static void irq_handle(Context *c) {
if (thiscpu->ev.event == EVENT_ERROR) {
printf("Unhandle signal '%s' at pc = %p, badaddr = %p, cause = 0x%x\n",
thiscpu->ev.msg, REG_PC(&c->uc), thiscpu->ev.ref, thiscpu->ev.cause);
thiscpu->ev.msg, AM_REG_PC(&c->uc), thiscpu->ev.ref, thiscpu->ev.cause);
assert(0);
}
c = user_handler(thiscpu->ev, c);
@ -36,13 +36,14 @@ static void irq_handle(Context *c) {
}
static void setup_stack(uintptr_t event, ucontext_t *uc) {
void *rip = (void *)REG_PC(uc);
void *pc = (void *)AM_REG_PC(uc);
extern uint8_t _start, _etext;
int trap_from_user = __am_in_userspace(rip);
int signal_safe = IN_RANGE(rip, RANGE(&_start, &_etext)) || trap_from_user ||
int trap_from_user = __am_in_userspace(pc);
int signal_safe = IN_RANGE(pc, RANGE(&_start, &_etext)) || trap_from_user ||
// Hack here: "+13" points to the instruction after syscall. This is the
// instruction which will trigger the pending signal if interrupt is enabled.
(rip == (void *)&sigprocmask + 13);
// FIXME: should change 13 for aarch and riscv
(pc == (void *)&sigprocmask + 13);
if (((event == EVENT_IRQ_IODEV) || (event == EVENT_IRQ_TIMER)) && !signal_safe) {
// Shared libraries contain code which are not reenterable.
@ -58,17 +59,17 @@ static void setup_stack(uintptr_t event, ucontext_t *uc) {
if (trap_from_user) __am_pmem_unprotect();
// skip the instructions causing SIGSEGV for syscall
if (event == EVENT_SYSCALL) { rip += SYSCALL_INSTR_LEN; }
REG_PC(uc) = (uintptr_t)rip;
if (event == EVENT_SYSCALL) { pc += SYSCALL_INSTR_LEN; }
AM_REG_PC(uc) = (uintptr_t)pc;
// switch to kernel stack if we were previously in user space
uintptr_t rsp = trap_from_user ? thiscpu->ksp : REG_SP(uc);
rsp -= sizeof(Context);
uintptr_t sp = trap_from_user ? thiscpu->ksp : AM_REG_SP(uc);
sp -= sizeof(Context);
#ifdef __x86_64__
// keep (rsp + 8) % 16 == 0 to support SSE
if ((rsp + 8) % 16 != 0) rsp -= 8;
// keep (sp + 8) % 16 == 0 to support SSE
if ((sp + 8) % 16 != 0) sp -= 8;
#endif
Context *c = (void *)rsp;
Context *c = (void *)sp;
// save the context on the stack
c->uc = *uc;
@ -77,17 +78,17 @@ static void setup_stack(uintptr_t event, ucontext_t *uc) {
__am_get_intr_sigmask(&uc->uc_sigmask);
// call irq_handle after returning from the signal handler
REG_GPR1(uc) = (uintptr_t)c;
REG_PC(uc) = (uintptr_t)irq_handle;
REG_SP(uc) = (uintptr_t)c;
AM_REG_GPR1(uc) = (uintptr_t)c;
AM_REG_PC(uc) = (uintptr_t)irq_handle;
AM_REG_SP(uc) = (uintptr_t)c;
}
static void iret(ucontext_t *uc) {
Context *c = (void *)REG_GPR1(uc);
Context *c = (void *)AM_REG_GPR1(uc);
// restore the context
*uc = c->uc;
thiscpu->ksp = c->ksp;
if (__am_in_userspace((void *)REG_PC(uc))) __am_pmem_protect();
if (__am_in_userspace((void *)AM_REG_PC(uc))) __am_pmem_protect();
}
static void sig_handler(int sig, siginfo_t *info, void *ucontext) {
@ -168,8 +169,8 @@ Context* kcontext(Area kstack, void (*entry)(void *), void *arg) {
Context *c = (Context*)kstack.end - 1;
__am_get_example_uc(c);
REG_PC(&c->uc) = (uintptr_t)__am_kcontext_start;
REG_SP(&c->uc) = (uintptr_t)kstack.end;
AM_REG_PC(&c->uc) = (uintptr_t)__am_kcontext_start;
AM_REG_SP(&c->uc) = (uintptr_t)kstack.end;
int ret = sigemptyset(&(c->uc.uc_sigmask)); // enable interrupt
assert(ret == 0);

View file

@ -8,13 +8,17 @@
#include <klib-macros.h>
#ifdef __x86_64__
#define REG_PC(uc) (uc)->uc_mcontext.gregs[REG_RIP]
#define REG_SP(uc) (uc)->uc_mcontext.gregs[REG_RSP]
#define REG_GPR1(uc) (uc)->uc_mcontext.gregs[REG_RDI]
#elif __aarch64__
#define REG_PC(uc) (uc)->uc_mcontext.pc
#define REG_SP(uc) (uc)->uc_mcontext.sp
#define REG_GPR1(uc) (uc)->uc_mcontext.regs[0]
#define AM_REG_PC(uc) (uc)->uc_mcontext.gregs[REG_RIP]
#define AM_REG_SP(uc) (uc)->uc_mcontext.gregs[REG_RSP]
#define AM_REG_GPR1(uc) (uc)->uc_mcontext.gregs[REG_RDI]
#elif defined(__aarch64__)
#define AM_REG_PC(uc) (uc)->uc_mcontext.pc
#define AM_REG_SP(uc) (uc)->uc_mcontext.sp
#define AM_REG_GPR1(uc) (uc)->uc_mcontext.regs[0]
#elif defined(__riscv) && __riscv_xlen == 64
#define AM_REG_PC(uc) (uc)->uc_mcontext.__gregs[REG_PC]
#define AM_REG_SP(uc) (uc)->uc_mcontext.__gregs[REG_SP]
#define AM_REG_GPR1(uc) (uc)->uc_mcontext.__gregs[REG_A0]
#else
#error Unsupported architecture
#endif

View file

@ -19,4 +19,11 @@ __am_kcontext_start:
and sp, x2, #0xfffffffffffffff0
br x1
bl __am_panic_on_return
#elif __riscv
// See riscv ABI manual for more details
// https://github.com/riscv-non-isa/riscv-elf-psabi-doc
addi sp, sp, -16
andi sp, sp, ~15
jalr a1
jal __am_panic_on_return
#endif

View file

@ -124,8 +124,8 @@ Context* ucontext(AddrSpace *as, Area kstack, void *entry) {
Context *c = (Context*)kstack.end - 1;
__am_get_example_uc(c);
REG_PC(&c->uc) = (uintptr_t)entry;
REG_SP(&c->uc) = (uintptr_t)USER_SPACE.end;
AM_REG_PC(&c->uc) = (uintptr_t)entry;
AM_REG_SP(&c->uc) = (uintptr_t)USER_SPACE.end;
int ret = sigemptyset(&(c->uc.uc_sigmask)); // enable interrupt
assert(ret == 0);