zephyr/scripts/gen_priv_stacks.py
Andrew Boie c78c5e6936 userspace: add additional script documentation
We have several scripts used by the build system related
to generating code for system calls, privileged mode stacks,
kernel object metadata, and application shared memory
partitions. Add some overview documentation for each.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
2019-03-12 08:37:58 +01:00

143 lines
4.0 KiB
Python
Executable File

#!/usr/bin/env python3
#
# Copyright (c) 2017 Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
"""
Script to generate gperf tables mapping threads to their privileged mode stacks
Some MPU devices require that memory region definitions be aligned to their
own size, which must be a power of two. This introduces difficulties in
reserving memory for the thread's supervisor mode stack inline with the
K_THREAD_STACK_DEFINE() macro.
Instead, the stack used when a user thread elevates privileges is allocated
elsewhere in memory, and a gperf table is created to be able to quickly
determine where the supervisor mode stack is in memory. This is accomplished
by scanning the DWARF debug information in zephyr_prebuilt.elf, identifying
instances of 'struct k_thread', and emitting a gperf configuration file which
allocates memory for each thread's privileged stack and creates the table
mapping thread addresses to these stacks.
"""
import sys
import argparse
import struct
from elf_helper import ElfHelper
kobjects = [
"k_stack",
"_k_thread_stack_element",
]
header = """%compare-lengths
%define lookup-function-name _k_priv_stack_map_lookup
%language=ANSI-C
%global-table
%struct-type
"""
priv_stack_decl_temp = ("static u8_t __used"
" __aligned(CONFIG_PRIVILEGED_STACK_SIZE)"
" priv_stack_%x[CONFIG_PRIVILEGED_STACK_SIZE];\n")
priv_stack_decl_size = "CONFIG_PRIVILEGED_STACK_SIZE"
includes = """#include <kernel.h>
#include <string.h>
"""
structure = """struct _k_priv_stack_map {
char *name;
u8_t *priv_stack_addr;
};
%%
"""
# Different versions of gperf have different prototypes for the lookup
# function, best to implement the wrapper here. The pointer value itself is
# turned into a string, we told gperf to expect binary strings that are not
# NULL-terminated.
footer = """%%
u8_t *_k_priv_stack_find(void *obj)
{
const struct _k_priv_stack_map *map =
_k_priv_stack_map_lookup((const char *)obj, sizeof(void *));
return map->priv_stack_addr;
}
"""
def write_gperf_table(fp, eh, objs, static_begin, static_end):
fp.write(header)
# priv stack declarations
fp.write("%{\n")
fp.write(includes)
for obj_addr, ko in objs.items():
fp.write(priv_stack_decl_temp % (obj_addr))
fp.write("%}\n")
# structure declaration
fp.write(structure)
for obj_addr, ko in objs.items():
byte_str = struct.pack("<I" if eh.little_endian else ">I", obj_addr)
fp.write("\"")
for byte in byte_str:
val = "\\x%02x" % byte
fp.write(val)
fp.write("\",priv_stack_%x\n" % obj_addr)
fp.write(footer)
def parse_args():
global args
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-k", "--kernel", required=True,
help="Input zephyr ELF binary")
parser.add_argument(
"-o", "--output", required=True,
help="Output list of kernel object addresses for gperf use")
parser.add_argument("-v", "--verbose", action="store_true",
help="Print extra debugging information")
args = parser.parse_args()
def main():
parse_args()
eh = ElfHelper(args.kernel, args.verbose, kobjects, [])
syms = eh.get_symbols()
max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
objs = eh.find_kobjects(syms)
if not objs:
sys.stderr.write("WARNING: zero kobject found in %s\n"
% args.kernel)
thread_counter = eh.get_thread_counter()
if thread_counter > max_threads:
sys.stderr.write("Too many thread objects (%d)\n" % thread_counter)
sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n",
-(-thread_counter // 8))
sys.exit(1)
with open(args.output, "w") as fp:
write_gperf_table(fp, eh, objs, syms["_static_kernel_objects_begin"],
syms["_static_kernel_objects_end"])
if __name__ == "__main__":
main()