blob: c5559407df47e38c691eb7b5a57cd3e85dd011da [file] [log] [blame]
Andrew Boie945af952017-08-22 13:15:23 -07001#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Intel Corporation
4#
5# SPDX-License-Identifier: Apache-2.0
Andrew Boiec78c5e62019-03-11 14:45:43 -07006"""
7Script to generate gperf tables of kernel object metadata
8
9User mode threads making system calls reference kernel objects by memory
10address, as the kernel/driver APIs in Zephyr are the same for both user
11and supervisor contexts. It is necessary for the kernel to be able to
12validate accesses to kernel objects to make the following assertions:
13
14 - That the memory address points to a kernel object
15
16 - The kernel object is of the expected type for the API being invoked
17
18 - The kernel object is of the expected initialization state
19
20 - The calling thread has sufficient permissions on the object
21
Marc Herbert4a10eea2019-04-16 15:39:45 -070022For more details see the "Kernel Objects" section in the documentation.
23
Andrew Boiec78c5e62019-03-11 14:45:43 -070024The zephyr build generates an intermediate ELF binary, zephyr_prebuilt.elf,
25which this script scans looking for kernel objects by examining the DWARF
26debug information to look for instances of data structures that are considered
27kernel objects. For device drivers, the API struct pointer populated at build
28time is also examined to disambiguate between various device driver instances
29since they are all 'struct device'.
30
Marc Herbert4a10eea2019-04-16 15:39:45 -070031This script can generate five different output files:
Andrew Boiec78c5e62019-03-11 14:45:43 -070032
33 - A gperf script to generate the hash table mapping kernel object memory
34 addresses to kernel object metadata, used to track permissions,
35 object type, initialization state, and any object-specific data.
36
37 - A header file containing generated macros for validating driver instances
38 inside the system call handlers for the driver subsystem APIs.
39
Marc Herbert4a10eea2019-04-16 15:39:45 -070040 - A code fragment included by kernel.h with one enum constant for
41 each kernel object type and each driver instance.
Andrew Boiec78c5e62019-03-11 14:45:43 -070042
Marc Herbert4a10eea2019-04-16 15:39:45 -070043 - The inner cases of a switch/case C statement, included by
44 kernel/userspace.c, mapping the kernel object types and driver
45 instances to their human-readable representation in the
Andrew Boiec78c5e62019-03-11 14:45:43 -070046 otype_to_str() function.
47
Marc Herbert4a10eea2019-04-16 15:39:45 -070048 - The inner cases of a switch/case C statement, included by
49 kernel/userspace.c, mapping kernel object types to their sizes.
50 This is used for allocating instances of them at runtime
51 (CONFIG_DYNAMIC_OBJECTS) in the obj_size_get() function.
Andrew Boiec78c5e62019-03-11 14:45:43 -070052"""
Andrew Boie945af952017-08-22 13:15:23 -070053
54import sys
55import argparse
Daniel Leunge58b6542018-08-08 11:23:16 -070056import math
Andrew Boie945af952017-08-22 13:15:23 -070057import os
58import struct
Andrew Boief20efcf2018-05-23 10:57:39 -070059from elf_helper import ElfHelper, kobject_to_enum
Andrew Boie945af952017-08-22 13:15:23 -070060
Marc Herbertf78288b2019-03-05 14:31:44 -080061from collections import OrderedDict
62
Andrew Boie09c22cc2018-06-27 10:25:45 -070063# Keys in this dictionary are structs which should be recognized as kernel
Andrew Boiec235e162019-03-27 14:27:24 -070064# objects. Values are a tuple:
65#
66# - The first item is None, or the name of a Kconfig that
67# indicates the presence of this object's definition in case it is not
68# available in all configurations.
69#
70# - The second item is a boolean indicating whether it is permissible for
71# the object to be located in user-accessible memory.
Andrew Boie09c22cc2018-06-27 10:25:45 -070072
Marc Herbertf78288b2019-03-05 14:31:44 -080073# Regular dictionaries are ordered only with Python 3.6 and
74# above. Good summary and pointers to official documents at:
75# https://stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6
76kobjects = OrderedDict ([
Andrew Boiec235e162019-03-27 14:27:24 -070077 ("k_mem_slab", (None, False)),
78 ("k_msgq", (None, False)),
79 ("k_mutex", (None, False)),
80 ("k_pipe", (None, False)),
81 ("k_queue", (None, False)),
82 ("k_poll_signal", (None, False)),
83 ("k_sem", (None, False)),
84 ("k_stack", (None, False)),
85 ("k_thread", (None, False)),
86 ("k_timer", (None, False)),
87 ("_k_thread_stack_element", (None, False)),
Andrew Boiec235e162019-03-27 14:27:24 -070088 ("device", (None, False)),
Andrew Boief0835672019-03-27 15:44:52 -070089 ("sys_mutex", (None, True))
Marc Herbertf78288b2019-03-05 14:31:44 -080090])
91
92
Andrew Boie5bd891d2017-09-27 12:59:28 -070093
94subsystems = [
Anas Nashif72565532017-12-12 08:19:25 -050095 "adc_driver_api",
96 "aio_cmp_driver_api",
97 "counter_driver_api",
98 "crypto_driver_api",
Andrew Boiece6c8f32018-02-09 13:58:37 -080099 "dma_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500100 "flash_driver_api",
101 "gpio_driver_api",
102 "i2c_driver_api",
103 "i2s_driver_api",
104 "ipm_driver_api",
Manivannan Sadhasivam26babfc2018-05-03 23:46:58 +0530105 "led_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500106 "pinmux_driver_api",
107 "pwm_driver_api",
108 "entropy_driver_api",
109 "rtc_driver_api",
110 "sensor_driver_api",
111 "spi_driver_api",
112 "uart_driver_api",
Alexander Wachter8757e782019-02-07 17:57:43 +0100113 "can_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500114]
Andrew Boie5bd891d2017-09-27 12:59:28 -0700115
116
Andrew Boie945af952017-08-22 13:15:23 -0700117header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700118%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700119%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700120%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700121%struct-type
122%{
123#include <kernel.h>
Andrew Boie31bdfc02017-11-08 16:38:03 -0800124#include <toolchain.h>
Andrew Boie47f8fd12017-10-05 11:11:02 -0700125#include <syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700126#include <string.h>
127%}
128struct _k_object;
Andrew Boie945af952017-08-22 13:15:23 -0700129"""
130
Andy Gross6042ae92018-01-22 14:26:49 -0600131# Different versions of gperf have different prototypes for the lookup
132# function, best to implement the wrapper here. The pointer value itself is
133# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500134# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700135footer = """%%
Patrik Flykt4344e272019-03-08 14:19:05 -0700136struct _k_object *z_object_gperf_find(void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700137{
Patrik Flykt4344e272019-03-08 14:19:05 -0700138 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700139}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700140
Patrik Flykt4344e272019-03-08 14:19:05 -0700141void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700142{
143 int i;
144
145 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700146 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700147 func(&wordlist[i], context);
148 }
149 }
150}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800151
152#ifndef CONFIG_DYNAMIC_OBJECTS
Patrik Flykt4344e272019-03-08 14:19:05 -0700153struct _k_object *z_object_find(void *obj)
154 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800155
Patrik Flykt4344e272019-03-08 14:19:05 -0700156void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
157 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800158#endif
Andrew Boie945af952017-08-22 13:15:23 -0700159"""
160
161
Andy Gross6042ae92018-01-22 14:26:49 -0600162def write_gperf_table(fp, eh, objs, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700163 fp.write(header)
Andrew Boief0835672019-03-27 15:44:52 -0700164 num_mutexes = eh.get_sys_mutex_counter()
Ulf Magnusson9d343562019-05-07 12:06:35 +0200165 if num_mutexes != 0:
Andrew Boief0835672019-03-27 15:44:52 -0700166 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n" % num_mutexes)
167 for i in range(num_mutexes):
168 fp.write("_K_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Ulf Magnusson9d343562019-05-07 12:06:35 +0200169 if i != num_mutexes - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700170 fp.write(", ")
171 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700172
Andrew Boief0835672019-03-27 15:44:52 -0700173 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700174 # Setup variables for mapping thread indexes
175 syms = eh.get_symbols()
176 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
177 thread_idx_map = {}
178
179 for i in range(0, thread_max_bytes):
180 thread_idx_map[i] = 0xFF
181
Andrew Boiebca15da2017-10-15 14:17:48 -0700182 for obj_addr, ko in objs.items():
183 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700184 # pre-initialized objects fall within this memory range, they are
185 # either completely initialized at build time, or done automatically
186 # at boot during some PRE_KERNEL_* phase
187 initialized = obj_addr >= static_begin and obj_addr < static_end
188
Andy Gross6042ae92018-01-22 14:26:49 -0600189 byte_str = struct.pack("<I" if eh.little_endian else ">I", obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700190 fp.write("\"")
191 for byte in byte_str:
192 val = "\\x%02x" % byte
193 fp.write(val)
194
Anas Nashif72565532017-12-12 08:19:25 -0500195 fp.write(
Andrew Boiea00eff72019-03-27 14:30:17 -0700196 "\",{},%s,%s,%s\n" %
Anas Nashif72565532017-12-12 08:19:25 -0500197 (obj_type,
198 "K_OBJ_FLAG_INITIALIZED" if initialized else "0",
Andrew Boiea00eff72019-03-27 14:30:17 -0700199 str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700200
Daniel Leunge58b6542018-08-08 11:23:16 -0700201 if obj_type == "K_OBJ_THREAD":
202 idx = math.floor(ko.data / 8)
203 bit = ko.data % 8
204 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
205
Andrew Boie945af952017-08-22 13:15:23 -0700206 fp.write(footer)
207
Daniel Leunge58b6542018-08-08 11:23:16 -0700208 # Generate the array of already mapped thread indexes
209 fp.write('\n')
210 fp.write('u8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
211
212 for i in range(0, thread_max_bytes):
213 fp.write(' 0x%x, ' % (thread_idx_map[i]))
214
215 fp.write('};\n')
216
Andrew Boie945af952017-08-22 13:15:23 -0700217
Leandro Pereirac2003672018-04-04 13:50:32 -0700218driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700219#define Z_SYSCALL_DRIVER_%(driver_upper)s(ptr, op) Z_SYSCALL_DRIVER_GEN(ptr, op, %(driver_lower)s, %(driver_upper)s)
Leandro Pereirac2003672018-04-04 13:50:32 -0700220"""
221
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500222
Leandro Pereirac2003672018-04-04 13:50:32 -0700223def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700224 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
225 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700226
Andrew Boie8345e5e2018-05-04 15:57:57 -0700227 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
228 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
229 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
230 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700231
232 for subsystem in subsystems:
233 subsystem = subsystem.replace("_driver_api", "")
234
235 fp.write(driver_macro_tpl % {
236 "driver_lower": subsystem.lower(),
237 "driver_upper": subsystem.upper(),
238 })
239
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700240 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700241
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700242
243def write_kobj_types_output(fp):
244 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700245 for kobj, obj_info in kobjects.items():
246 dep, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700247 if kobj == "device":
248 continue
249
Andrew Boie09c22cc2018-06-27 10:25:45 -0700250 if dep:
251 fp.write("#ifdef %s\n" % dep)
252
Andrew Boief20efcf2018-05-23 10:57:39 -0700253 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700254
Andrew Boie09c22cc2018-06-27 10:25:45 -0700255 if dep:
256 fp.write("#endif\n")
257
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700258 fp.write("/* Driver subsystems */\n")
259 for subsystem in subsystems:
260 subsystem = subsystem.replace("_driver_api", "").upper()
261 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
262
263
264def write_kobj_otype_output(fp):
265 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700266 for kobj, obj_info in kobjects.items():
267 dep, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700268 if kobj == "device":
269 continue
270
Andrew Boie09c22cc2018-06-27 10:25:45 -0700271 if dep:
272 fp.write("#ifdef %s\n" % dep)
273
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500274 fp.write('case %s: ret = "%s"; break;\n' %
275 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700276 if dep:
277 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700278
279 fp.write("/* Driver subsystems */\n")
280 for subsystem in subsystems:
281 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700282 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700283 subsystem.upper(),
284 subsystem
285 ))
286
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500287
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700288def write_kobj_size_output(fp):
289 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700290 for kobj, obj_info in kobjects.items():
291 dep, _ = obj_info
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700292 # device handled by default case. Stacks are not currently handled,
293 # if they eventually are it will be a special case.
294 if kobj == "device" or kobj == "_k_thread_stack_element":
295 continue
296
Andrew Boie09c22cc2018-06-27 10:25:45 -0700297 if dep:
298 fp.write("#ifdef %s\n" % dep)
299
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700300 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500301 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700302 if dep:
303 fp.write("#endif\n")
304
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700305
Andrew Boie945af952017-08-22 13:15:23 -0700306def parse_args():
307 global args
308
Anas Nashif72565532017-12-12 08:19:25 -0500309 parser = argparse.ArgumentParser(
310 description=__doc__,
311 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700312
Leandro Pereirac2003672018-04-04 13:50:32 -0700313 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500314 help="Input zephyr ELF binary")
315 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700316 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500317 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700318 parser.add_argument(
319 "-V", "--validation-output", required=False,
320 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700321 parser.add_argument(
322 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700323 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700324 parser.add_argument(
325 "-S", "--kobj-otype-output", required=False,
326 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700327 parser.add_argument(
328 "-Z", "--kobj-size-output", required=False,
329 help="Output case statements for obj_size_get()")
Andrew Boie945af952017-08-22 13:15:23 -0700330 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500331 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700332 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100333 if "VERBOSE" in os.environ:
334 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700335
336
337def main():
338 parse_args()
339
Leandro Pereirac2003672018-04-04 13:50:32 -0700340 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -0800341 assert args.kernel, "--kernel ELF required for --gperf-output"
Leandro Pereirac2003672018-04-04 13:50:32 -0700342 eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems)
343 syms = eh.get_symbols()
344 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
345 objs = eh.find_kobjects(syms)
Marc Herbertf78288b2019-03-05 14:31:44 -0800346 if not objs:
347 sys.stderr.write("WARNING: zero kobject found in %s\n"
348 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -0700349
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500350 thread_counter = eh.get_thread_counter()
351 if thread_counter > max_threads:
Leandro Pereirac2003672018-04-04 13:50:32 -0700352 sys.stderr.write("Too many thread objects (%d)\n" % thread_counter)
Tomasz Gorochowik8adf39a2019-02-15 14:52:59 +0100353 sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n" %
Leandro Pereirac2003672018-04-04 13:50:32 -0700354 -(-thread_counter // 8))
355 sys.exit(1)
Andrew Boie818a96d2017-11-03 09:00:35 -0700356
Leandro Pereirac2003672018-04-04 13:50:32 -0700357 with open(args.gperf_output, "w") as fp:
358 write_gperf_table(fp, eh, objs,
359 syms["_static_kernel_objects_begin"],
360 syms["_static_kernel_objects_end"])
361
362 if args.validation_output:
363 with open(args.validation_output, "w") as fp:
364 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -0500365
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700366 if args.kobj_types_output:
367 with open(args.kobj_types_output, "w") as fp:
368 write_kobj_types_output(fp)
369
370 if args.kobj_otype_output:
371 with open(args.kobj_otype_output, "w") as fp:
372 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -0700373
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700374 if args.kobj_size_output:
375 with open(args.kobj_size_output, "w") as fp:
376 write_kobj_size_output(fp)
377
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500378
Andrew Boie945af952017-08-22 13:15:23 -0700379if __name__ == "__main__":
380 main()