zephyr/scripts/gen_syscall_header.py
Andrew Boie c5354552ce gen_syscall_header: use compiler barrier
We need to enforce that if the implementation function is inlined,
and we are using a syscall declaration macro where a runtime check
is performed, that all memory access in the inlined implementation
function is done after the user context check is performed.

Fixes bad memory access issues observed due to the compiler fetching
member data from a kernel object when the calling context was in
user mode.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2017-10-16 16:16:56 -07:00

135 lines
3.6 KiB
Python
Executable File

#!/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 gen_make_syscall(ret, argc):
if (ret != Retval.VOID):
sys.stdout.write("return (ret)")
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:
sys.stdout.write("\t\t")
gen_make_syscall(ret, argc)
else:
sys.stdout.write("\t\tif (_is_user_context()) {")
newline()
sys.stdout.write("\t\t\t")
gen_make_syscall(ret, argc)
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")
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")