diff options
author | dzwdz | 2024-08-02 01:20:40 +0200 |
---|---|---|
committer | dzwdz | 2024-08-02 01:20:40 +0200 |
commit | e818cab3f1fc4a3d4d0b8e2c9424fb2e7b1dff70 (patch) | |
tree | 5d59d2e0ea74253f5b265cdd542b74daca6dce5a /src/kernel/arch | |
parent | 1890868af4b8cf2593a4b0831e2fc69a44ec680b (diff) |
*: use a generic UserRegs type everywhere I'm storing registers
mostly inspired by Plan 9's Ureg, probably obvious from the name
Diffstat (limited to 'src/kernel/arch')
-rw-r--r-- | src/kernel/arch/amd64/regs.c | 26 | ||||
-rw-r--r-- | src/kernel/arch/amd64/sysenter.c | 13 | ||||
-rw-r--r-- | src/kernel/arch/amd64/sysenter.h | 11 | ||||
-rw-r--r-- | src/kernel/arch/generic.h | 7 |
4 files changed, 47 insertions, 10 deletions
diff --git a/src/kernel/arch/amd64/regs.c b/src/kernel/arch/amd64/regs.c new file mode 100644 index 0000000..bb4e5aa --- /dev/null +++ b/src/kernel/arch/amd64/regs.c @@ -0,0 +1,26 @@ +#include <kernel/arch/generic.h> +#include <kernel/panic.h> + +void +regs_safecopy(UserRegs *dst, const UserRegs *src) +{ + /* 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 + ); + + uint64_t newflags = (src->flags & 0xCD5) | (dst->flags & ~0xCD5); + /* I "spelled it out" directly instead of using memcpy hoping that gcc + * maybe would notice it can skip copying the last 8 bytes. It didn't :( */ + *dst = *src; + dst->flags = newflags; +} diff --git a/src/kernel/arch/amd64/sysenter.c b/src/kernel/arch/amd64/sysenter.c index 5a96e33..2f83e3d 100644 --- a/src/kernel/arch/amd64/sysenter.c +++ b/src/kernel/arch/amd64/sysenter.c @@ -2,17 +2,20 @@ #include <kernel/arch/amd64/sysenter.h> #include <kernel/arch/generic.h> #include <kernel/proc.h> +#include <shared/mem.h> -CpuRegs _sysexit_regs; +SysexitRegs _sysexit_regs; -_Noreturn void sysexit(CpuRegs regs) { - _sysexit_regs = regs; +_Noreturn void sysexit(UserRegs *regs, char sse[512]) { + _sysexit_regs.u = *regs; + memcpy(_sysexit_regs.sse, sse, 512); _sysexit_real(); } _Noreturn void sysenter_stage2(void) { - CpuRegs *regs = &proc_cur->regs; - *regs = _sysexit_regs; + UserRegs *regs = &proc_cur->regs; + *regs = _sysexit_regs.u; + memcpy(proc_cur->sse, _sysexit_regs.sse, 512); _syscall(regs->rdi, regs->rsi, regs->rdx, regs->r10, regs->r8, regs->r9); proc_switch_any(); } diff --git a/src/kernel/arch/amd64/sysenter.h b/src/kernel/arch/amd64/sysenter.h index 03a9f45..65c46f8 100644 --- a/src/kernel/arch/amd64/sysenter.h +++ b/src/kernel/arch/amd64/sysenter.h @@ -1,9 +1,14 @@ #pragma once #include <kernel/types.h> -// sysenter.c -extern CpuRegs _sysexit_regs; +typedef struct SysexitRegs SysexitRegs; +struct SysexitRegs { + UserRegs u; + char sse[512]; +}; +_Static_assert(sizeof(SysexitRegs) == 18 * 8 + 512); + +extern SysexitRegs _sysexit_regs; _Noreturn void sysenter_stage2(void); -// sysenter.s _Noreturn void _sysexit_real(void); diff --git a/src/kernel/arch/generic.h b/src/kernel/arch/generic.h index a6a14c9..c9431eb 100644 --- a/src/kernel/arch/generic.h +++ b/src/kernel/arch/generic.h @@ -27,8 +27,7 @@ uint64_t uptime_ns(void); void timer_schedule(Proc *p, uint64_t ns); void timer_deschedule(Proc *p); -// src/arch/i386/sysenter.s -_Noreturn void sysexit(CpuRegs); +_Noreturn void sysexit(UserRegs *, char sse[512]); // all of those can allocate memory Pagedir *pagedir_new(void); @@ -52,3 +51,7 @@ int kprintf(const char *fmt, ...); void *debug_caller(size_t depth); void debug_stacktrace(void); + +/** "Applies" an UserRegs struct received from userland over another UserRegs + * without overriding privileged registers. */ +void regs_safecopy(UserRegs *, const UserRegs *); |