blob: a22616ebb2b7b8a74a1529525923c0b5f7e28653 [file] [log] [blame]
Chunlin Han18560a02018-02-01 01:19:49 -06001#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Linaro Limited
4#
5# SPDX-License-Identifier: Apache-2.0
6
Andrew Boiec78c5e62019-03-11 14:45:43 -07007"""
8Script to generate gperf tables mapping threads to their privileged mode stacks
9
10Some MPU devices require that memory region definitions be aligned to their
11own size, which must be a power of two. This introduces difficulties in
12reserving memory for the thread's supervisor mode stack inline with the
13K_THREAD_STACK_DEFINE() macro.
14
15Instead, the stack used when a user thread elevates privileges is allocated
16elsewhere in memory, and a gperf table is created to be able to quickly
17determine where the supervisor mode stack is in memory. This is accomplished
18by scanning the DWARF debug information in zephyr_prebuilt.elf, identifying
19instances of 'struct k_thread', and emitting a gperf configuration file which
20allocates memory for each thread's privileged stack and creates the table
21mapping thread addresses to these stacks.
22"""
23
Chunlin Han18560a02018-02-01 01:19:49 -060024import sys
25import argparse
Chunlin Han18560a02018-02-01 01:19:49 -060026import struct
Andy Gross6042ae92018-01-22 14:26:49 -060027from elf_helper import ElfHelper
Chunlin Han18560a02018-02-01 01:19:49 -060028
Andrew Boiec235e162019-03-27 14:27:24 -070029kobjects = {
30 "_k_thread_stack_element": (None, False)
31}
Chunlin Han18560a02018-02-01 01:19:49 -060032
33
Chunlin Han18560a02018-02-01 01:19:49 -060034header = """%compare-lengths
Patrik Flykt7c0a2452019-03-14 09:20:46 -060035%define lookup-function-name z_priv_stack_map_lookup
Chunlin Han18560a02018-02-01 01:19:49 -060036%language=ANSI-C
37%global-table
38%struct-type
39"""
40
41
Ioannis Glaropoulos88959e72019-06-13 18:11:58 +020042# Each privilege stack buffer needs to respect the alignment
43# constraints as specified in arm/arch.h.
Andy Gross6042ae92018-01-22 14:26:49 -060044priv_stack_decl_temp = ("static u8_t __used"
Ioannis Glaropoulos88959e72019-06-13 18:11:58 +020045 " __aligned(Z_PRIVILEGE_STACK_ALIGN)"
Andy Gross6042ae92018-01-22 14:26:49 -060046 " priv_stack_%x[CONFIG_PRIVILEGED_STACK_SIZE];\n")
Chunlin Han18560a02018-02-01 01:19:49 -060047
48
49includes = """#include <kernel.h>
50#include <string.h>
51"""
52
53
54structure = """struct _k_priv_stack_map {
55 char *name;
56 u8_t *priv_stack_addr;
57};
58%%
59"""
60
61
Andy Gross6042ae92018-01-22 14:26:49 -060062# Different versions of gperf have different prototypes for the lookup
63# function, best to implement the wrapper here. The pointer value itself is
64# turned into a string, we told gperf to expect binary strings that are not
65# NULL-terminated.
Chunlin Han18560a02018-02-01 01:19:49 -060066footer = """%%
Patrik Flykt7c0a2452019-03-14 09:20:46 -060067u8_t *z_priv_stack_find(void *obj)
Chunlin Han18560a02018-02-01 01:19:49 -060068{
69 const struct _k_priv_stack_map *map =
Patrik Flykt7c0a2452019-03-14 09:20:46 -060070 z_priv_stack_map_lookup((const char *)obj, sizeof(void *));
Chunlin Han18560a02018-02-01 01:19:49 -060071 return map->priv_stack_addr;
72}
73"""
74
75
Ulf Magnusson1a27de02019-03-25 20:02:21 +010076def write_gperf_table(fp, eh, objs):
Chunlin Han18560a02018-02-01 01:19:49 -060077 fp.write(header)
78
79 # priv stack declarations
80 fp.write("%{\n")
81 fp.write(includes)
Ulf Magnusson12ba9df2019-03-19 19:28:24 +010082 for obj_addr in objs:
Chunlin Han18560a02018-02-01 01:19:49 -060083 fp.write(priv_stack_decl_temp % (obj_addr))
84 fp.write("%}\n")
85
86 # structure declaration
87 fp.write(structure)
88
Ulf Magnusson12ba9df2019-03-19 19:28:24 +010089 for obj_addr in objs:
Andy Gross6042ae92018-01-22 14:26:49 -060090 byte_str = struct.pack("<I" if eh.little_endian else ">I", obj_addr)
Chunlin Han18560a02018-02-01 01:19:49 -060091 fp.write("\"")
92 for byte in byte_str:
93 val = "\\x%02x" % byte
94 fp.write(val)
95
96 fp.write("\",priv_stack_%x\n" % obj_addr)
97
98 fp.write(footer)
99
100
Chunlin Han18560a02018-02-01 01:19:49 -0600101def parse_args():
102 global args
103
Andy Gross6042ae92018-01-22 14:26:49 -0600104 parser = argparse.ArgumentParser(
105 description=__doc__,
106 formatter_class=argparse.RawDescriptionHelpFormatter)
Chunlin Han18560a02018-02-01 01:19:49 -0600107
108 parser.add_argument("-k", "--kernel", required=True,
Andy Gross6042ae92018-01-22 14:26:49 -0600109 help="Input zephyr ELF binary")
110 parser.add_argument(
111 "-o", "--output", required=True,
112 help="Output list of kernel object addresses for gperf use")
Chunlin Han18560a02018-02-01 01:19:49 -0600113 parser.add_argument("-v", "--verbose", action="store_true",
Andy Gross6042ae92018-01-22 14:26:49 -0600114 help="Print extra debugging information")
Chunlin Han18560a02018-02-01 01:19:49 -0600115 args = parser.parse_args()
116
117
118def main():
119 parse_args()
120
Andy Gross6042ae92018-01-22 14:26:49 -0600121 eh = ElfHelper(args.kernel, args.verbose, kobjects, [])
122 syms = eh.get_symbols()
123 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
124 objs = eh.find_kobjects(syms)
Marc Herbertf78288b2019-03-05 14:31:44 -0800125 if not objs:
126 sys.stderr.write("WARNING: zero kobject found in %s\n"
127 % args.kernel)
Andy Gross6042ae92018-01-22 14:26:49 -0600128
Anas Nashif2e7bdb62018-09-16 14:56:07 -0500129 thread_counter = eh.get_thread_counter()
130 if thread_counter > max_threads:
Andy Gross6042ae92018-01-22 14:26:49 -0600131 sys.stderr.write("Too many thread objects (%d)\n" % thread_counter)
132 sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n",
133 -(-thread_counter // 8))
134 sys.exit(1)
Chunlin Han18560a02018-02-01 01:19:49 -0600135
136 with open(args.output, "w") as fp:
Ulf Magnusson1a27de02019-03-25 20:02:21 +0100137 write_gperf_table(fp, eh, objs)
Andy Gross6042ae92018-01-22 14:26:49 -0600138
Chunlin Han18560a02018-02-01 01:19:49 -0600139
140if __name__ == "__main__":
141 main()