Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cef416f
ume: Add interpolation and specific pass for ume template tags #757
arcane-quill Mar 21, 2026
33bf7f8
ume: Add specific tags for regs and exceptions #757
arcane-quill Mar 22, 2026
95cdeb5
ume: Fix subdir in meson
arcane-quill Mar 22, 2026
2a65a6c
ume: Add interpolation and specific pass for ume template tags #757
arcane-quill Mar 21, 2026
8749792
ume: Remove everything related to frontend #757
arcane-quill Mar 23, 2026
275af19
ume: Add ume definition #757
arcane-quill Mar 30, 2026
f9870ad
ume: Add more values for interpolation #757
arcane-quill Apr 4, 2026
fec5dc8
ume: Add missing interpolation #757
arcane-quill Apr 12, 2026
fc5e22e
ume: Fix checkstyle violations #757
arcane-quill Apr 12, 2026
1440cb7
ume: Fix more checkstyle violations #757
arcane-quill Apr 12, 2026
28c1e59
ume: Remove duplicate line #757
arcane-quill Apr 12, 2026
3f37df9
ume: Revert frontend changes #757
arcane-quill Apr 13, 2026
3f7de33
ume: Revert atg file changes #757
arcane-quill Apr 13, 2026
b6d7912
ume: Use proper viam objects and fix templates #757
arcane-quill Apr 14, 2026
488a431
ume: Revert misc file
arcane-quill Apr 15, 2026
8c54fa7
ume: Fix signal.c reigster handling #757
arcane-quill Apr 23, 2026
5fde96b
ume: Add ifs for causevar and signal to template #757
arcane-quill May 9, 2026
dcb3847
ume: Refactor UME definitions #757
arcane-quill May 17, 2026
daec0b8
ume: Add UME section to vadl file, remove exceptions from cpuloop #757
arcane-quill May 26, 2026
a6a88bf
ume: Add syscall section to vadl file #757
arcane-quill May 31, 2026
1379c83
iss: Fix UME pass order
Jozott00 Jun 3, 2026
53fbd00
ume: Fix registers #757
arcane-quill Jun 8, 2026
4f2a2ec
ume: Use hardcoded arguments #757
arcane-quill Jun 12, 2026
16ea90b
ume: Improve register hardcoding #757
arcane-quill Jun 12, 2026
93f5a2b
ume: Add syscall #757
arcane-quill Jul 19, 2026
ad2f2e5
ume: Remove sepc #757
arcane-quill Jul 19, 2026
e39efaf
ume: Add synthetic exception #757
arcane-quill Jul 19, 2026
20f20ff
ume: Add more synth syscall logic #757
arcane-quill Jul 26, 2026
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
36 changes: 36 additions & 0 deletions sys/risc-v/rv64ume.vadl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,42 @@ import rv64csr::{ RV64IMZicsr }

instruction set architecture RV64UME extending RV64IMZicsr = {}

application binary interface ABI for RV64UME = {
alias register a0 = X(10)
alias register a1 = X(11)
alias register a2 = X(12)
alias register a3 = X(13)
alias register a4 = X(14)
alias register a5 = X(15)
alias register a6 = X(16)
alias register a7 = X(17)
alias register sp = X(2)
alias register ra = X(1)
alias register gp = X(3)
alias register fp = X(8)

return address = ra
stack pointer = sp
return value = a0
frame pointer = fp
global pointer = gp
function argument = [ a{0..7} ]
caller saved = [ a{0..7} ]
callee saved = [ ra, fp,
X(9), X(18), X(19), X(20), X(21),
X(22), X(23), X(24), X(25), X(26), X(27) ]

special absolute address load instruction = LA
special local address load instruction = LLA

special return instruction = RET
special call instruction = CALL
Comment on lines +8 to +36

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.

Fine for now, later this should be minimized to a minimal set of definitions that is required for the UME (#968).

}

enumeration LinuxSyscall : Bits<64> = {
sys_riscv_hwprobe = 258
, sys_riscv_flush_icache = 259
}

// This is the system-mode entry point.
// Once we have a user-mode definition, this should be removed.
Expand Down
73 changes: 21 additions & 52 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,17 +24,10 @@
#include "signal-common.h"
#include "elf.h"

enum {
RV64UME_EXC_ILLEGAL_INSTR = 2,
RV64UME_EXC_BREAKPOINT = 3,
RV64UME_EXC_ECALL = 11,
};

void cpu_loop(CPURV64UMEState *env)
void cpu_loop(CPU[(${gen_arch_upper})]State *env)
{
CPUState *cs = env_cpu(env);
int trapnr;
uint32_t cause;
target_ulong ret;

for (;;) {
Expand All @@ -50,55 +43,31 @@ void cpu_loop(CPURV64UMEState *env)
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
case RV64UME_EXCP_EXC:
cause = env->arg_exc_cause;
switch (cause) {
case RV64UME_EXC_ECALL:
env->pc += 4;
if (env->x[RV64UME_REG_A7] == TARGET_NR_rv64ume_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);
}
if (ret == -QEMU_ERESTARTSYS) {
env->pc -= 4;
} else if (ret != -QEMU_ESIGRETURN) {
env->x[RV64UME_REG_A0] = ret;
}
if (cs->singlestep_enabled) {
goto gdbstep;
}
break;
case RV64UME_EXC_ILLEGAL_INSTR:
force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc);
break;
case RV64UME_EXC_BREAKPOINT:
case EXCP_DEBUG:
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
default:
EXCP_DUMP(env,
"\nqemu: unhandled rv64ume exception cause %#x - aborting\n",
cause);
exit(EXIT_FAILURE);
case [(${gen_arch_upper})]_EXCP_SYSCALL:
env->[(${pc_info.accessor})] += [(${config.insn_width_bytes})];
ret = do_syscall(env,
env->[(${config.sysRegFile})][ [(${config.sysReg})] ],
[# th:each="arg : ${config.args}"]
env->[(${arg.file})][ [(${arg.index})] ],
[/]
0, 0);
if (ret == -QEMU_ERESTARTSYS) {
env->[(${pc_info.accessor})] -= [(${config.insn_width_bytes})];
} else if (ret != -QEMU_ESIGRETURN) {
env->[(${config.retRegFile})][ [(${config.retReg})] ] = ret; }
if (cs->singlestep_enabled) {
goto gdbstep;
}
break;
case EXCP_DEBUG:
gdbstep:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->[(${pc_info.accessor})]);
break;
default:
EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
trapnr);
exit(EXIT_FAILURE);
}

