#!/usr/bin/env python3 # # Copyright (c) 2017 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 import sys from enum import Enum class Retval(Enum): VOID = 0 U32 = 1 U64 = 2 def gen_macro(ret, argc): if ret == Retval.VOID: suffix = "_VOID" elif ret == Retval.U64: suffix = "_RET64" else: suffix = "" sys.stdout.write("K_SYSCALL_DECLARE%d%s(id, name" % (argc, suffix)) if (ret != Retval.VOID): sys.stdout.write(", ret") for i in range(argc): sys.stdout.write(", t%d, p%d" % (i, i)) sys.stdout.write(")") def gen_fn(ret, argc, name, extern=False): sys.stdout.write("\t%s %s %s(" % (("extern" if extern else "static inline"), ("ret" if ret != Retval.VOID else "void"), name)) if argc == 0: sys.stdout.write("void") else: for i in range(argc): sys.stdout.write("t%d p%d" % (i, i)) if i != (argc - 1): sys.stdout.write(", ") sys.stdout.write(")") def tabs(count): sys.stdout.write("\t" * count) def gen_make_syscall(ret, argc, tabcount): tabs(tabcount) # The core kernel is built with the --no-whole-archive linker option. # For all the individual .o files which make up the kernel, if there # are no external references to symbols within these object files, # everything in the object file is dropped. # # This has a subtle interaction with system call handlers. If an object # file has system call handler inside it, and nothing else in the # object file is referenced, then the linker will prefer the weak # version of the handler in the generated syscall_dispatch.c. The # user will get an "unimplemented system call" error if the associated # system call for that handler is made. # # Fix this by making a fake reference to the handler function at the # system call site. The address gets stored inside a special section # "hndlr_ref". This is enough to prevent the handlers from being # dropped, and the hndlr_ref section is itself dropped from the binary # from gc-sections; these references will not consume space. sys.stdout.write( "static _GENERIC_SECTION(hndlr_ref) __used void *href = (void *)&hdlr_##name; \\\n") tabs(tabcount) if (ret != Retval.VOID): sys.stdout.write("return (ret)") else: sys.stdout.write("return (void)") if (argc <= 6 and ret != Retval.U64): sys.stdout.write("_arch") sys.stdout.write("_syscall%s_invoke%d(" % (("_ret64" if ret == Retval.U64 else ""), argc)) for i in range(argc): sys.stdout.write("(u32_t)p%d, " % (i)) sys.stdout.write("id); \\\n") def gen_call_impl(ret, argc): if (ret != Retval.VOID): sys.stdout.write("return ") sys.stdout.write("_impl_##name(") for i in range(argc): sys.stdout.write("p%d" % (i)) if i != (argc - 1): sys.stdout.write(", ") sys.stdout.write("); \\\n") def newline(): sys.stdout.write(" \\\n") def gen_defines_inner(ret, argc, kernel_only=False, user_only=False): sys.stdout.write("#define ") gen_macro(ret, argc) newline() if not user_only: gen_fn(ret, argc, "_impl_##name", extern=True) sys.stdout.write(";") newline() gen_fn(ret, argc, "name") newline() sys.stdout.write("\t{") newline() if kernel_only: sys.stdout.write("\t\t") gen_call_impl(ret, argc) elif user_only: gen_make_syscall(ret, argc, 2) else: sys.stdout.write("\t\tif (_is_user_context()) {") newline() gen_make_syscall(ret, argc, 3) sys.stdout.write("\t\t} else {") newline() # Prevent memory access issues if the implementation function gets # inlined sys.stdout.write("\t\t\tcompiler_barrier();") newline() sys.stdout.write("\t\t\t") gen_call_impl(ret, argc) sys.stdout.write("\t\t}") newline() sys.stdout.write("\t}\n\n") def gen_defines(argc, kernel_only=False, user_only=False): gen_defines_inner(Retval.VOID, argc, kernel_only, user_only) gen_defines_inner(Retval.U32, argc, kernel_only, user_only) gen_defines_inner(Retval.U64, argc, kernel_only, user_only) sys.stdout.write( "/* Auto-generated by gen_syscall_header.py, do not edit! */\n\n") sys.stdout.write("#ifndef GEN_SYSCALL_H\n#define GEN_SYSCALL_H\n\n") sys.stdout.write("#include \n") for i in range(11): sys.stdout.write( "#if !defined(CONFIG_USERSPACE) || defined(__ZEPHYR_SUPERVISOR__)\n") gen_defines(i, kernel_only=True) sys.stdout.write("#elif defined(__ZEPHYR_USER__)\n") gen_defines(i, user_only=True) sys.stdout.write("#else /* mixed kernel/user macros */\n") gen_defines(i) sys.stdout.write("#endif /* mixed kernel/user macros */\n\n") sys.stdout.write("#endif /* GEN_SYSCALL_H */\n")