summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/shell/shell.c1
-rw-r--r--src/kernel/proc.c1
-rw-r--r--src/kernel/syscalls.c41
-rw-r--r--src/libc/syscall.c4
-rw-r--r--src/libk/include/camellia/syscalls.h3
-rw-r--r--src/libk/include/camellia/types.h5
6 files changed, 52 insertions, 3 deletions
diff --git a/src/cmd/shell/shell.c b/src/cmd/shell/shell.c
index 15cb6ed..bdf36a9 100644
--- a/src/cmd/shell/shell.c
+++ b/src/cmd/shell/shell.c
@@ -141,6 +141,7 @@ static void run(char *cmd) {
static void intr(struct intr_data *intr) {
fprintf(stderr, "%s: got interrupt: %s\n", getprogname(), intr->msg);
+ _sys_intr_return(intr, 0);
}
int main(int argc, char **argv) {
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index 350f3ee..8be1080 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -413,6 +413,7 @@ static void proc_intr_deliver(Proc *p) {
d.rcx = p->regs.rcx;
d.rax = p->regs.rax;
d.rip = p->regs.rip;
+ d.flags = p->regs.flags;
// one more because the buffer itself isn't NUL terminated
// TODO ensure NUL termination
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 23a8883..ffd69b8 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -487,6 +487,46 @@ long _sys_duplex(hid_t from, hid_t to, int flags) {
return -1; // dummy
}
+void _sys_intr_return(struct intr_data __user *intr, int flags) {
+ CpuRegs *r = &proc_cur->regs;
+ struct intr_data d;
+ if (flags != 0 || pcpy_from(proc_cur, &d, intr, sizeof(d)) < sizeof(d)) {
+ proc_kill(proc_cur, EFAULT);
+ proc_switch_any(); /* doesn't return */
+ }
+ r->r15 = d.r15;
+ r->r14 = d.r14;
+ r->r13 = d.r13;
+ r->r12 = d.r12;
+ r->r11 = d.r11;
+ r->r10 = d.r10;
+ r->r9 = d.r9;
+ r->r8 = d.r8;
+ r->rdi = d.rdi;
+ r->rsi = d.rsi;
+ r->rbp = d.rbp;
+ r->rsp = d.rsp;
+ r->rbx = d.rbx;
+ r->rdx = d.rdx;
+ r->rcx = d.rcx;
+ r->rax = d.rax;
+ r->rip = d.rip;
+ /* preserved flags: (see intel vol 1 3.4.3.)
+ * 1<<0 = CF, carry flag
+ * 1<<2 = PF, parity flag
+ * 1<<4 = AC, auxilary carry
+ * 1<<6 = ZF, zero flag
+ * 1<<7 = SF, sign flag
+ * 1<<11 = OF, overflow flag
+ * 1<<10 = DF, direction flag
+ */
+ static_assert(
+ ((1<<0) | (1<<2) | (1<<4) | (1<<6) | (1<<7) | (1<<10) | (1<<11))
+ == 0xCD5
+ );
+ r->flags = (d.flags & 0xCD5) | (r->flags & ~0xCD5);
+}
+
long _sys_execbuf(void __user *ubuf, size_t len) {
if (len == 0) SYSCALL_RETURN(0);
static_assert(EXECBUF_MAX_LEN <= KMALLOC_MAX);
@@ -544,6 +584,7 @@ long _syscall(long num, long a, long b, long c, long d, long e) {
break; case _SYS_TIME: _sys_time(a);
break; case _SYS_GETNULL: _sys_getnull(a);
break; case _SYS_DUPLEX: _sys_duplex(a, b, c);
+ break; case _SYS_INTR_RETURN: _sys_intr_return((userptr_t)a, b);
break; case _SYS_EXECBUF: _sys_execbuf((userptr_t)a, b);
break; case _SYS_DEBUG_KLOG: _sys_debug_klog((userptr_t)a, b);
break;
diff --git a/src/libc/syscall.c b/src/libc/syscall.c
index c6e3762..023a7bb 100644
--- a/src/libc/syscall.c
+++ b/src/libc/syscall.c
@@ -102,6 +102,10 @@ long _sys_duplex(hid_t from, hid_t to, int flags) {
return _syscall(_SYS_DUPLEX, (long)from, (long)to, (long)flags, 0, 0);
}
+void _sys_intr_return(struct intr_data __user *intr, int flags) {
+ return (void)_syscall(_SYS_INTR_RETURN, (long)intr, (long)flags, 0, 0, 0);
+}
+
long _sys_execbuf(void __user *buf, size_t len) {
return _syscall(_SYS_EXECBUF, (long)buf, (long)len, 0, 0, 0);
}
diff --git a/src/libk/include/camellia/syscalls.h b/src/libk/include/camellia/syscalls.h
index 16576e0..628a511 100644
--- a/src/libk/include/camellia/syscalls.h
+++ b/src/libk/include/camellia/syscalls.h
@@ -24,6 +24,7 @@
#define _SYS_TIME 23
#define _SYS_GETNULL 24
#define _SYS_DUPLEX 25
+#define _SYS_INTR_RETURN 26
#define _SYS_EXECBUF 100
#define _SYS_DEBUG_KLOG 101
@@ -92,6 +93,8 @@ hid_t _sys_getnull(int flags);
long _sys_duplex(hid_t from, hid_t to, int flags);
+void _sys_intr_return(struct intr_data __user *intr, int flags);
+
/* see shared/execbuf.h */
long _sys_execbuf(void __user *buf, size_t len);
diff --git a/src/libk/include/camellia/types.h b/src/libk/include/camellia/types.h
index 9cbd386..86ffb56 100644
--- a/src/libk/include/camellia/types.h
+++ b/src/libk/include/camellia/types.h
@@ -36,12 +36,11 @@ struct intr_data {
/* same order as CpuRegs.
* notable omissions:
* - SSE registers (usually there's no need to save them, userland can do
- * that itself if it wants)
- * - FLAGS (so the kernel doesn't need to care about sanitizing it) */
+ * that itself if it wants) */
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rdi, rsi;
userptr_t rbp, rsp;
- uint64_t rbx, rdx, rcx, rax, rip;
+ uint64_t rbx, rdx, rcx, rax, rip, flags;
char msg[]; /* variable size, NUL terminated */
};