Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 68 additions & 28 deletions vadl/main/resources/templates/iss/linux-user/gen-arch/cpu_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
#include "signal-common.h"
#include "elf.h"


enum {
RV64UME_EXC_ILLEGAL_INSTR = 2,
RV64UME_EXC_BREAKPOINT = 3,
RV64UME_EXC_ECALL = 11,
[# th:each="exc : ${config.excIds}"]
[(${gen_arch_upper})]_EXC_[(${exc.key})] = [(${exc.value})],
[/]
};

void cpu_loop(CPURV64UMEState *env)
void cpu_loop(CPU[(${gen_arch_upper})]State *env)
{
CPUState *cs = env_cpu(env);
int trapnr;
Expand All @@ -50,45 +51,47 @@ void cpu_loop(CPURV64UMEState *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
case RV64UME_EXCP_EXC:
cause = env->arg_exc_cause;
[# th:if="${not #strings.isEmpty(config.excCauseVar)}"]
case [(${gen_arch_upper})]_EXCP_[(${config.syscallException})]:
cause = env->[(${config.excCauseVar})];
Comment thread
arcane-quill marked this conversation as resolved.
switch (cause) {
case RV64UME_EXC_ECALL:
env->pc += 4;
if (env->x[RV64UME_REG_A7] == TARGET_NR_rv64ume_flush_icache) {
case [(${gen_arch_upper})]_EXC_[(${config.syscallInstr})]:
env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
[# th:if="${config.hasIcacheFlush}"]
if (env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
/* no-op in QEMU; TB invalidation is automatic */
ret = 0;
} else {
[/]
ret = do_syscall(env,
env->x[RV64UME_REG_A7],
env->x[RV64UME_REG_A0],
env->x[RV64UME_REG_A1],
env->x[RV64UME_REG_A2],
env->x[RV64UME_REG_A3],
env->x[RV64UME_REG_A4],
env->x[RV64UME_REG_A5],
0, 0);
env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
[# th:each="arg : ${config.args}"]
env->[(${config.mainRegisterFile})][ [(${arg})] ],
[/]
0, 0);
[# th:if="${config.hasIcacheFlush}"]
}
[/]
Comment on lines +60 to +74
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

major: Just assume there is no icache-flush

if (ret == -QEMU_ERESTARTSYS) {
env->pc -= 4;
env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
} else if (ret != -QEMU_ESIGRETURN) {
env->x[RV64UME_REG_A0] = ret;
}
env->[(${config.mainRegisterFile})][ [(${config.retReg})] ] = ret; }
if (cs->singlestep_enabled) {
goto gdbstep;
}
break;
case RV64UME_EXC_ILLEGAL_INSTR:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);

case [(${gen_arch_upper})]_EXC_[(${config.illegalInstrExcName})]:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
break;
case RV64UME_EXC_BREAKPOINT:
case [(${gen_arch_upper})]_EXC_[(${config.breakpointExcName})]:
case EXCP_DEBUG:
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
break;
default:
EXCP_DUMP(env,
"\nqemu: unhandled rv64ume exception cause %#x - aborting\n",
"\nqemu: unhandled [(${gen_arch_lower})] exception cause %#x - aborting\n",
cause);
exit(EXIT_FAILURE);
}
Expand All @@ -98,6 +101,43 @@ void cpu_loop(CPURV64UMEState *env)
trapnr);
exit(EXIT_FAILURE);
}
[/]
[# th:if="${#strings.isEmpty(config.excCauseVar)}"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

major: This check is unnecessary, as exceptions in the ISS are always rendered as cause variables in the state.

case [(${gen_arch_upper})]_EXC_[(${config.syscallInstr})]:
env->[(${pc_reg.name_lower})] += [(${config.insn_width_bytes})];
[# th:if="${config.hasIcacheFlush}"]
if (env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ] == TARGET_NR_[(${gen_arch_lower})]_flush_icache) {
/* no-op in QEMU; TB invalidation is automatic */
ret = 0;
} else {
[/]
ret = do_syscall(env,
env->[(${config.mainRegisterFile})][ [(${config.sysReg})] ],
[# th:each="arg : ${config.args}"]
env->[(${config.mainRegisterFile})][ [(${arg})] ],
[/]
0, 0);
[# th:if="${config.hasIcacheFlush}"]
}
[/]
if (ret == -QEMU_ERESTARTSYS) {
env->[(${pc_reg.name_lower})] -= [(${config.insn_width_bytes})];
} else if (ret != -QEMU_ESIGRETURN) {
env->[(${config.mainRegisterFile})][ [(${config.retReg})] ] = ret; }
if (cs->singlestep_enabled) {
goto gdbstep;
}
break;

case [(${gen_arch_upper})]_EXC_[(${config.illegalInstrExcName})]:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->[(${pc_reg.name_lower})]);
break;
case [(${gen_arch_upper})]_EXC_[(${config.breakpointExcName})]:
case EXCP_DEBUG:
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_reg.name_lower})]);
break;
[/]

process_pending_signals(env);
}
Expand All @@ -109,8 +149,8 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
TaskState *ts = get_task_state(cpu);
struct image_info *info = ts->info;