process_pending_signals(env);
}
}
Expand All @@ -109,8 +78,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_info.accessor})] = regs->sepc;
env->[(${config.spRegFile})][ [(${config.spReg})] ] = regs->[(${config.spRegName})];

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')
}
162 changes: 12 additions & 150 deletions vadl/main/resources/templates/iss/linux-user/gen-arch/signal.c
Original file line number Diff line number Diff line change
@@ -1,171 +1,33 @@
/*
* Emulation of Linux signals for rv64ume user-mode.
*/

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

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

struct target_ucontext {
abi_ulong uc_flags;
abi_ptr uc_link;
target_stack_t uc_stack;
target_sigset_t uc_sigmask;
uint8_t __unused[1024 / 8 - sizeof(target_sigset_t)];
struct target_sigcontext uc_mcontext QEMU_ALIGNED(16);
};

struct target_rt_sigframe {
struct target_siginfo info;
struct target_ucontext uc;
};

static abi_ulong get_sigframe(struct target_sigaction *ka,
CPURV64UMEState *regs, size_t framesize)
{
abi_ulong sp = get_sp_from_cpustate(regs);

if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) {
return -1L;
}

sp = target_sigsp(sp, ka) - framesize;
sp &= ~0xf;

return sp;
}

static void setup_sigcontext(struct target_sigcontext *sc, CPURV64UMEState *env)
{
int i;

__put_user(env->pc, &sc->pc);
for (i = 1; i < 32; i++) {
__put_user(env->x[i], &sc->gpr[i - 1]);
}
}

static void setup_ucontext(struct target_ucontext *uc,
CPURV64UMEState *env, target_sigset_t *set)
{
int i;

__put_user(0, &(uc->uc_flags));
__put_user(0, &(uc->uc_link));

target_save_altstack(&uc->uc_stack, env);

for (i = 0; i < TARGET_NSIG_WORDS; i++) {
__put_user(set->sig[i], &(uc->uc_sigmask.sig[i]));
}

setup_sigcontext(&uc->uc_mcontext, env);
}

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;

frame_addr = get_sigframe(ka, env, sizeof(*frame));
trace_user_setup_rt_frame(env, frame_addr);
(void)ka;
(void)info;
(void)set;
(void)env;

if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
goto badframe;
}

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;

return;

badframe:
unlock_user_struct(frame, frame_addr, 1);
if (sig == TARGET_SIGSEGV) {
ka->_sa_handler = TARGET_SIG_DFL;
force_sig(TARGET_SIGSEGV);
} else {
force_sig(sig);
}
force_sig(TARGET_SIGSEGV);
}

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

__get_user(env->pc, &sc->pc);
for (i = 1; i < 32; ++i) {
__get_user(env->x[i], &sc->gpr[i - 1]);
}
}

static void restore_ucontext(CPURV64UMEState *env, struct target_ucontext *uc)
{
sigset_t blocked;
target_sigset_t target_set;
int i;

target_sigemptyset(&target_set);
for (i = 0; i < TARGET_NSIG_WORDS; i++) {
__get_user(target_set.sig[i], &(uc->uc_sigmask.sig[i]));
}
(void)env;

target_to_host_sigset_internal(&blocked, &target_set);
set_sigmask(&blocked);

restore_sigcontext(env, &uc->uc_mcontext);
}

long do_rt_sigreturn(CPURV64UMEState *env)
{
struct target_rt_sigframe *frame;
abi_ulong frame_addr;

frame_addr = env->x[RV64UME_REG_SP];
trace_user_do_sigreturn(env, frame_addr);
if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
goto badframe;
}

restore_ucontext(env, &frame->uc);
target_restore_altstack(&frame->uc.uc_stack, env);

unlock_user_struct(frame, frame_addr, 0);
return -QEMU_ESIGRETURN;

badframe:
unlock_user_struct(frame, frame_addr, 0);
force_sig(TARGET_SIGSEGV);
return 0;
}

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 */

default_rt_sigreturn = sigtramp_page;
unlock_user(tramp, sigtramp_page, 8);
}
(void)sigtramp_page;
}

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
Loading
Loading