diff --git a/src/kernel/syscall.cpp.cog b/src/kernel/syscall.cpp.cog index 663be99..e93acd2 100644 --- a/src/kernel/syscall.cpp.cog +++ b/src/kernel/syscall.cpp.cog @@ -49,6 +49,9 @@ namespace syscalls for type, suffix in param.type.c_names(param.options): args.append(f"{type} {param.name}{suffix}") + if len(args) > 6: + args = args[:6] + ["uint64_t *sp"] + cog.outl(f"""j6_status_t _syscall_verify_{name} ({", ".join(args)});""") ]]]*/ //[[[end]]] diff --git a/src/kernel/syscall.s b/src/kernel/syscall.s index b442fba..a0f0998 100644 --- a/src/kernel/syscall.s +++ b/src/kernel/syscall.s @@ -50,6 +50,11 @@ syscall_handler_prelude: push r14 push r15 + ; if we've got more than 6 arguments, the rest + ; are on the user stack, and pointed to by rbx. + ; push rbx so that it's the 7th argument. + push rbx + inc qword [rel __counter_syscall_enter] cmp rax, NUM_SYSCALLS @@ -62,6 +67,8 @@ syscall_handler_prelude: call r11 + add rsp, 8 ; account for passing rbx on the stack + inc qword [rel __counter_syscall_sysret] jmp kernel_to_user_trampoline diff --git a/src/kernel/syscall_verify.cpp.cog b/src/kernel/syscall_verify.cpp.cog index 058587e..97390b0 100644 --- a/src/kernel/syscall_verify.cpp.cog +++ b/src/kernel/syscall_verify.cpp.cog @@ -28,6 +28,14 @@ namespace { return reinterpret_cast(param) < arch::kernel_offset && (optional || param); } + + // When called with more than 6 arguments, the 7th argument to the + // verify function is the stack pointer holding the rest. "Pop" them + // into variables to be passed normally with pop_from. + template + inline T pop_from(uint64_t *&sp) { + return *reinterpret_cast(sp++); + } } namespace syscalls { @@ -56,13 +64,13 @@ for id, scope, method in syscalls.methods: objparams = [] if method.constructor: - argdefs.append("j6_handle_t *self") + argdefs.append(("j6_handle_t *", "self")) cxxargdefs.append("j6_handle_t *self") args.append("self") refparams.append(("self", False)) elif not method.static: - argdefs.append("j6_handle_t self") + argdefs.append(("j6_handle_t", "self")) cxxargdefs.append(f"obj::{scope.cname} *self") args.append("self_obj") @@ -75,7 +83,7 @@ for id, scope, method in syscalls.methods: for type, suffix in param.type.c_names(param.options): arg = f"{param.name}{suffix}" - argdefs.append(f"{type} {arg}") + argdefs.append((type, arg)) for type, suffix in param.type.cxx_names(param.options): arg = f"{param.name}{suffix}" @@ -101,8 +109,20 @@ for id, scope, method in syscalls.methods: for sub in subs[1:]: refparams.append((param.name + sub[1], param.optional)) + first_args = ", ".join(map(lambda x: f"{x[0]} {x[1]}", argdefs[:6])) + extra_argdefs = argdefs[6:] + + if extra_argdefs: + first_args += ", uint64_t *sp" + cog.outl(f"""j6_status_t {name} ({", ".join(cxxargdefs)});""") - cog.outl(f"""j6_status_t _syscall_verify_{name} ({", ".join(argdefs)}) {{""") + cog.outl(f"""j6_status_t _syscall_verify_{name} ({first_args}) {{""") + + for type, arg in extra_argdefs: + cog.outl(f" {type} {arg} = pop_from<{type}>(sp);") + + if extra_argdefs: + cog.outl() for pname, optional in refparams: cog.outl(f" if (!check_refparam({pname}, {cbool[optional]}))") diff --git a/src/libraries/j6/syscalls.s.cog b/src/libraries/j6/syscalls.s.cog index b1b9250..279d89c 100644 --- a/src/libraries/j6/syscalls.s.cog +++ b/src/libraries/j6/syscalls.s.cog @@ -6,6 +6,15 @@ push rbp mov rbp, rsp + ; if the syscall has more than 6 arguments, the rest + ; will be pushed on the stack. in that case, we'd need + ; to pass this stack pointer to the kernel, so stash + ; off rbx (callee-saved) and pass the pointer to the + ; arguments there. + push rbx + mov rbx, rbp + add rbx, 16 ; account for stack frame + ; args should already be in rdi, etc, but rcx will ; get stomped, so stash it in r10, which isn't a ; callee-saved register, but also isn't used in the @@ -16,6 +25,7 @@ syscall ; result is now already in rax, so just return + pop rbx pop rbp ret %endmacro