Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (c) 2017 Intel Corporation |
| 4 | # |
| 5 | # SPDX-License-Identifier: Apache-2.0 |
| 6 | |
| 7 | import sys |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 8 | from enum import Enum |
| 9 | |
| 10 | class Retval(Enum): |
| 11 | VOID = 0 |
| 12 | U32 = 1 |
| 13 | U64 = 2 |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 14 | |
Andrew Boie | 990bf16 | 2017-10-03 12:36:49 -0700 | [diff] [blame] | 15 | def gen_macro(ret, argc): |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 16 | if ret == Retval.VOID: |
| 17 | suffix = "_VOID" |
| 18 | elif ret == Retval.U64: |
| 19 | suffix = "_RET64" |
| 20 | else: |
| 21 | suffix = "" |
| 22 | |
| 23 | sys.stdout.write("K_SYSCALL_DECLARE%d%s(id, name" % (argc, suffix)) |
| 24 | if (ret != Retval.VOID): |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 25 | sys.stdout.write(", ret") |
| 26 | for i in range(argc): |
| 27 | sys.stdout.write(", t%d, p%d" % (i, i)) |
| 28 | sys.stdout.write(")") |
| 29 | |
| 30 | def gen_fn(ret, argc, name, extern=False): |
| 31 | sys.stdout.write("\t%s %s %s(" % |
| 32 | (("extern" if extern else "static inline"), |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 33 | ("ret" if ret != Retval.VOID else "void"), name)) |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 34 | if argc == 0: |
| 35 | sys.stdout.write("void"); |
| 36 | else: |
| 37 | for i in range(argc): |
| 38 | sys.stdout.write("t%d p%d" % (i, i)) |
| 39 | if i != (argc - 1): |
| 40 | sys.stdout.write(", ") |
| 41 | sys.stdout.write(")") |
| 42 | |
Andrew Boie | 3ae6444 | 2017-11-28 13:59:15 -0800 | [diff] [blame] | 43 | def tabs(count): |
| 44 | sys.stdout.write("\t" * count); |
| 45 | |
| 46 | def gen_make_syscall(ret, argc, tabcount): |
| 47 | tabs(tabcount) |
| 48 | |
| 49 | # The core kernel is built with the --no-whole-archive linker option. |
| 50 | # For all the individual .o files which make up the kernel, if there |
| 51 | # are no external references to symbols within these object files, |
| 52 | # everything in the object file is dropped. |
| 53 | # |
| 54 | # This has a subtle interaction with system call handlers. If an object |
| 55 | # file has system call handler inside it, and nothing else in the |
| 56 | # object file is referenced, then the linker will prefer the weak |
| 57 | # version of the handler in the generated syscall_dispatch.c. The |
| 58 | # user will get an "unimplemented system call" error if the associated |
| 59 | # system call for that handler is made. |
| 60 | # |
| 61 | # Fix this by making a fake reference to the handler function at the |
| 62 | # system call site. The address gets stored inside a special section |
| 63 | # "hndlr_ref". This is enough to prevent the handlers from being |
| 64 | # dropped, and the hndlr_ref section is itself dropped from the binary |
| 65 | # from gc-sections; these references will not consume space. |
| 66 | |
| 67 | sys.stdout.write("static _GENERIC_SECTION(hndlr_ref) __used void *href = (void *)&_handler_##name; \\\n") |
| 68 | tabs(tabcount) |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 69 | if (ret != Retval.VOID): |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 70 | sys.stdout.write("return (ret)") |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 71 | if (argc <= 6 and ret != Retval.U64): |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 72 | sys.stdout.write("_arch") |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 73 | sys.stdout.write("_syscall%s_invoke%d(" % |
| 74 | (("_ret64" if ret == Retval.U64 else ""), argc)) |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 75 | for i in range(argc): |
| 76 | sys.stdout.write("(u32_t)p%d, " % (i)) |
| 77 | sys.stdout.write("id); \\\n") |
| 78 | |
| 79 | def gen_call_impl(ret, argc): |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 80 | if (ret != Retval.VOID): |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 81 | sys.stdout.write("return ") |
| 82 | sys.stdout.write("_impl_##name(") |
| 83 | for i in range(argc): |
| 84 | sys.stdout.write("p%d" % (i)) |
| 85 | if i != (argc - 1): |
| 86 | sys.stdout.write(", ") |
| 87 | sys.stdout.write("); \\\n") |
| 88 | |
| 89 | def newline(): |
| 90 | sys.stdout.write(" \\\n") |
| 91 | |
| 92 | def gen_defines_inner(ret, argc, kernel_only=False, user_only=False): |
| 93 | sys.stdout.write("#define ") |
Andrew Boie | 990bf16 | 2017-10-03 12:36:49 -0700 | [diff] [blame] | 94 | gen_macro(ret, argc) |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 95 | newline() |
| 96 | |
Andrew Boie | 990bf16 | 2017-10-03 12:36:49 -0700 | [diff] [blame] | 97 | if not user_only: |
| 98 | gen_fn(ret, argc, "_impl_##name", extern=True) |
| 99 | sys.stdout.write(";") |
| 100 | newline() |
| 101 | |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 102 | gen_fn(ret, argc, "name"); |
| 103 | newline() |
| 104 | sys.stdout.write("\t{") |
| 105 | newline() |
| 106 | |
| 107 | if kernel_only: |
| 108 | sys.stdout.write("\t\t") |
| 109 | gen_call_impl(ret, argc) |
| 110 | elif user_only: |
Andrew Boie | 3ae6444 | 2017-11-28 13:59:15 -0800 | [diff] [blame] | 111 | gen_make_syscall(ret, argc, 2) |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 112 | else: |
| 113 | sys.stdout.write("\t\tif (_is_user_context()) {") |
| 114 | newline() |
| 115 | |
Andrew Boie | 3ae6444 | 2017-11-28 13:59:15 -0800 | [diff] [blame] | 116 | gen_make_syscall(ret, argc, 3) |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 117 | |
| 118 | sys.stdout.write("\t\t} else {") |
| 119 | newline() |
| 120 | |
Andrew Boie | c535455 | 2017-10-14 11:00:12 -0700 | [diff] [blame] | 121 | # Prevent memory access issues if the implementation function gets |
| 122 | # inlined |
| 123 | sys.stdout.write("\t\t\tcompiler_barrier();"); |
| 124 | newline() |
| 125 | |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 126 | sys.stdout.write("\t\t\t") |
| 127 | gen_call_impl(ret, argc) |
| 128 | sys.stdout.write("\t\t}") |
| 129 | newline() |
| 130 | |
| 131 | sys.stdout.write("\t}\n\n") |
| 132 | |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 133 | |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 134 | def gen_defines(argc, kernel_only=False, user_only=False): |
Andrew Boie | 3ff41b9 | 2017-10-08 12:20:24 -0700 | [diff] [blame] | 135 | gen_defines_inner(Retval.VOID, argc, kernel_only, user_only) |
| 136 | gen_defines_inner(Retval.U32, argc, kernel_only, user_only) |
| 137 | gen_defines_inner(Retval.U64, argc, kernel_only, user_only) |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 138 | |
| 139 | |
| 140 | sys.stdout.write("/* Auto-generated by gen_syscall_header.py, do not edit! */\n\n") |
| 141 | sys.stdout.write("#ifndef GEN_SYSCALL_H\n#define GEN_SYSCALL_H\n\n") |
| 142 | |
| 143 | for i in range(11): |
Andrew Boie | a949b50 | 2017-10-10 16:10:39 -0700 | [diff] [blame] | 144 | sys.stdout.write("#if !defined(CONFIG_USERSPACE) || defined(__ZEPHYR_SUPERVISOR__)\n") |
Andrew Boie | 1d3731f | 2017-09-22 13:52:21 -0700 | [diff] [blame] | 145 | gen_defines(i, kernel_only=True) |
| 146 | sys.stdout.write("#elif defined(__ZEPHYR_USER__)\n") |
| 147 | gen_defines(i, user_only=True) |
| 148 | sys.stdout.write("#else /* mixed kernel/user macros */\n") |
| 149 | gen_defines(i) |
| 150 | sys.stdout.write("#endif /* mixed kernel/user macros */\n\n") |
| 151 | |
| 152 | sys.stdout.write("#endif /* GEN_SYSCALL_H */\n") |
| 153 | |
| 154 | |
| 155 | |
| 156 | |
| 157 | |