Update scripts in the build folder to pass all enabled `ruff` checks. Signed-off-by: Jordan Yates <jordan@embeint.com>
628 lines
20 KiB
Python
Executable File
628 lines
20 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2017 Intel Corporation
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
"""
|
|
Script to generate system call invocation macros
|
|
|
|
This script parses the system call metadata JSON file emitted by
|
|
parse_syscalls.py to create several files:
|
|
|
|
- A file containing weak aliases of any potentially unimplemented system calls,
|
|
as well as the system call dispatch table, which maps system call type IDs
|
|
to their handler functions.
|
|
|
|
- A header file defining the system call type IDs, as well as function
|
|
prototypes for all system call handler functions.
|
|
|
|
- A directory containing header files. Each header corresponds to a header
|
|
that was identified as containing system call declarations. These
|
|
generated headers contain the inline invocation functions for each system
|
|
call in that header.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
# Some kernel headers cannot include automated tracing without causing unintended recursion or
|
|
# other serious issues.
|
|
# These headers typically already have very specific tracing hooks for all relevant things
|
|
# written by hand so are excluded.
|
|
notracing = ["kernel.h", "zephyr/kernel.h", "errno_private.h", "zephyr/errno_private.h"]
|
|
|
|
types64 = ["int64_t", "uint64_t"]
|
|
|
|
# The kernel linkage is complicated. These functions from
|
|
# userspace_handlers.c are present in the kernel .a library after
|
|
# userspace.c, which contains the weak fallbacks defined here. So the
|
|
# linker finds the weak one first and stops searching, and thus won't
|
|
# see the real implementation which should override. Yet changing the
|
|
# order runs afoul of a comment in CMakeLists.txt that the order is
|
|
# critical. These are core syscalls that won't ever be unconfigured,
|
|
# just disable the fallback mechanism as a simple workaround.
|
|
noweak = ["z_mrsh_k_object_release", "z_mrsh_k_object_access_grant", "z_mrsh_k_object_alloc"]
|
|
|
|
table_template = """/* auto-generated by gen_syscalls.py, don't edit */
|
|
|
|
#include <zephyr/llext/symbol.h>
|
|
|
|
/* Weak handler functions that get replaced by the real ones unless a system
|
|
* call is not implemented due to kernel configuration.
|
|
*/
|
|
%s
|
|
|
|
const _k_syscall_handler_t _k_syscall_table[K_SYSCALL_LIMIT] = {
|
|
\t%s
|
|
};
|
|
"""
|
|
|
|
list_template = """/* auto-generated by gen_syscalls.py, don't edit */
|
|
|
|
#ifndef ZEPHYR_SYSCALL_LIST_H
|
|
#define ZEPHYR_SYSCALL_LIST_H
|
|
|
|
%s
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
|
|
#endif /* _ASMLANGUAGE */
|
|
|
|
#endif /* ZEPHYR_SYSCALL_LIST_H */
|
|
"""
|
|
|
|
syscall_template = """/* auto-generated by gen_syscalls.py, don't edit */
|
|
|
|
{include_guard}
|
|
|
|
{tracing_include}
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <zephyr/syscall_list.h>
|
|
#include <zephyr/syscall.h>
|
|
|
|
#include <zephyr/linker/sections.h>
|
|
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {{
|
|
#endif
|
|
|
|
{invocations}
|
|
|
|
#ifdef __cplusplus
|
|
}}
|
|
#endif
|
|
|
|
#endif
|
|
#endif /* include guard */
|
|
"""
|
|
|
|
handler_template = """
|
|
extern uintptr_t z_hdlr_%s(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
|
|
uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, void *ssf);
|
|
"""
|
|
|
|
weak_template = """
|
|
__weak ALIAS_OF(handler_no_syscall)
|
|
uintptr_t %s(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
|
|
uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, void *ssf);
|
|
"""
|
|
|
|
# defines a macro wrapper which supersedes the syscall when used
|
|
# and provides tracing enter/exit hooks while allowing per compilation unit
|
|
# enable/disable of syscall tracing. Used for returning functions
|
|
# Note that the last argument to the exit macro is the return value.
|
|
syscall_tracer_with_return_template = """
|
|
#if defined(CONFIG_TRACING_SYSCALL)
|
|
#ifndef DISABLE_SYSCALL_TRACING
|
|
{trace_diagnostic}
|
|
#define {func_name}({argnames}) ({{ \
|
|
{func_type} syscall__retval; \
|
|
sys_port_trace_syscall_enter({syscall_id}, {func_name}{trace_argnames}); \
|
|
syscall__retval = {func_name}({argnames}); \
|
|
sys_port_trace_syscall_exit({syscall_id}, {func_name}{trace_argnames}, syscall__retval); \
|
|
syscall__retval; \
|
|
}})
|
|
#endif
|
|
#endif
|
|
"""
|
|
|
|
# defines a macro wrapper which supersedes the syscall when used
|
|
# and provides tracing enter/exit hooks while allowing per compilation unit
|
|
# enable/disable of syscall tracing. Used for non-returning (void) functions
|
|
syscall_tracer_void_template = """
|
|
#if defined(CONFIG_TRACING_SYSCALL)
|
|
#ifndef DISABLE_SYSCALL_TRACING
|
|
{trace_diagnostic}
|
|
#define {func_name}({argnames}) do {{ \
|
|
sys_port_trace_syscall_enter({syscall_id}, {func_name}{trace_argnames}); \
|
|
{func_name}({argnames}); \
|
|
sys_port_trace_syscall_exit({syscall_id}, {func_name}{trace_argnames}); \
|
|
}} while(false)
|
|
#endif
|
|
#endif
|
|
"""
|
|
|
|
|
|
llext_weakdefs_template = """/* auto-generated by gen_syscalls.py, don't edit */
|
|
|
|
#include <zephyr/toolchain.h>
|
|
#include <zephyr/llext/symbol.h>
|
|
|
|
/*
|
|
* This symbol is placed at address 0 by llext-sections.ld. Its value and
|
|
* type is not important, we are only interested in its location.
|
|
*/
|
|
static void * const no_syscall_impl Z_GENERIC_SECTION(llext_no_syscall_impl);
|
|
|
|
/*
|
|
* Weak references to all syscall implementations. Those not found by the
|
|
* linker outside this file will be exported as NULL and simply fail when
|
|
* an extension requiring them is loaded.
|
|
*/
|
|
%s
|
|
"""
|
|
|
|
|
|
llext_exports_template = """/* auto-generated by gen_syscalls.py, don't edit */
|
|
|
|
/*
|
|
* Export the implementation functions of all emitted syscalls.
|
|
* Only the symbol names are relevant in this file, they will be
|
|
* resolved to the actual implementation functions by the linker.
|
|
*/
|
|
|
|
/* Symbol declarations */
|
|
%s
|
|
|
|
/* Exported symbols */
|
|
%s
|
|
"""
|
|
|
|
typename_regex = re.compile(r'(.*?)([A-Za-z0-9_]+)$')
|
|
|
|
|
|
class SyscallParseException(Exception):
|
|
pass
|
|
|
|
|
|
def typename_split(item):
|
|
item = item.strip().replace("\n", " ")
|
|
if "[" in item:
|
|
raise SyscallParseException(
|
|
f"Please pass arrays to syscalls as pointers, unable to process '{item}'"
|
|
)
|
|
|
|
if "(" in item:
|
|
raise SyscallParseException("Please use typedefs for function pointers")
|
|
|
|
mo = typename_regex.match(item)
|
|
if not mo:
|
|
raise SyscallParseException("Malformed system call invocation")
|
|
|
|
m = mo.groups()
|
|
return (m[0].strip(), m[1])
|
|
|
|
|
|
def need_split(argtype):
|
|
return (not args.long_registers) and (argtype in types64)
|
|
|
|
|
|
# Note: "lo" and "hi" are named in little endian conventions,
|
|
# but it doesn't matter as long as they are consistently
|
|
# generated.
|
|
def union_decl(ctype, split):
|
|
middle = "struct { uintptr_t lo, hi; } split" if split else "uintptr_t x"
|
|
return f"union {{ {middle}; {ctype} val; }}"
|
|
|
|
|
|
def wrapper_defs(func_name, func_type, args, fn, userspace_only):
|
|
ret64 = need_split(func_type)
|
|
mrsh_args = [] # List of rvalue expressions for the marshalled invocation
|
|
|
|
decl_arglist = ", ".join([" ".join(argrec) for argrec in args]) or "void"
|
|
syscall_id = "K_SYSCALL_" + func_name.upper()
|
|
|
|
wrap = ''
|
|
if not userspace_only:
|
|
wrap += f"extern {func_type} z_impl_{func_name}({decl_arglist});\n"
|
|
wrap += "\n"
|
|
|
|
wrap += "__pinned_func\n"
|
|
wrap += f"static inline {func_type} {func_name}({decl_arglist})\n"
|
|
wrap += "{\n"
|
|
if not userspace_only:
|
|
wrap += "#ifdef CONFIG_USERSPACE\n"
|
|
|
|
wrap += ("\t" + "uint64_t ret64;\n") if ret64 else ""
|
|
if not userspace_only:
|
|
wrap += "\t" + "if (z_syscall_trap()) {\n"
|
|
|
|
valist_args = []
|
|
for argnum, (argtype, argname) in enumerate(args):
|
|
split = need_split(argtype)
|
|
decl = union_decl(argtype, split)
|
|
wrap += f"\t\t{decl} parm{argnum}"
|
|
if argtype != "va_list":
|
|
wrap += f" = {{ .val = {argname} }};\n"
|
|
else:
|
|
# va_list objects are ... peculiar.
|
|
wrap += ";\n" + "\t\t" + f"va_copy(parm{argnum}.val, {argname});\n"
|
|
valist_args.append(f"parm{argnum}.val")
|
|
if split:
|
|
mrsh_args.append(f"parm{argnum}.split.lo")
|
|
mrsh_args.append(f"parm{argnum}.split.hi")
|
|
else:
|
|
mrsh_args.append(f"parm{argnum}.x")
|
|
|
|
if ret64:
|
|
mrsh_args.append("(uintptr_t)&ret64")
|
|
|
|
if len(mrsh_args) > 6:
|
|
wrap += "\t\t" + "uintptr_t more[] = {\n"
|
|
wrap += "\t\t\t" + (",\n\t\t\t".join(mrsh_args[5:])) + "\n"
|
|
wrap += "\t\t" + "};\n"
|
|
mrsh_args[5:] = ["(uintptr_t) &more"]
|
|
|
|
invoke_args = ", ".join(mrsh_args + [syscall_id])
|
|
invoke = f"arch_syscall_invoke{len(mrsh_args)}({invoke_args})"
|
|
|
|
if ret64:
|
|
invoke = "\t\t" + f"(void) {invoke};\n"
|
|
retcode = "\t\t" + f"return ({func_type}) ret64;\n"
|
|
elif func_type == "void":
|
|
invoke = "\t\t" + f"(void) {invoke};\n"
|
|
retcode = "\t\t" + "return;\n"
|
|
elif valist_args:
|
|
invoke = "\t\t" + f"{func_type} invoke__retval = {invoke};\n"
|
|
retcode = "\t\t" + "return invoke__retval;\n"
|
|
else:
|
|
invoke = "\t\t" + f"return ({func_type}) {invoke};\n"
|
|
retcode = ""
|
|
|
|
wrap += invoke
|
|
for argname in valist_args:
|
|
wrap += "\t\t" + f"va_end({argname});\n"
|
|
wrap += retcode
|
|
if not userspace_only:
|
|
wrap += "\t" + "}\n"
|
|
wrap += "#endif\n"
|
|
|
|
# Otherwise fall through to direct invocation of the impl func.
|
|
# Note the compiler barrier: that is required to prevent code from
|
|
# the impl call from being hoisted above the check for user
|
|
# context.
|
|
impl_arglist = ", ".join([argrec[1] for argrec in args])
|
|
impl_call = f"z_impl_{func_name}({impl_arglist})"
|
|
wrap += "\t" + "compiler_barrier();\n"
|
|
ret = "return " if func_type != "void" else ""
|
|
wrap += "\t" + f"{ret}{impl_call};\n"
|
|
|
|
wrap += "}\n"
|
|
|
|
if fn not in notracing:
|
|
argnames = ", ".join([f"{argname}" for _, argname in args])
|
|
trace_argnames = ""
|
|
if len(args) > 0:
|
|
trace_argnames = ", " + argnames
|
|
trace_diagnostic = ""
|
|
if os.getenv('TRACE_DIAGNOSTICS'):
|
|
trace_diagnostic = f"#warning Tracing {func_name}"
|
|
if func_type != "void":
|
|
wrap += syscall_tracer_with_return_template.format(
|
|
func_type=func_type,
|
|
func_name=func_name,
|
|
argnames=argnames,
|
|
trace_argnames=trace_argnames,
|
|
syscall_id=syscall_id,
|
|
trace_diagnostic=trace_diagnostic,
|
|
)
|
|
else:
|
|
wrap += syscall_tracer_void_template.format(
|
|
func_type=func_type,
|
|
func_name=func_name,
|
|
argnames=argnames,
|
|
trace_argnames=trace_argnames,
|
|
syscall_id=syscall_id,
|
|
trace_diagnostic=trace_diagnostic,
|
|
)
|
|
|
|
return wrap
|
|
|
|
|
|
# Returns an expression for the specified (zero-indexed!) marshalled
|
|
# parameter to a syscall, with handling for a final "more" parameter.
|
|
def mrsh_rval(mrsh_num, total):
|
|
if mrsh_num < 5 or total <= 6:
|
|
return f"arg{mrsh_num}"
|
|
else:
|
|
return f"(((uintptr_t *)more)[{mrsh_num - 5}])"
|
|
|
|
|
|
def marshall_defs(func_name, func_type, args):
|
|
mrsh_name = "z_mrsh_" + func_name
|
|
|
|
nmrsh = 0 # number of marshalled uintptr_t parameter
|
|
vrfy_parms = [] # list of (argtype, bool_is_split)
|
|
for argtype, _ in args:
|
|
split = need_split(argtype)
|
|
vrfy_parms.append((argtype, split))
|
|
nmrsh += 2 if split else 1
|
|
|
|
# Final argument for a 64 bit return value?
|
|
if need_split(func_type):
|
|
nmrsh += 1
|
|
|
|
decl_arglist = ", ".join([" ".join(argrec) for argrec in args])
|
|
mrsh = f"extern {func_type} z_vrfy_{func_name}({decl_arglist});\n"
|
|
|
|
mrsh += f"uintptr_t {mrsh_name}(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2,\n"
|
|
if nmrsh <= 6:
|
|
mrsh += "\t\t" + "uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, void *ssf)\n"
|
|
else:
|
|
mrsh += "\t\t" + "uintptr_t arg3, uintptr_t arg4, void *more, void *ssf)\n"
|
|
mrsh += "{\n"
|
|
mrsh += "\t" + "_current->syscall_frame = ssf;\n"
|
|
|
|
for unused_arg in range(nmrsh, 6):
|
|
mrsh += f"\t(void) arg{unused_arg};\t/* unused */\n"
|
|
|
|
if nmrsh > 6:
|
|
mrsh += (
|
|
"\tK_OOPS(K_SYSCALL_MEMORY_READ(more, " + str(nmrsh - 5) + " * sizeof(uintptr_t)));\n"
|
|
)
|
|
|
|
argnum = 0
|
|
for i, (argtype, split) in enumerate(vrfy_parms):
|
|
decl = union_decl(argtype, split)
|
|
mrsh += f"\t{decl} parm{i};\n"
|
|
rval = mrsh_rval(argnum, nmrsh)
|
|
if split:
|
|
mrsh += "\t" + f"parm{i}.split.lo = {rval};\n"
|
|
argnum += 1
|
|
rval = mrsh_rval(argnum, nmrsh)
|
|
mrsh += "\t" + f"parm{i}.split.hi = {rval};\n"
|
|
else:
|
|
mrsh += "\t" + f"parm{i}.x = {rval};\n"
|
|
argnum += 1
|
|
|
|
# Finally, invoke the verify function
|
|
out_args = ", ".join([f"parm{i}.val" for i in range(len(args))])
|
|
vrfy_call = f"z_vrfy_{func_name}({out_args})"
|
|
|
|
if func_type == "void":
|
|
mrsh += "\t" + f"{vrfy_call};\n"
|
|
mrsh += "\t" + "_current->syscall_frame = NULL;\n"
|
|
mrsh += "\t" + "return 0;\n"
|
|
else:
|
|
mrsh += "\t" + f"{func_type} ret = {vrfy_call};\n"
|
|
|
|
if need_split(func_type):
|
|
rval = mrsh_rval(nmrsh - 1, nmrsh)
|
|
ptr = f"((uint64_t *){rval})"
|
|
mrsh += "\t" + f"K_OOPS(K_SYSCALL_MEMORY_WRITE({ptr}, 8));\n"
|
|
mrsh += "\t" + f"*{ptr} = ret;\n"
|
|
mrsh += "\t" + "_current->syscall_frame = NULL;\n"
|
|
mrsh += "\t" + "return 0;\n"
|
|
else:
|
|
mrsh += "\t" + "_current->syscall_frame = NULL;\n"
|
|
mrsh += "\t" + "return (uintptr_t) ret;\n"
|
|
|
|
mrsh += "}\n"
|
|
|
|
return mrsh, mrsh_name
|
|
|
|
|
|
def analyze_fn(match_group, fn, userspace_only):
|
|
func, args = match_group
|
|
|
|
try:
|
|
if args == "void":
|
|
args = []
|
|
else:
|
|
args = [typename_split(a) for a in args.split(",")]
|
|
|
|
func_type, func_name = typename_split(func)
|
|
except SyscallParseException:
|
|
sys.stderr.write(f"In declaration of {func}\n")
|
|
raise
|
|
|
|
sys_id = "K_SYSCALL_" + func_name.upper()
|
|
|
|
marshaller = None
|
|
marshaller, handler = marshall_defs(func_name, func_type, args)
|
|
invocation = wrapper_defs(func_name, func_type, args, fn, userspace_only)
|
|
|
|
# Entry in _k_syscall_table
|
|
table_entry = f"[{sys_id}] = {handler}"
|
|
|
|
return (handler, invocation, marshaller, sys_id, table_entry)
|
|
|
|
|
|
def parse_args():
|
|
global args
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
allow_abbrev=False,
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-i", "--json-file", required=True, help="Read syscall information from json file"
|
|
)
|
|
parser.add_argument(
|
|
"-d", "--syscall-dispatch", required=True, help="output C system call dispatch table file"
|
|
)
|
|
parser.add_argument(
|
|
"-l", "--syscall-list", required=True, help="output C system call list header"
|
|
)
|
|
parser.add_argument(
|
|
"-o", "--base-output", required=True, help="Base output directory for syscall macro headers"
|
|
)
|
|
parser.add_argument(
|
|
"-s",
|
|
"--split-type",
|
|
action="append",
|
|
help="A long type that must be split/marshalled on 32-bit systems",
|
|
)
|
|
parser.add_argument(
|
|
"-x",
|
|
"--long-registers",
|
|
action="store_true",
|
|
help="Indicates we are on system with 64-bit registers",
|
|
)
|
|
parser.add_argument(
|
|
"--gen-mrsh-files", action="store_true", help="Generate marshalling files (*_mrsh.c)"
|
|
)
|
|
parser.add_argument(
|
|
"-e", "--syscall-exports-llext", help="output C system call export for extensions"
|
|
)
|
|
parser.add_argument(
|
|
"-w", "--syscall-weakdefs-llext", help="output C system call weak definitions"
|
|
)
|
|
parser.add_argument(
|
|
"-u",
|
|
"--userspace-only",
|
|
action="store_true",
|
|
help="Only generate the userpace path of wrappers",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
|
|
def main():
|
|
parse_args()
|
|
|
|
if args.split_type is not None:
|
|
for t in args.split_type:
|
|
types64.append(t)
|
|
|
|
with open(args.json_file) as fd:
|
|
syscalls = json.load(fd)
|
|
|
|
invocations = {}
|
|
mrsh_defs = {}
|
|
mrsh_includes = {}
|
|
ids_emit = []
|
|
ids_not_emit = []
|
|
table_entries = []
|
|
handlers = []
|
|
emit_list = []
|
|
exported = []
|
|
|
|
for match_group, fn, to_emit in syscalls:
|
|
handler, inv, mrsh, sys_id, entry = analyze_fn(match_group, fn, args.userspace_only)
|
|
|
|
if fn not in invocations:
|
|
invocations[fn] = []
|
|
|
|
invocations[fn].append(inv)
|
|
handlers.append(handler)
|
|
|
|
if to_emit:
|
|
ids_emit.append(sys_id)
|
|
table_entries.append(entry)
|
|
emit_list.append(handler)
|
|
exported.append(handler.replace("z_mrsh_", "z_impl_"))
|
|
else:
|
|
ids_not_emit.append(sys_id)
|
|
|
|
if mrsh and to_emit:
|
|
syscall = typename_split(match_group[0])[1]
|
|
mrsh_defs[syscall] = mrsh
|
|
mrsh_includes[syscall] = f"#include <zephyr/syscalls/{fn}>"
|
|
|
|
with open(args.syscall_dispatch, "w") as fp:
|
|
table_entries.append("[K_SYSCALL_BAD] = handler_bad_syscall")
|
|
|
|
weak_defines = "".join(
|
|
[weak_template % name for name in handlers if name not in noweak and name in emit_list]
|
|
)
|
|
|
|
# The "noweak" ones just get a regular declaration
|
|
noweak_args = ", ".join([f"uintptr_t arg{i + 1}" for i in range(6)]) + ", void *ssf"
|
|
weak_defines += "\n".join([f"extern uintptr_t {s}({noweak_args});" for s in noweak])
|
|
|
|
fp.write(table_template % (weak_defines, ",\n\t".join(table_entries)))
|
|
|
|
exported.sort()
|
|
|
|
if args.syscall_weakdefs_llext:
|
|
with open(args.syscall_weakdefs_llext, "w") as fp:
|
|
# Provide weak definitions for all emitted syscalls
|
|
weak_refs = "\n".join(
|
|
f"extern __weak ALIAS_OF(no_syscall_impl) void * const {e};" for e in exported
|
|
)
|
|
fp.write(llext_weakdefs_template % weak_refs)
|
|
|
|
if args.syscall_exports_llext:
|
|
with open(args.syscall_exports_llext, "w") as fp:
|
|
# Export symbols for emitted syscalls
|
|
extern_refs = "\n".join(f"extern void * const {e};" for e in exported)
|
|
exported_symbols = "\n".join(f"EXPORT_GROUP_SYMBOL(SYSCALL, {e});" for e in exported)
|
|
fp.write(llext_exports_template % (extern_refs, exported_symbols))
|
|
|
|
# Listing header emitted to stdout
|
|
ids_emit.sort()
|
|
ids_emit.extend(["K_SYSCALL_BAD", "K_SYSCALL_LIMIT"])
|
|
|
|
ids_as_defines = ""
|
|
for i, item in enumerate(ids_emit):
|
|
ids_as_defines += f"#define {item} {i}\n"
|
|
|
|
if ids_not_emit:
|
|
# There are syscalls that are not used in the image but
|
|
# their IDs are used in the generated stubs. So need to
|
|
# make them usable but outside the syscall ID range.
|
|
ids_as_defines += "\n\n/* Following syscalls are not used in image */\n"
|
|
ids_not_emit.sort()
|
|
num_emitted_ids = len(ids_emit)
|
|
for i, item in enumerate(ids_not_emit):
|
|
ids_as_defines += f"#define {item} {i + num_emitted_ids}\n"
|
|
|
|
with open(args.syscall_list, "w") as fp:
|
|
fp.write(list_template % ids_as_defines)
|
|
|
|
os.makedirs(args.base_output, exist_ok=True)
|
|
for fn, invo_list in invocations.items():
|
|
out_fn = os.path.join(args.base_output, fn)
|
|
|
|
ig = re.sub("[^a-zA-Z0-9]", "_", "Z_INCLUDE_SYSCALLS_" + fn).upper()
|
|
include_guard = f"#ifndef {ig}\n#define {ig}\n"
|
|
tracing_include = ""
|
|
if fn not in notracing:
|
|
tracing_include = "#include <zephyr/tracing/tracing_syscall.h>"
|
|
header = syscall_template.format(
|
|
include_guard=include_guard,
|
|
tracing_include=tracing_include,
|
|
invocations="\n\n".join(invo_list),
|
|
)
|
|
|
|
with open(out_fn, "w") as fp:
|
|
fp.write(header)
|
|
|
|
# Likewise emit _mrsh.c files for syscall inclusion
|
|
if args.gen_mrsh_files:
|
|
for fn in mrsh_defs:
|
|
mrsh_fn = os.path.join(args.base_output, fn + "_mrsh.c")
|
|
|
|
with open(mrsh_fn, "w") as fp:
|
|
fp.write("/* auto-generated by gen_syscalls.py, don't edit */\n\n")
|
|
fp.write(mrsh_includes[fn] + "\n")
|
|
fp.write("\n")
|
|
fp.write(mrsh_defs[fn] + "\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|