forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgen_priv_stacks.py
executable file
·140 lines (107 loc) · 3.86 KB
/
gen_priv_stacks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/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_thread_stack_element": (None, False)
}
header = """%compare-lengths
%define lookup-function-name z_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 *z_priv_stack_find(void *obj)
{
const struct _k_priv_stack_map *map =
z_priv_stack_map_lookup((const char *)obj, sizeof(void *));
return map->priv_stack_addr;
}
"""
def write_gperf_table(fp, eh, objs):
fp.write(header)
# priv stack declarations
fp.write("%{\n")
fp.write(includes)
for obj_addr in objs:
fp.write(priv_stack_decl_temp % (obj_addr))
fp.write("%}\n")
# structure declaration
fp.write(structure)
for obj_addr in objs:
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)
if __name__ == "__main__":
main()