diff options
author | dzwdz | 2024-07-26 21:40:57 +0200 |
---|---|---|
committer | dzwdz | 2024-07-26 21:40:57 +0200 |
commit | 58514d351e1f0e8871f534422cf025109ddbb844 (patch) | |
tree | 43c91a3c6c325649be2f07f2a38d0753f0a68cf7 | |
parent | 69fd0dd9fda47aa52cccdbef6ca388cea38e693b (diff) |
kernel: implement _sys_intr_return
-rw-r--r-- | src/cmd/shell/shell.c | 1 | ||||
-rw-r--r-- | src/kernel/proc.c | 1 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 41 | ||||
-rw-r--r-- | src/libc/syscall.c | 4 | ||||
-rw-r--r-- | src/libk/include/camellia/syscalls.h | 3 | ||||
-rw-r--r-- | src/libk/include/camellia/types.h | 5 |
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 */ }; |