syscalls: llext: Export z_impl symbols so they are available to kernel

commit 67bb6db3f8 ("syscall: Export all emitted syscalls, enabling
them for extensions") exports all emitted syscalls, however, it does
that only for the `z_mrsh` symbols, effectively only available for
userspace. If an extension running at kernel level tries to use a
syscall, it will fail to load.

This patch fixes that by exposing the `z_impl` symbols instead. However,
this is not as straightforward as the `z_mrsh` ones. As, in their
signatures, they can basically contain any type, it's not just a matter
of emitting `EXPORT_SYMBOL(z_impl_<syscall>)`, as the compiler will
complain about the undefined types. Here, there are a few approaches.

One of them is to have the `EXPORT_SYMBOL` being generated on the same
files where the syscall is implemented - injecting it there would allow
it to access all known symbols. But changing a lot of files is
undesirable, and it was one of the nice points of first patch.

Another one would be to reconstruct - or simply use the absolute path -
for the includes where the syscalls are defined. Reconstruct the paths
seems fragile and I'm not sure using absolute paths is portable.

Finally, the approach used in this patch is to declare, on a different
generated file, all `z_impl_` symbols as `void *` - after all, only the
address (and the name) to the function is relevant to EXPORT_SYMBOL. By
living in an compilation unit that doesn't include any header which
would expose any of the syscalls, there shouldn't be any conflicts. And
to account for the possibility that a syscall is not compiled - due
being configured out via Kconfig - all those symbols are also weak
aliases to a pointer to NULL. This file is then included in
`llext_export.c` (which should naturally not include any conflicting
header).

Signed-off-by: Ederson de Souza <ederson.desouza@intel.com>
This commit is contained in:
Ederson de Souza 2024-03-21 15:51:15 -07:00 committed by Anas Nashif
parent 321e395a8f
commit 62b19ef65c
3 changed files with 31 additions and 7 deletions

View file

@ -759,6 +759,7 @@ add_custom_command(OUTPUT include/generated/syscall_dispatch.c ${syscall_list_h}
--json-file ${syscalls_json} # Read this file
--base-output include/generated/syscalls # Write to this dir
--syscall-dispatch include/generated/syscall_dispatch.c # Write this file
--syscall-export-llext include/generated/syscall_export_llext.c
--syscall-list ${syscall_list_h}
$<$<BOOL:${CONFIG_USERSPACE}>:--gen-mrsh-files>
${SYSCALL_LONG_REGISTERS_ARG}

View file

@ -62,8 +62,6 @@ table_template = """/* auto-generated by gen_syscalls.py, don't edit */
const _k_syscall_handler_t _k_syscall_table[K_SYSCALL_LIMIT] = {
\t%s
};
/* Export syscalls for extensions */
%s
"""
list_template = """/* auto-generated by gen_syscalls.py, don't edit */
@ -159,6 +157,20 @@ syscall_tracer_void_template = """
#endif
"""
exported_template = """
/* Export syscalls for extensions */
static void * const no_handler = NULL;
/* Weak references, if something is not found by the linker, it will be NULL
* and simply fail during extension load
*/
%s
/* Exported symbols */
%s
"""
typename_regex = re.compile(r'(.*?)([A-Za-z0-9_]+)$')
@ -410,6 +422,8 @@ def parse_args():
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-export-llext",
help="output C system call export for extensions")
args = parser.parse_args()
@ -431,6 +445,7 @@ def main():
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)
@ -445,6 +460,7 @@ def main():
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)
@ -464,12 +480,17 @@ def main():
weak_defines += "\n".join(["extern uintptr_t %s(uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, void *ssf);"
% s for s in noweak])
# Export symbols for emitted syscalls
exported_symbols = "\n".join("EXPORT_SYMBOL(%s);" % e for e in emit_list)
fp.write(table_template % (weak_defines,
",\n\t".join(table_entries),
exported_symbols))
",\n\t".join(table_entries)))
if args.syscall_export_llext:
with open(args.syscall_export_llext, "w") as fp:
# Export symbols for emitted syscalls
weak_refs = "\n".join("extern __weak ALIAS_OF(no_handler) void * const %s;"
% e for e in exported)
exported_symbols = "\n".join("EXPORT_SYMBOL(%s);"
% e for e in exported)
fp.write(exported_template % (weak_refs, exported_symbols))
# Listing header emitted to stdout
ids_emit.sort()

View file

@ -15,3 +15,5 @@ EXPORT_SYMBOL(strncmp);
EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
#include <syscall_export_llext.c>