Files
jsix_import/src/kernel/syscall.cpp.cog
Justin C. Miller b6218a1121 [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.
2022-01-30 12:25:11 -08:00

87 lines
2.0 KiB
C++

// vim: ft=cpp
#include <stddef.h>
#include <string.h>
#include "debug.h"
#include "logger.h"
#include "syscall.h"
extern "C" {
void syscall_invalid(uint64_t call);
}
size_t __counter_syscall_enter = 0;
size_t __counter_syscall_sysret = 0;
/*[[[cog code generation
from definitions.context import Context
ctx = Context(definitions_path)
ctx.parse("syscalls.def")
syscalls = ctx.interfaces['syscalls']
]]]*/
/// [[[end]]]
namespace syscalls
{
/*[[[cog code generation
last_scope = None
for id, scope, method in syscalls.methods:
if scope != last_scope:
cog.outl()
last_scope = scope
if scope:
name = f"{scope.name}_{method.name}"
else:
name = method.name
args = []
if method.constructor:
args.append("j6_handle_t *self")
elif not method.static:
args.append("j6_handle_t self")
for param in method.params:
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]]]
}
uintptr_t syscall_registry[num_syscalls] __attribute__((section(".syscall_registry")));
void
syscall_invalid(uint64_t call)
{
log::warn(logs::syscall, "Received unknown syscall: %02x\n", call);
}
void
syscall_initialize()
{
memset(&syscall_registry, 0, sizeof(syscall_registry));
/*[[[cog code generation
for id, scope, method in syscalls.methods:
if scope:
name = f"{scope.name}_{method.name}"
else:
name = method.name
cog.outl(f"syscall_registry[{id}] = reinterpret_cast<uintptr_t>(syscalls::_syscall_verify_{name});")
cog.outl(f"""log::debug(logs::syscall, "Enabling syscall {id:02x} as {name}");""")
cog.outl("")
]]]*/
//[[[end]]]
}