Re: [Qemu-devel] [PATCH v8 10/23] RISC-V Linux User Emulation
On Thu, Apr 5, 2018 at 12:44 AM, Laurent Vivierwrote: > Le 02/03/2018 à 14:51, Michael Clark a écrit : > > Implementation of linux user emulation for RISC-V. > > > > Reviewed-by: Richard Henderson > > Signed-off-by: Sagar Karandikar > > Signed-off-by: Michael Clark > > --- > > linux-user/elfload.c | 22 +++ > > linux-user/main.c | 99 + > > linux-user/riscv/syscall_nr.h | 287 ++ > > > linux-user/riscv/target_cpu.h | 18 +++ > > linux-user/riscv/target_elf.h | 14 ++ > > linux-user/riscv/target_signal.h | 23 +++ > > linux-user/riscv/target_structs.h | 46 ++ > > linux-user/riscv/target_syscall.h | 56 > > linux-user/riscv/termbits.h | 222 + > > linux-user/signal.c | 203 ++- > > linux-user/syscall.c | 2 + > > linux-user/syscall_defs.h | 13 +- > > target/riscv/cpu_user.h | 13 ++ > > 13 files changed, 1012 insertions(+), 6 deletions(-) > > create mode 100644 linux-user/riscv/syscall_nr.h > > create mode 100644 linux-user/riscv/target_cpu.h > > create mode 100644 linux-user/riscv/target_elf.h > > create mode 100644 linux-user/riscv/target_signal.h > > create mode 100644 linux-user/riscv/target_structs.h > > create mode 100644 linux-user/riscv/target_syscall.h > > create mode 100644 linux-user/riscv/termbits.h > > create mode 100644 target/riscv/cpu_user.h > > > ... > > diff --git a/linux-user/signal.c b/linux-user/signal.c > > index 9a380b9..4d3f244 100644 > > --- a/linux-user/signal.c > > +++ b/linux-user/signal.c > ... > > +static abi_ulong get_sigframe(struct target_sigaction *ka, > > + CPURISCVState *regs, size_t framesize) > > +{ > > +abi_ulong sp = regs->gpr[xSP]; > > +int onsigstack = on_sig_stack(sp); > > + > > +/* redzone */ > > +/* This is the X/Open sanctioned signal stack switching. */ > > +if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) { > > +sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_ > size; > > +} > > + > > +sp -= framesize; > > +sp &= ~3UL; /* align sp on 4-byte boundary */ > > kernel aligns using 0xf. Why do you use a different alignment? Thanks for reviewing this! This looks like a bug! I'm raising this as an issue on the riscv-qemu tracker so that its easier than searching through the mail archive: - https://github.com/riscv/riscv-qemu/issues/129 > + > > +/* If we are on the alternate signal stack and would overflow it, > don't. > > + Return an always-bogus address instead so we will die with > SIGSEGV. */ > > +if (onsigstack && !likely(on_sig_stack(sp))) { > > +return -1L; > > +} > > + > > +return sp; > > +} > Other question why don't you use the same logic as in kernel? > > 1- check for signal stack overflow > 2- check for X/Open sanctioned signal stack switching > > static inline void __user *get_sigframe(struct ksignal *ksig, > struct pt_regs *regs, size_t framesize) > { > unsigned long sp; > /* Default to using normal stack */ > sp = regs->sp; > > /* > * If we are on the alternate signal stack and would overflow > it, don't. > * Return an always-bogus address instead so we will die with > SIGSEGV. > */ > if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) > return (void __user __force *)(-1UL); > > /* This is the X/Open sanctioned signal stack switching. */ > sp = sigsp(sp, ksig) - framesize; > > /* Align the stack frame. */ > sp &= ~0xfUL; > > return (void __user *)sp; > } > > Thanks, > Laurent >
Re: [Qemu-devel] [PATCH v8 10/23] RISC-V Linux User Emulation
Le 02/03/2018 à 14:51, Michael Clark a écrit : > Implementation of linux user emulation for RISC-V. > > Reviewed-by: Richard Henderson> Signed-off-by: Sagar Karandikar > Signed-off-by: Michael Clark > --- > linux-user/elfload.c | 22 +++ > linux-user/main.c | 99 + > linux-user/riscv/syscall_nr.h | 287 > ++ > linux-user/riscv/target_cpu.h | 18 +++ > linux-user/riscv/target_elf.h | 14 ++ > linux-user/riscv/target_signal.h | 23 +++ > linux-user/riscv/target_structs.h | 46 ++ > linux-user/riscv/target_syscall.h | 56 > linux-user/riscv/termbits.h | 222 + > linux-user/signal.c | 203 ++- > linux-user/syscall.c | 2 + > linux-user/syscall_defs.h | 13 +- > target/riscv/cpu_user.h | 13 ++ > 13 files changed, 1012 insertions(+), 6 deletions(-) > create mode 100644 linux-user/riscv/syscall_nr.h > create mode 100644 linux-user/riscv/target_cpu.h > create mode 100644 linux-user/riscv/target_elf.h > create mode 100644 linux-user/riscv/target_signal.h > create mode 100644 linux-user/riscv/target_structs.h > create mode 100644 linux-user/riscv/target_syscall.h > create mode 100644 linux-user/riscv/termbits.h > create mode 100644 target/riscv/cpu_user.h > ... > diff --git a/linux-user/signal.c b/linux-user/signal.c > index 9a380b9..4d3f244 100644 > --- a/linux-user/signal.c > +++ b/linux-user/signal.c ... > +static abi_ulong get_sigframe(struct target_sigaction *ka, > + CPURISCVState *regs, size_t framesize) > +{ > +abi_ulong sp = regs->gpr[xSP]; > +int onsigstack = on_sig_stack(sp); > + > +/* redzone */ > +/* This is the X/Open sanctioned signal stack switching. */ > +if ((ka->sa_flags & TARGET_SA_ONSTACK) != 0 && !onsigstack) { > +sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; > +} > + > +sp -= framesize; > +sp &= ~3UL; /* align sp on 4-byte boundary */ kernel aligns using 0xf. Why do you use a different alignment? > + > +/* If we are on the alternate signal stack and would overflow it, don't. > + Return an always-bogus address instead so we will die with SIGSEGV. */ > +if (onsigstack && !likely(on_sig_stack(sp))) { > +return -1L; > +} > + > +return sp; > +} Other question why don't you use the same logic as in kernel? 1- check for signal stack overflow 2- check for X/Open sanctioned signal stack switching static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t framesize) { unsigned long sp; /* Default to using normal stack */ sp = regs->sp; /* * If we are on the alternate signal stack and would overflow it, don't. * Return an always-bogus address instead so we will die with SIGSEGV. */ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) return (void __user __force *)(-1UL); /* This is the X/Open sanctioned signal stack switching. */ sp = sigsp(sp, ksig) - framesize; /* Align the stack frame. */ sp &= ~0xfUL; return (void __user *)sp; } Thanks, Laurent
[Qemu-devel] [PATCH v8 10/23] RISC-V Linux User Emulation
Implementation of linux user emulation for RISC-V. Reviewed-by: Richard HendersonSigned-off-by: Sagar Karandikar Signed-off-by: Michael Clark --- linux-user/elfload.c | 22 +++ linux-user/main.c | 99 + linux-user/riscv/syscall_nr.h | 287 ++ linux-user/riscv/target_cpu.h | 18 +++ linux-user/riscv/target_elf.h | 14 ++ linux-user/riscv/target_signal.h | 23 +++ linux-user/riscv/target_structs.h | 46 ++ linux-user/riscv/target_syscall.h | 56 linux-user/riscv/termbits.h | 222 + linux-user/signal.c | 203 ++- linux-user/syscall.c | 2 + linux-user/syscall_defs.h | 13 +- target/riscv/cpu_user.h | 13 ++ 13 files changed, 1012 insertions(+), 6 deletions(-) create mode 100644 linux-user/riscv/syscall_nr.h create mode 100644 linux-user/riscv/target_cpu.h create mode 100644 linux-user/riscv/target_elf.h create mode 100644 linux-user/riscv/target_signal.h create mode 100644 linux-user/riscv/target_structs.h create mode 100644 linux-user/riscv/target_syscall.h create mode 100644 linux-user/riscv/termbits.h create mode 100644 target/riscv/cpu_user.h diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 6689089..838f1c4 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1293,6 +1293,28 @@ static inline void init_thread(struct target_pt_regs *regs, #endif /* TARGET_TILEGX */ +#ifdef TARGET_RISCV + +#define ELF_START_MMAP 0x8000 +#define ELF_ARCH EM_RISCV + +#ifdef TARGET_RISCV32 +#define ELF_CLASS ELFCLASS32 +#else +#define ELF_CLASS ELFCLASS64 +#endif + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ +regs->sepc = infop->entry; +regs->sp = infop->start_stack; +} + +#define ELF_EXEC_PAGESIZE 4096 + +#endif /* TARGET_RISCV */ + #ifdef TARGET_HPPA #define ELF_START_MMAP 0x8000 diff --git a/linux-user/main.c b/linux-user/main.c index bbeb78f..7bc9bc7 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3653,6 +3653,100 @@ void cpu_loop(CPUTLGState *env) #endif +#ifdef TARGET_RISCV + +void cpu_loop(CPURISCVState *env) +{ +CPUState *cs = CPU(riscv_env_get_cpu(env)); +int trapnr, signum, sigcode; +target_ulong sigaddr; +target_ulong ret; + +for (;;) { +cpu_exec_start(cs); +trapnr = cpu_exec(cs); +cpu_exec_end(cs); +process_queued_cpu_work(cs); + +signum = 0; +sigcode = 0; +sigaddr = 0; + +switch (trapnr) { +case EXCP_INTERRUPT: +/* just indicate that signals should be handled asap */ +break; +case EXCP_ATOMIC: +cpu_exec_step_atomic(cs); +break; +case RISCV_EXCP_U_ECALL: +env->pc += 4; +if (env->gpr[xA7] == TARGET_NR_arch_specific_syscall + 15) { +/* riscv_flush_icache_syscall is a no-op in QEMU as + self-modifying code is automatically detected */ +ret = 0; +} else { +ret = do_syscall(env, + env->gpr[xA7], + env->gpr[xA0], + env->gpr[xA1], + env->gpr[xA2], + env->gpr[xA3], + env->gpr[xA4], + env->gpr[xA5], + 0, 0); +} +if (ret == -TARGET_ERESTARTSYS) { +env->pc -= 4; +} else if (ret != -TARGET_QEMU_ESIGRETURN) { +env->gpr[xA0] = ret; +} +if (cs->singlestep_enabled) { +goto gdbstep; +} +break; +case RISCV_EXCP_ILLEGAL_INST: +signum = TARGET_SIGILL; +sigcode = TARGET_ILL_ILLOPC; +break; +case RISCV_EXCP_BREAKPOINT: +signum = TARGET_SIGTRAP; +sigcode = TARGET_TRAP_BRKPT; +sigaddr = env->pc; +break; +case RISCV_EXCP_INST_PAGE_FAULT: +case RISCV_EXCP_LOAD_PAGE_FAULT: +case RISCV_EXCP_STORE_PAGE_FAULT: +signum = TARGET_SIGSEGV; +sigcode = TARGET_SEGV_MAPERR; +break; +case EXCP_DEBUG: +gdbstep: +signum = gdb_handlesig(cs, TARGET_SIGTRAP); +sigcode = TARGET_TRAP_BRKPT; +break; +default: +EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n", + trapnr); +exit(EXIT_FAILURE); +} + +if (signum) { +target_siginfo_t info = { +.si_signo = signum, +