This file is just the generated cap flag constants. Move it to not collide with more capability code to be added.
205 lines
6.3 KiB
C++
205 lines
6.3 KiB
C++
// vim: ft=cpp
|
|
|
|
#include <stdint.h>
|
|
#include <arch/memory.h>
|
|
#include <j6/cap_flags.h>
|
|
#include <j6/errors.h>
|
|
#include <j6/types.h>
|
|
#include <util/counted.h>
|
|
|
|
#include "profiler.h"
|
|
#include "syscalls/helpers.h"
|
|
|
|
/*[[[cog code generation
|
|
from definitions.context import Context
|
|
|
|
ctx = Context(definitions_path)
|
|
ctx.parse("syscalls.def")
|
|
syscalls = ctx.interfaces["syscalls"]
|
|
|
|
for obj in syscalls.exposes:
|
|
cog.outl(f'#include "objects/{obj.cname}.h"')
|
|
]]]*/
|
|
//[[[end]]]
|
|
|
|
|
|
/*[[[cog code generation
|
|
cog.outl(f'constexpr size_t syscall_count = {len(syscalls.methods)};')
|
|
]]]*/
|
|
//[[[end]]]
|
|
DECLARE_PROFILE_CLASS(syscall_profiles, syscall_count);
|
|
namespace {
|
|
enum class req { required, optional, zero_ok };
|
|
|
|
template <typename T>
|
|
__attribute__((always_inline))
|
|
inline bool range_check(const T* param) {
|
|
return reinterpret_cast<uintptr_t>(param) < arch::kernel_offset;
|
|
}
|
|
|
|
template <typename T>
|
|
__attribute__((always_inline))
|
|
inline bool check_refparam(const T* param, req required) {
|
|
return range_check(param) && ((required == req::optional) || param);
|
|
}
|
|
|
|
template <typename T>
|
|
__attribute__((always_inline))
|
|
inline bool check_refparam(const T* param, size_t len, req required) {
|
|
bool nullok = (required == req::optional) || (required == req::zero_ok && !len);
|
|
return range_check(param) && (param || nullok);
|
|
}
|
|
|
|
template <typename T>
|
|
__attribute__((always_inline))
|
|
inline bool check_refparam(const T* param, size_t *len, req required) {
|
|
if (!range_check(len)) return false;
|
|
if (len) return check_refparam(param, *len, required);
|
|
// if len is null but param is not, call that invalid.
|
|
else return !param && required == req::optional;
|
|
}
|
|
|
|
// 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++);
|
|
}
|
|
}
|
|
|
|
DEFINE_PROFILE_CLASS(syscall_profiles);
|
|
|
|
namespace syscalls {
|
|
|
|
using util::buffer;
|
|
|
|
/*[[[cog code generation
|
|
cbool = {True: "true", False: "false"}
|
|
|
|
def get_caps(opts, type):
|
|
caps = opts.get("cap", list())
|
|
return [f"j6_cap_{type.name}_{c}" for c in caps]
|
|
|
|
for id, scope, method in syscalls.methods:
|
|
if scope:
|
|
name = f"{scope.name}_{method.name}"
|
|
else:
|
|
name = f"{method.name}"
|
|
|
|
args = []
|
|
argdefs = []
|
|
cxxargdefs = []
|
|
refparams = []
|
|
|
|
handles = []
|
|
objparams = []
|
|
|
|
if method.constructor:
|
|
argdefs.append(("j6_handle_t *", "self"))
|
|
cxxargdefs.append("j6_handle_t *self")
|
|
args.append("self")
|
|
refparams.append(("self", "required"))
|
|
|
|
elif not method.static:
|
|
argdefs.append(("j6_handle_t", "self"))
|
|
|
|
if "handle" in method.options:
|
|
args.append("self_handle")
|
|
cxxargdefs.append(f"obj::handle *self_handle")
|
|
else:
|
|
args.append("self_obj")
|
|
cxxargdefs.append(f"obj::{scope.cname} *self")
|
|
objparams.append((f"obj::{scope.cname} *", "self"))
|
|
|
|
handles.append((scope.cname, "self", get_caps(method.options, scope)))
|
|
|
|
for param in method.params:
|
|
needs_obj = param.type.needs_object(param.options)
|
|
needs_handle = ("handle" in param.options) or needs_obj
|
|
|
|
for type, suffix in param.type.c_names(param.options):
|
|
arg = f"{param.name}{suffix}"
|
|
argdefs.append((type, arg))
|
|
|
|
for type, suffix in param.type.cxx_names(param.options):
|
|
arg = f"{param.name}{suffix}"
|
|
|
|
if needs_handle:
|
|
handles.append((param.type.object.cname, arg, get_caps(param.options, param.type.object)))
|
|
if needs_obj:
|
|
objparams.append((type, arg))
|
|
args.append(f"{arg}_obj")
|
|
cxxargdefs.append(f"{type} {arg}")
|
|
else:
|
|
args.append(f"{arg}_handle")
|
|
cxxargdefs.append(f"obj::handle *{arg}_handle")
|
|
break
|
|
else:
|
|
cxxargdefs.append(f"{type} {arg}")
|
|
args.append(arg)
|
|
|
|
if not needs_handle and param.caps:
|
|
handles.append((
|
|
f"obj::{param.type.object.cname}",
|
|
arg, get_caps(param.options, param.type.object)))
|
|
|
|
if param.refparam:
|
|
subs = param.type.c_names(param.options)
|
|
checkargs = map(lambda x: f"{param.name}{x[1]}", subs)
|
|
|
|
refparams.append((", ".join(checkargs), 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"
|
|
|
|
attr = ""
|
|
if "noreturn" in method.options:
|
|
attr = "[[noreturn]] "
|
|
|
|
cog.outl(f"""{attr}j6_status_t {name} ({", ".join(cxxargdefs)});""")
|
|
cog.outl(f"""{attr}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 checkargs, optional in refparams:
|
|
cog.outl(f" if (!check_refparam({checkargs}, req::{optional}))")
|
|
cog.outl( " return j6_err_invalid_arg;")
|
|
cog.outl()
|
|
|
|
for type, arg, caps in handles:
|
|
cog.outl(f" obj::handle *{arg}_handle = get_handle<typename obj::{type}>({arg});")
|
|
cog.outl(f" if (!{arg}_handle) return j6_err_invalid_arg;")
|
|
|
|
if caps:
|
|
allcaps = " | ".join(caps)
|
|
cog.outl(f" j6_cap_t {arg}_caps_req = {allcaps};")
|
|
cog.outl(f" if (!{arg}_handle->has_cap({arg}_caps_req)) return j6_err_denied;")
|
|
|
|
for type, arg in objparams:
|
|
if type.endswith('*'):
|
|
type = type[:-1].strip()
|
|
|
|
cog.outl(f" {type} *{arg}_obj = {arg}_handle->as<typename {type}>();")
|
|
cog.outl(f" if (!{arg}_obj) return j6_err_invalid_arg;")
|
|
cog.outl()
|
|
|
|
if "noreturn" in method.options:
|
|
cog.outl(f""" {name}({", ".join(args)});""")
|
|
else:
|
|
cog.outl(f""" profiler<syscall_profiles, {id}> profile {{"{name}"}};""")
|
|
cog.outl(f""" return {name}({", ".join(args)});""")
|
|
cog.outl("}")
|
|
cog.outl("\n")
|
|
]]]*/
|
|
//[[[end]]]
|
|
|
|
} // namespace syscalls
|