// 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(bool enable_test)
{
    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

        indent = ""
        if "test" in method.options:
            cog.outl("if (enable_test) {")
            indent = "    "

        cog.outl(f"{indent}syscall_registry[{id}] = reinterpret_cast<uintptr_t>(syscalls::_syscall_verify_{name});")
        cog.outl(f"""{indent}log::spam(logs::syscall, "Enabling syscall {id:02x} as {name}");""")

        if "test" in method.options:
            cog.outl("}")

        cog.outl("")
    ]]]*/
    //[[[end]]]
}

