commit - c21d1989ef14647a6262e7ac4c5a2438df77abe4
commit + 16107e2ec3ad181f8d1905b71edf72b65487ac34
blob - a0baec7dd2d222cb9851c15e968d68c23e0ddede
blob + 910b207a5c86bc89611cebafb24cf0fa056f2e3d
--- .gitignore
+++ .gitignore
examples/*.elf
src/syscalls.h
+src/signal-bootstrap-code.h
src/*.o
tools/bin
tools/build
blob - 038e3eabdf2b72e8a0eb09c150efc3ad81ad0ebf
blob + e1164a3ca8c929fc4bcd7264ad638b734d6dc10e
--- Makefile
+++ Makefile
CFLAGS = ${CFLAGS_OS} ${COPT} -std=c2x -Wall -Wextra
LDFLAGS = ${LDFLAGS_OS} -lpthread
-OBJ = src/linurv.o src/ecall.o src/cpu.o src/exec.o
-T = test
+OBJ = src/linurv.o src/ecall.o src/cpu.o src/exec.o src/signal.o
+T = signal
PROGS = examples/test.elf \
examples/echo.elf \
examples/cat.elf \
examples/hello.elf \
- examples/asm.elf
+ examples/asm.elf \
+ examples/signal.elf
all: linurv ${PROGS}
cp -f linurv rootfs/bin
cp -f ${PROGS} rootfs/bin
cp -f test.txt rootfs/
- ${CHROOT} rootfs /bin/linurv /bin/$T.elf
+ ${CHROOT} rootfs /bin/linurv -v /bin/$T.elf
distclean: clean
(cd tools; ${MAKE} distclean)
clean:
- rm -f linurv src/*.o examples/*.elf *.core src/syscalls.h
+ rm -f linurv src/*.o examples/*.elf *.core src/syscalls.h src/signal-bootstrap-code.h src/sbc.*
rm -rf rootfs
install: linurv
src/ecall.o: src/syscalls.h
+src/cpu.o: src/signal-bootstrap-code.h
+
src/syscalls.h: src/syscalls.inc src/gensyscalls.sh
sh src/gensyscalls.sh < src/syscalls.inc > $@
.c.o:
${CC} -c -o $@ $< ${CFLAGS}
+src/signal-bootstrap-code.h: src/signal-bootstrap-code.S
+ ${CROSS}-as -o src/sbc.o src/signal-bootstrap-code.S
+ ${CROSS}-objcopy -O binary src/sbc.o src/sbc.bin
+ hexdump -v -e '16/1 "0x%02x," "\n"' <src/sbc.bin >$@
+ rm -f src/sbc.*
.c.elf:
${CROSS}-gcc -g -o $@ $< -Og
blob - /dev/null
blob + c45dfee3c45a53836ac02cd12653fa993a6c1252 (mode 644)
--- /dev/null
+++ examples/signal.c
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+
+void handle_signal (int sig)
+{
+ printf ("Signal: %d\n", sig);
+}
+
+int main (void)
+{
+ struct sigaction act;
+
+ memset (&act, 0, sizeof (act));
+ act.sa_handler = handle_signal;
+ sigaction (SIGINT, &act, NULL);
+
+ for (int i = 0; i < 3; ++i) {
+ puts ("sleeping...");
+ sleep (5);
+ }
+}
blob - cf9d917af65dec853f6d7828188c8e3fe8ff08a2
blob + 684502fb6349e72eeefd9b684a72400af6d18215
--- src/cpu.c
+++ src/cpu.c
#include <inttypes.h>
#include "linurv.h"
+static volatile u64 pending_sig_handler;
+static volatile int pending_sig = 0;
static u64 regs[31];
u64 pc, next_pc;
+__attribute__((aligned(4)))
+static u8 signal_bootstrap_code[] = {
+#include "signal-bootstrap-code.h"
+};
+
void cpu_set (size_t reg, u64 val)
{
if (reg > 0)
break;
case 0b011: // sd
sx ("sd");
- write_u64 (b, a);
- break;
+ write_u64 (b, a);
+ break;
default:
goto ud;
}
break;
case 0b1110011: // ecall/ebreak
if ((instr >> 20) & 1) {
- vdebug ("ebreak");
- __builtin_trap ();
+ instr = read_u32 (next_pc);
+ if (instr == 0x40005013) {
+ // return from signal
+ vdebug ("sigret");
+ next_pc = cpu_get (REG_ra);
+ cpu_set (REG_ra, read_u32 (cpu_get (REG_sp)));
+ cpu_set (REG_sp, cpu_get (REG_sp) + 8);
+ } else {
+ vdebug ("ebreak");
+ __builtin_trap ();
+ }
} else {
ecall ();
}
error ("invalid instruction: %08x", instr);
}
pc = next_pc;
+
+ if (pending_sig != 0) {
+ u64 sp;
+
+ debug ("Entering signal. (sp=%#lx)", (long)cpu_get (REG_sp));
+ cpu_set (REG_sp, cpu_get (REG_sp) - 24);
+ sp = cpu_get (REG_sp);
+ write_u64 (sp + 16, cpu_get (REG_ra));
+ write_u64 (sp + 8, cpu_get (REG_t0));
+ write_u64 (sp, cpu_get (REG_t1));
+ cpu_set (REG_ra, pc);
+ cpu_set (REG_t0, pending_sig_handler);
+ cpu_set (REG_t1, pending_sig);
+ pc = (u64)signal_bootstrap_code;
+ pending_sig = 0;
+ }
}
+void cpu_enter_signal (int sig, u64 handler)
+{
+ pending_sig_handler = handler;
+ pending_sig = sig;
+}
blob - 850c540e4c5020fd1870815dda1c4fed964d743d
blob + 5ce02ee3ef69ce0d1b9549ae62ac662c1fd8bbd2
--- src/ecall.c
+++ src/ecall.c
#include <fcntl.h>
#include <sched.h>
#include <errno.h>
+#include <time.h>
#include "syscalls.h"
#include "linurv.h"
char release[65];
char version[65];
char machine[65];
+};
+
+struct linux_timespec {
+ time_t ltv_sec;
+ long ltv_nsec;
};
static int map_errno (int err)
o |= R_OK;
return o;
+}
+
+static void timespec_from_linux (struct timespec *out, const struct linux_timespec *in)
+{
+ out->tv_sec = in->ltv_sec;
+ out->tv_nsec = in->ltv_nsec;
}
+static void timespec_to_linux (struct linux_timespec *out, const struct timespec *in)
+{
+ out->ltv_sec = in->tv_sec;
+ out->ltv_nsec = in->tv_nsec;
+}
+
+int mysigaction (int sig, const void *act, void *oact);
#define ptr(T, x) ((T *)(x))
#define str(x) ptr (const char, x)
ret = enosys ("get_robust_limit");
break;
case SYS_nanosleep:
- ret = enosys ("nanosleep");
+ {
+ const struct linux_timespec *lin = ptr (const void, a0);
+ struct linux_timespec *lout = ptr (void, a1);
+ struct timespec in, out;
+
+ timespec_from_linux (&in, lin);
+
+ ret = map (nanosleep (&in, lout != NULL ? &out : NULL));
+
+ if (lout != NULL)
+ timespec_to_linux (lout, &out);
+
+ dbg ("nanosleep(%p, %p)", lin, lout);
break;
+ }
case SYS_gettimer:
ret = enosys ("gettimer");
break;
break;
case SYS_sigsuspend:
ret = enosys ("sigsuspend");
+ abort ();
break;
case SYS_sigaction:
- ret = enosys ("sigaction");
+ ret = map (mysigaction (i0, ptr (const void, a1), ptr (void, a2)));
+ dbg ("sigaction(%d, %p, %p)", i0, ptr (const void, a1), ptr (void, a2));
break;
case SYS_rt_sigprocmask:
ret = enosys ("rt_sigprocmask");
blob - e139c889771a6f6a503315250cf80acbad06cd75
blob + d565fc7a8b030875463a30066c3c5a63ca5fe009
--- src/linurv.h
+++ src/linurv.h
int my_execve (const char *path, char **argv, char **envp);
int is_executable (const Elf64_Ehdr *);
void logger (enum log_level, const char *, int, const char *, ...);
+void cpu_enter_signal (int sig, u64 handler);
#define log(level, ...) logger ((level), __FILE__, __LINE__, __VA_ARGS__)
#define fatal(...) log (LOG_SILENT, __VA_ARGS__)
blob - /dev/null
blob + 49cfdf3ad59c9937e6b42e18c60cdedaf15f2980 (mode 644)
--- /dev/null
+++ src/signal-bootstrap-code.S
+# t0 - signal handler
+# t1 - signal number
+
+addi sp, sp, -(8 * 14)
+sd t2, 104(sp)
+sd t3, 96(sp)
+sd t4, 88(sp)
+sd t5, 80(sp)
+sd t6, 72(sp)
+sd a0, 64(sp)
+sd a1, 56(sp)
+sd a2, 48(sp)
+sd a3, 40(sp)
+sd a4, 32(sp)
+sd a5, 24(sp)
+sd a6, 16(sp)
+sd a7, 8(sp)
+sd ra, 0(sp)
+
+mv a0, t1
+jalr t0
+
+ld ra, 0(sp)
+ld a7, 8(sp)
+ld a6, 16(sp)
+ld a5, 24(sp)
+ld a4, 32(sp)
+ld a3, 40(sp)
+ld a2, 48(sp)
+ld a1, 56(sp)
+ld a0, 64(sp)
+ld t6, 72(sp)
+ld t5, 80(sp)
+ld t4, 88(sp)
+ld t3, 96(sp)
+ld t2, 104(sp)
+ld t1, 112(sp)
+ld t0, 120(sp)
+addi sp, sp, (8 * 16)
+ebreak
+srai x0, x0, 0
blob - /dev/null
blob + 41f75f230737220be38dd77a1a156f1afa869114 (mode 644)
--- /dev/null
+++ src/signal.c
+#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include "linurv.h"
+
+#define LSA_NOCLDSTOP 1
+#define LSA_NOCLDWAIT 2
+#define LSA_SIGINFO 4
+#define LSA_ONSTACK 0x08000000
+#define LSA_RESTART 0x10000000
+#define LSA_NODEFER 0x40000000
+#define LSA_RESETHAND 0x80000000
+
+#define LSIG_ERR ((void (*)(int))-1)
+#define LSIG_DFL ((void (*)(int)) 0)
+#define LSIG_IGN ((void (*)(int)) 1)
+
+#define LSIGHUP 1
+#define LSIGINT 2
+#define LSIGQUIT 3
+#define LSIGILL 4
+#define LSIGTRAP 5
+#define LSIGABRT 6
+#define LSIGIOT SIGABRT
+#define LSIGBUS 7
+#define LSIGFPE 8
+#define LSIGKILL 9
+#define LSIGUSR1 10
+#define LSIGSEGV 11
+#define LSIGUSR2 12
+#define LSIGPIPE 13
+#define LSIGALRM 14
+#define LSIGTERM 15
+#define LSIGSTKFLT 16
+#define LSIGCHLD 17
+#define LSIGCONT 18
+#define LSIGSTOP 19
+#define LSIGTSTP 20
+#define LSIGTTIN 21
+#define LSIGTTOU 22
+#define LSIGURG 23
+#define LSIGXCPU 24
+#define LSIGXFSZ 25
+#define LSIGVTALRM 26
+#define LSIGPROF 27
+#define LSIGWINCH 28
+#define LSIGIO 29
+#define LSIGPOLL SIGIO
+#define LSIGPWR 30
+#define LSIGSYS 31
+#define LSIGUNUSED SIGSYS
+#define L_NSIG 32
+
+typedef int linux_pid_t;
+typedef unsigned linux_uid_t;
+typedef long linux_clock_t;
+
+typedef struct {
+ unsigned long bits[128 / sizeof (uint64_t)];
+} linux_sigset_t;
+
+union linux_sigval {
+ int sival_int;
+ void *sival_ptr;
+};
+
+typedef struct {
+ int32_t lsi_signo, lsi_errno, lsi_code;
+ union {
+ char __pad[128 - 2*sizeof(int32_t) - sizeof(int64_t)];
+ struct {
+ union {
+ struct {
+ linux_pid_t lsi_pid;
+ linux_uid_t lsi_uid;
+ } __piduid;
+ struct {
+ int32_t lsi_timerid;
+ int32_t lsi_overrun;
+ } __timer;
+ } __first;
+ union {
+ union linux_sigval lsi_value;
+ struct {
+ int32_t lsi_status;
+ linux_clock_t lsi_utime, lsi_stime;
+ } __sigchld;
+ } __second;
+ } __si_common;
+ struct {
+ void *lsi_addr;
+ int16_t lsi_addr_lsb;
+ union {
+ struct {
+ void *lsi_lower;
+ void *lsi_upper;
+ } __addr_bnd;
+ uint32_t lsi_pkey;
+ } __first;
+ } __sigfault;
+ struct {
+ int64_t lsi_band;
+ int32_t lsi_fd;
+ } __sigpoll;
+ struct {
+ void *lsi_call_addr;
+ int32_t lsi_syscall;
+ uint32_t lsi_arch;
+ } __sigsys;
+ } __si_fields;
+} linux_siginfo_t;
+
+struct linux_sigaction {
+ union {
+ void (*lsa_handler)(int);
+ void (*lsa_sigaction)(int, linux_siginfo_t *, void *);
+ } __lsa_handler;
+ linux_sigset_t lsa_mask;
+ int lsa_flags;
+ void *lsa_restorer;
+};
+
+struct signal_handler {
+ uint64_t handler;
+};
+
+static struct signal_handler signals[L_NSIG];
+
+static void signal_handler (int sig);
+
+static void sigset_from_linux (sigset_t *out, const linux_sigset_t *in)
+{
+ (void)out;
+ (void)in;
+ // TODO
+}
+
+static void sigset_to_linux (linux_sigset_t *out, const sigset_t *in)
+{
+ (void)out;
+ (void)in;
+ // TODO
+}
+
+static int sa_flags_from_linux (int in)
+{
+ // TODO
+ return in;
+}
+
+static int sa_flags_to_linux (int in)
+{
+ // TODO
+ return in;
+}
+
+static void sigaction_from_linux (int lsig, struct sigaction *out, const struct linux_sigaction *in)
+{
+ void (*h)(int) = in->__lsa_handler.lsa_handler;
+
+ if (h == LSIG_ERR) {
+ out->sa_handler = SIG_ERR;
+ } else if (h == LSIG_DFL) {
+ out->sa_handler = SIG_DFL;
+ } else if (h == LSIG_IGN) {
+ out->sa_handler = SIG_IGN;
+ } else {
+ signals[lsig].handler = (uint64_t)in->__lsa_handler.lsa_handler;
+ out->sa_handler = signal_handler;
+ }
+
+ sigset_from_linux (&out->sa_mask, &in->lsa_mask);
+ out->sa_flags = sa_flags_from_linux (in->lsa_flags);
+}
+
+static void sigaction_to_linux (int lsig, struct linux_sigaction *out, const struct sigaction *in)
+{
+ void (*h)(int) = in->sa_handler;
+
+ if (h == SIG_ERR) {
+ out->__lsa_handler.lsa_handler = LSIG_ERR;
+ } else if (h == SIG_DFL) {
+ out->__lsa_handler.lsa_handler = LSIG_DFL;
+ } else if (h == SIG_IGN) {
+ out->__lsa_handler.lsa_handler = LSIG_IGN;
+ } else {
+ out->__lsa_handler.lsa_handler = (void *)signals[lsig].handler;
+ }
+
+ sigset_to_linux (&out->lsa_mask, &in->sa_mask);
+ out->lsa_flags = sa_flags_to_linux (in->sa_flags);
+ out->lsa_restorer = NULL;
+}
+
+static int signum_from_linux (int sig)
+{
+ static const int signals[L_NSIG] = {
+ [LSIGHUP] = SIGHUP,
+ [LSIGINT] = SIGINT,
+ [LSIGQUIT] = SIGQUIT,
+ [LSIGILL] = SIGILL,
+ [LSIGTRAP] = SIGTRAP,
+ [LSIGABRT] = SIGABRT,
+ [LSIGBUS] = SIGBUS,
+ [LSIGFPE] = SIGFPE,
+ [LSIGKILL] = SIGKILL,
+ [LSIGUSR1] = SIGUSR1,
+ [LSIGSEGV] = SIGSEGV,
+ [LSIGUSR2] = SIGUSR2,
+ [LSIGPIPE] = SIGPIPE,
+ [LSIGALRM] = SIGALRM,
+ [LSIGTERM] = SIGTERM,
+ [LSIGSTKFLT] = SIGSEGV,
+ [LSIGCHLD] = SIGCHLD,
+ [LSIGCONT] = SIGCONT,
+ [LSIGSTOP] = SIGSTOP,
+ [LSIGTSTP] = SIGTSTP,
+ [LSIGTTIN] = SIGTTIN,
+ [LSIGTTOU] = SIGTTOU,
+ [LSIGURG] = SIGURG,
+ [LSIGXCPU] = SIGXCPU,
+ [LSIGXFSZ] = SIGXFSZ,
+ [LSIGVTALRM] = SIGVTALRM,
+ [LSIGPROF] = SIGPROF,
+ [LSIGWINCH] = SIGWINCH,
+ [LSIGIO] = SIGIO,
+ [LSIGPWR] = SIGIO,
+ [LSIGSYS] = SIGSYS,
+ };
+
+ return sig >= 0 && sig <= L_NSIG ? signals[sig] : 0;
+}
+
+static int signum_to_linux (int sig)
+{
+ static const int signals[] = {
+ [SIGHUP] = LSIGHUP,
+ [SIGINT] = LSIGINT,
+ [SIGQUIT] = LSIGQUIT,
+ [SIGILL] = LSIGILL,
+ [SIGTRAP] = LSIGTRAP,
+ [SIGABRT] = LSIGABRT,
+ [SIGBUS] = LSIGBUS,
+ [SIGFPE] = LSIGFPE,
+ [SIGKILL] = LSIGKILL,
+ [SIGUSR1] = LSIGUSR1,
+ [SIGSEGV] = LSIGSEGV,
+ [SIGUSR2] = LSIGUSR2,
+ [SIGPIPE] = LSIGPIPE,
+ [SIGALRM] = LSIGALRM,
+ [SIGTERM] = LSIGTERM,
+ //[SIGSTKFLT] = LSIGSTKFLT,
+ [SIGCHLD] = LSIGCHLD,
+ [SIGCONT] = LSIGCONT,
+ [SIGSTOP] = LSIGSTOP,
+ [SIGTSTP] = LSIGTSTP,
+ [SIGTTIN] = LSIGTTIN,
+ [SIGTTOU] = LSIGTTOU,
+ [SIGURG] = LSIGURG,
+ [SIGXCPU] = LSIGXCPU,
+ [SIGXFSZ] = LSIGXFSZ,
+ [SIGVTALRM] = LSIGVTALRM,
+ [SIGPROF] = LSIGPROF,
+ [SIGWINCH] = LSIGWINCH,
+ [SIGIO] = LSIGIO,
+ //[SIGPWR] = LSIGPWR,
+ [SIGSYS] = LSIGSYS,
+ };
+
+ return signals[sig];
+}
+
+// TODO: mask signals
+static void signal_handler (int sig)
+{
+ int lsig;
+
+ lsig = signum_to_linux (sig);
+
+ debug ("Received signal %d (%d).", sig, lsig);
+
+ cpu_enter_signal (lsig, signals[sig].handler);
+}
+
+int mysigaction (int lsig, const void *xact, void *xoact)
+{
+ const struct linux_sigaction *lact = xact;
+ struct linux_sigaction *loact = xoact;
+ struct sigaction act, oact;
+ int sig, ret;
+
+
+ if ((lact->lsa_flags & LSA_SIGINFO) == LSA_SIGINFO) {
+ error ("sigaction() with SA_SIGINFO not supported");
+ errno = ENOSYS;
+ return -1;
+ }
+
+ sig = signum_from_linux (lsig);
+
+ debug ("Registering signal %d (%d).", lsig, sig);
+
+ if (lact != NULL)
+ sigaction_from_linux (lsig, &act, lact);
+
+ ret = sigaction (sig, lact != NULL ? &act : NULL, loact != NULL ? &oact : NULL);
+
+ if (loact != NULL)
+ sigaction_to_linux (lsig, loact, &oact);
+
+ return ret;
+}