parse_syscalls.py was doing too much and was generating derived and partial string output information that was completed later by gen_syscalls.py. Now parse_syscalls.py just breaks up system call information into non-derived data which is fully processed by gen_syscalls.py. The goal is to ease maintenance of system call generation with all the mechanism on what to do with system call information in one script location rather than two of them. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
223 lines
5.2 KiB
Python
Executable File
223 lines
5.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2017 Intel Corporation
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
import sys
|
|
import re
|
|
import argparse
|
|
import os
|
|
import json
|
|
|
|
table_template = """/* auto-generated by gen_syscalls.py, don't edit */
|
|
|
|
/* 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_
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
#include <zephyr/types.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
enum {
|
|
\t%s
|
|
};
|
|
|
|
%s
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* _ASMLANGUAGE */
|
|
|
|
#endif /* _ZEPHYR_SYSCALL_LIST_H_ */
|
|
"""
|
|
|
|
syscall_template = """
|
|
/* auto-generated by gen_syscalls.py, don't edit */
|
|
|
|
#ifndef _ASMLANGUAGE
|
|
|
|
#include <syscall_list.h>
|
|
#include <syscall_macros.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
%s
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
"""
|
|
|
|
handler_template = """
|
|
extern u32_t %s(u32_t arg1, u32_t arg2, u32_t arg3,
|
|
u32_t arg4, u32_t arg5, u32_t arg6, void *ssf);
|
|
"""
|
|
|
|
weak_template = """
|
|
__weak ALIAS_OF(handler_no_syscall)
|
|
u32_t %s(u32_t arg1, u32_t arg2, u32_t arg3,
|
|
u32_t arg4, u32_t arg5, u32_t arg6, void *ssf);
|
|
"""
|
|
|
|
|
|
typename_regex = re.compile(r'(.*?)([A-Za-z0-9_]+)$')
|
|
|
|
|
|
class SyscallParseException(Exception):
|
|
pass
|
|
|
|
|
|
def typename_split(item):
|
|
if "[" in item:
|
|
raise SyscallParseException(
|
|
"Please pass arrays to syscalls as pointers, unable to process '%s'" %
|
|
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 analyze_fn(match_group):
|
|
func, args = match_group
|
|
|
|
try:
|
|
if args == "void":
|
|
args = []
|
|
else:
|
|
args = [typename_split(a.strip()) for a in args.split(",")]
|
|
|
|
func_type, func_name = typename_split(func)
|
|
except SyscallParseException:
|
|
sys.stderr.write("In declaration of %s\n" % func)
|
|
raise
|
|
|
|
sys_id = "K_SYSCALL_" + func_name.upper()
|
|
|
|
if func_type == "void":
|
|
suffix = "_VOID"
|
|
is_void = True
|
|
else:
|
|
is_void = False
|
|
if func_type in ["s64_t", "u64_t"]:
|
|
suffix = "_RET64"
|
|
else:
|
|
suffix = ""
|
|
|
|
is_void = (func_type == "void")
|
|
|
|
# Get the proper system call macro invocation, which depends on the
|
|
# number of arguments, the return type, and whether the implementation
|
|
# is an inline function
|
|
macro = "K_SYSCALL_DECLARE%d%s" % (len(args), suffix)
|
|
|
|
# Flatten the argument lists and generate a comma separated list
|
|
# of t0, p0, t1, p1, ... tN, pN as expected by the macros
|
|
flat_args = [i for sublist in args for i in sublist]
|
|
if not is_void:
|
|
flat_args = [func_type] + flat_args
|
|
flat_args = [sys_id, func_name] + flat_args
|
|
argslist = ", ".join(flat_args)
|
|
|
|
invocation = "%s(%s);" % (macro, argslist)
|
|
|
|
handler = "_handler_" + func_name
|
|
|
|
# Entry in _k_syscall_table
|
|
table_entry = "[%s] = %s" % (sys_id, handler)
|
|
|
|
return (handler, invocation, sys_id, table_entry)
|
|
|
|
def parse_args():
|
|
global args
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
|
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("-o", "--base-output", required=True,
|
|
help="Base output directory for syscall macro headers")
|
|
args = parser.parse_args()
|
|
|
|
|
|
def main():
|
|
parse_args()
|
|
|
|
with open(args.json_file, 'r') as fd:
|
|
syscalls = json.load(fd)
|
|
|
|
invocations = {}
|
|
ids = []
|
|
table_entries = []
|
|
handlers = []
|
|
|
|
for match_group, fn in syscalls:
|
|
handler, inv, sys_id, entry = analyze_fn(match_group)
|
|
|
|
if fn not in invocations:
|
|
invocations[fn] = []
|
|
|
|
invocations[fn].append(inv)
|
|
ids.append(sys_id)
|
|
table_entries.append(entry)
|
|
handlers.append(handler)
|
|
|
|
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])
|
|
|
|
fp.write(table_template % (weak_defines, ",\n\t".join(table_entries)))
|
|
|
|
# Listing header emitted to stdout
|
|
ids.sort()
|
|
ids.extend(["K_SYSCALL_BAD", "K_SYSCALL_LIMIT"])
|
|
handler_defines = "".join([handler_template % name for name in handlers])
|
|
sys.stdout.write(list_template % (",\n\t".join(ids), handler_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)
|
|
|
|
header = syscall_template % "\n\n".join(invo_list)
|
|
|
|
with open(out_fn, "w") as fp:
|
|
fp.write(header)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|