[kernel] Allow 7+ argument syscalls
The syscall interface is designed to closely follow the System V amd64 calling convention, so that as much as possible, the call into the assembly trampoline for the syscall sets up the call correctly. Before this change, the only exception was using r10 (a caller-saved register already) to stash the contents of rcx, which gets clobbered by the syscall instruction. However, this only preserves registers for the function call, as the stack is switched upon kernel entry, and additional call frames have been added by the time the syscall gets back into C++ land. This change adds a new parameter to the syscall in rbx. Since rbx is callee-saved, the syscall trampoline pushes it to the stack, and then puts the address of the stack-passed arguments into rbx. Now that the syscall implementations are wrapped in the _syscall_verify_* functions, we can piggy-back on those to also set up the extra arguments from the user stack. Now, for any syscall with 7 or more arguments, the verify wrapper takes the first six arguments normally, then gets a stack pointer (the rbx value) as its 7th and final argument. It's then the job of the verify wrapper to get the remaining arguments from that stack pointer and pass them to the implementation function as normal arguments.
This commit is contained in:
@@ -28,6 +28,14 @@ namespace {
|
||||
return reinterpret_cast<uintptr_t>(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 <typename T>
|
||||
inline T pop_from(uint64_t *&sp) {
|
||||
return *reinterpret_cast<T*>(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]}))")
|
||||
|
||||
Reference in New Issue
Block a user