env->pc = regs->sepc;
env->x[RV64UME_REG_SP] = regs->sp;
env->[(${pc_reg.name_lower})] = regs->[(${config.initialPc})];
env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = regs->[(${config.initalSp})];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

major: As we just hardcode the target_pt_regs anyway, just use regs->pc and regs->sp instead.


ts->stack_base = info->start_stack;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
syscall_nr_generators += {
'rv64ume': generator(sh,
'[(${gen_arch_lower})]': generator(sh,
arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
output: '@BASENAME@_nr.h')
}
69 changes: 41 additions & 28 deletions vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Emulation of Linux signals for rv64ume user-mode.
* Emulation of Linux signals for [(${gen_arch_lower})] user-mode.
*/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

major: I think for now, signals are too overwhelming.

Let's turn it into a bare minimum implementation that just ensures compilation succeeds.

Something like this (although not tested).

#include "qemu/osdep.h"
#include "qemu.h"
#include "user-internals.h"
#include "signal-common.h"

void setup_rt_frame(int sig, struct target_sigaction *ka,
                    target_siginfo_t *info,
                    target_sigset_t *set, CPU[(${gen_arch_upper})]State *env)
{
    (void)ka;
    (void)info;
    (void)set;
    (void)env;

    if (sig == TARGET_SIGSEGV) {
        force_sig(TARGET_SIGSEGV);
    } else {
        force_sig(sig);
    }
}

long do_rt_sigreturn(CPU[(${gen_arch_upper})]State *env)
{
    (void)env;

    force_sig(TARGET_SIGSEGV);
    return 0;
}

void setup_sigtramp(abi_ulong sigtramp_page)
{
    (void)sigtramp_page;
}

Also test if it compiles when you are removing the whole content. In that case, do that instead.


#include "qemu/osdep.h"
Expand All @@ -9,13 +9,16 @@
#include "linux-user/trace.h"

/*
* Minimal sigcontext matching rv64ume state:
* Minimal sigcontext matching [(${gen_arch_lower})] state:
* - pc
* - x1..x31 (x0 is always zero and omitted)
*/
struct target_sigcontext {
abi_long pc;
abi_long gpr[31];
abi_long [(${pc_reg.name_lower})];

[# th:each="tensor : ${config.signalStateTensors}"]
abi_long [(${tensor.name_lower})][ [(${tensor.size})] ];
[/]
};

struct target_ucontext {
Expand All @@ -33,7 +36,7 @@ struct target_rt_sigframe {
};

static abi_ulong get_sigframe(struct target_sigaction *ka,
CPURV64UMEState *regs, size_t framesize)
CPU[(${gen_arch_upper})]State *regs, size_t framesize)
{
abi_ulong sp = get_sp_from_cpustate(regs);

Expand All @@ -42,23 +45,25 @@ static abi_ulong get_sigframe(struct target_sigaction *ka,
}

sp = target_sigsp(sp, ka) - framesize;
sp &= ~0xf;
sp &= ~[(${config.stack_align_mask} ?: '0xf')];

return sp;
}

static void setup_sigcontext(struct target_sigcontext *sc, CPURV64UMEState *env)
static void setup_sigcontext(struct target_sigcontext *sc, CPU[(${gen_arch_upper})]State *env)
{
int i;

__put_user(env->pc, &sc->pc);
for (i = 1; i < 32; i++) {
__put_user(env->x[i], &sc->gpr[i - 1]);
}
__put_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
[# th:each="tensor : ${config.signalStateTensors}"]
for (i = 0; i < [(${tensor.size})]; i++) {
__put_user(env->[(${tensor.name_lower})][i], &sc->[(${tensor.name_lower})][i]);
}
[/]
}

static void setup_ucontext(struct target_ucontext *uc,
CPURV64UMEState *env, target_sigset_t *set)
CPU[(${gen_arch_upper})]State *env, target_sigset_t *set)
{
int i;

Expand All @@ -76,7 +81,7 @@ static void setup_ucontext(struct target_ucontext *uc,

void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPURV64UMEState *env)
target_sigset_t *set, CPU[(${gen_arch_upper})]State *env)
{
abi_ulong frame_addr;
struct target_rt_sigframe *frame;
Expand All @@ -91,12 +96,18 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
setup_ucontext(&frame->uc, env, set);
frame->info = *info;

env->pc = ka->_sa_handler;
env->x[RV64UME_REG_SP] = frame_addr;
env->x[RV64UME_REG_A0] = sig;
env->x[RV64UME_REG_A1] = frame_addr + offsetof(struct target_rt_sigframe, info);
env->x[RV64UME_REG_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
env->x[RV64UME_REG_RA] = default_rt_sigreturn;
env->[(${pc_reg.name_lower})] = ka->_sa_handler;
env->[(${config.mainRegisterFile})][ [(${config.spReg})] ] = frame_addr;
env->[(${config.mainRegisterFile})][ [(${config.args[0]})] ] = sig;
[# th:if="${#lists.size(config.args) > 1}"]
env->[(${config.mainRegisterFile})][ [(${config.args[1]})] ] = frame_addr + offsetof(struct target_rt_sigframe, info);
[/]
[# th:if="${#lists.size(config.args) > 2}"]
env->[(${config.mainRegisterFile})][ [(${config.args[2]})] ] = frame_addr + offsetof(struct target_rt_sigframe, uc);
[/]
[# th:if="${config.raReg != null}"]
env->[(${config.mainRegisterFile})][ [(${config.raReg})] ] = default_rt_sigreturn;
[/]

return;

Expand All @@ -108,17 +119,19 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
force_sig(TARGET_SIGSEGV);
}

static void restore_sigcontext(CPURV64UMEState *env, struct target_sigcontext *sc)
static void restore_sigcontext(CPU[(${gen_arch_upper})]State *env, struct target_sigcontext *sc)
{
int i;

__get_user(env->pc, &sc->pc);
for (i = 1; i < 32; ++i) {
__get_user(env->x[i], &sc->gpr[i - 1]);
__get_user(env->[(${pc_reg.name_lower})], &sc->[(${pc_reg.name_lower})]);
[# th:each="tensor : ${config.signalStateTensors}"]
for (i = 0; i < [(${tensor.size})]; i++) {
__get_user(env->[(${tensor.name_lower})][i], &sc->[(${tensor.name_lower})][i]);
}
[/]
}

static void restore_ucontext(CPURV64UMEState *env, struct target_ucontext *uc)
static void restore_ucontext(CPU[(${gen_arch_upper})]State *env, struct target_ucontext *uc)
{
sigset_t blocked;
target_sigset_t target_set;
Expand All @@ -135,12 +148,12 @@ static void restore_ucontext(CPURV64UMEState *env, struct target_ucontext *uc)
restore_sigcontext(env, &uc->uc_mcontext);
}

long do_rt_sigreturn(CPURV64UMEState *env)
long do_rt_sigreturn(CPU[(${gen_arch_upper})]State *env)
{
struct target_rt_sigframe *frame;
abi_ulong frame_addr;

frame_addr = env->x[RV64UME_REG_SP];
frame_addr = env->[(${config.mainRegisterFile})][ [(${config.spReg})] ];
trace_user_do_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
Expand All @@ -163,8 +176,8 @@ void setup_sigtramp(abi_ulong sigtramp_page)
uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
assert(tramp != NULL);

__put_user(0x08b00893, tramp + 0); /* li a7, 139 = __NR_rt_sigreturn */
__put_user(0x00000073, tramp + 1); /* ecall */
__put_user([(${config.sigtrampLoadSyscallInstr})], tramp + 0); /* load rt_sigreturn syscall number */
__put_user([(${config.sigtrampTrapInstr})], tramp + 1); /* syscall/trap instruction */

default_rt_sigreturn = sigtramp_page;
unlock_user(tramp, sigtramp_page, 8);
Expand Down
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: This whole table is currently hardcoded. However, I think we should do the dynamic interpolation in a separate PR.

Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@

244 or1k or1k_atomic sys_or1k_atomic

258 rv64ume rv64ume_hwprobe sys_rv64ume_hwprobe
259 rv64ume rv64ume_flush_icache sys_rv64ume_flush_icache
258 [(${gen_arch_lower})] [(${gen_arch_lower})]_hwprobe sys_[(${gen_arch_lower})]_hwprobe
259 [(${gen_arch_lower})] [(${gen_arch_lower})]_flush_icache sys_[(${gen_arch_lower})]_flush_icache

260 time32 wait4 sys_wait4 compat_sys_wait4
260 64 wait4 sys_wait4
Expand Down
38 changes: 18 additions & 20 deletions vadl/main/resources/templates/iss/linux-user/gen-arch/target_cpu.h
Original file line number Diff line number Diff line change
@@ -1,40 +1,38 @@
#ifndef RV64UME_TARGET_CPU_H
#define RV64UME_TARGET_CPU_H
#ifndef [(${gen_arch_upper})]_TARGET_CPU_H
#define [(${gen_arch_upper})]_TARGET_CPU_H

//TODO: check for correct interpolattions for regs & values
enum {
RV64UME_REG_RA = 1,
RV64UME_REG_SP = 2,
RV64UME_REG_TP = 4,
RV64UME_REG_A0 = 10,
RV64UME_REG_A1 = 11,
RV64UME_REG_A2 = 12,
RV64UME_REG_A3 = 13,
RV64UME_REG_A4 = 14,
RV64UME_REG_A5 = 15,
RV64UME_REG_A7 = 17,
[(${gen_arch_upper})]_REG_RA = [(${config.raReg})],
[(${gen_arch_upper})]_REG_SP = [(${config.spReg})],
[(${gen_arch_upper})]_REG_TP = [(${config.tpReg})],

[# th:each="arg, stat : ${config.args}"]
[(${gen_arch_upper})]_REG_ARG[(${stat.index})] = [(${arg})],
[/]
};

static inline void cpu_clone_regs_child(CPURV64UMEState *env, target_ulong newsp,
static inline void cpu_clone_regs_child(CPU[(${gen_arch_upper})]State *env, target_ulong newsp,
unsigned flags)
{
if (newsp) {
env->x[RV64UME_REG_SP] = newsp;
env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP] = newsp;
}

env->x[RV64UME_REG_A0] = 0;
env->[(${register_tensors[0].name_lower})][ [(${config.retReg})] ] = 0;
}

static inline void cpu_clone_regs_parent(CPURV64UMEState *env, unsigned flags)
static inline void cpu_clone_regs_parent(CPU[(${gen_arch_upper})]State *env, unsigned flags)
{
}

static inline void cpu_set_tls(CPURV64UMEState *env, target_ulong newtls)
static inline void cpu_set_tls(CPU[(${gen_arch_upper})]State *env, target_ulong newtls)
{
env->x[RV64UME_REG_TP] = newtls;
env->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_TP] = newtls;
}

static inline abi_ulong get_sp_from_cpustate(CPURV64UMEState *state)
static inline abi_ulong get_sp_from_cpustate(CPU[(${gen_arch_upper})]State *state)
{
return state->x[RV64UME_REG_SP];
return state->[(${register_tensors[0].name_lower})][ [(${gen_arch_upper})]_REG_SP];
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* later version. See the COPYING file in the top-level directory.
*/

#ifndef RV64UME_TARGET_ELF_H
#define RV64UME_TARGET_ELF_H
#ifndef [(${gen_arch_upper})]_TARGET_ELF_H
#define [(${gen_arch_upper})]_TARGET_ELF_H
static inline const char *cpu_get_model(uint32_t eflags)
{
return "max";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef RV64UME_TARGET_ERRNO_DEFS_H
#define RV64UME_TARGET_ERRNO_DEFS_H
#ifndef [(${gen_arch_upper})]_TARGET_ERRNO_DEFS_H
#define [(${gen_arch_upper})]_TARGET_ERRNO_DEFS_H

/* Target uses generic errno */
#include "../generic/target_errno_defs.h"
Expand Down
Loading
Loading