blob: 84759fc47e597bb10ed11805b5357ea6d85e2a30 [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
Ulf Magnusson0d39a102019-09-06 11:13:19 +020076kobjects = 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)),
Wentong Wu5611e922019-06-20 23:51:27 +080089 ("sys_mutex", (None, True)),
90 ("k_futex", (None, True))
Marc Herbertf78288b2019-03-05 14:31:44 -080091])
92
93
Andrew Boie5bd891d2017-09-27 12:59:28 -070094
95subsystems = [
Anas Nashif72565532017-12-12 08:19:25 -050096 "adc_driver_api",
97 "aio_cmp_driver_api",
98 "counter_driver_api",
99 "crypto_driver_api",
Andrew Boiece6c8f32018-02-09 13:58:37 -0800100 "dma_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500101 "flash_driver_api",
102 "gpio_driver_api",
103 "i2c_driver_api",
104 "i2s_driver_api",
105 "ipm_driver_api",
Manivannan Sadhasivam26babfc2018-05-03 23:46:58 +0530106 "led_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500107 "pinmux_driver_api",
108 "pwm_driver_api",
109 "entropy_driver_api",
110 "rtc_driver_api",
111 "sensor_driver_api",
112 "spi_driver_api",
113 "uart_driver_api",
Alexander Wachter8757e782019-02-07 17:57:43 +0100114 "can_driver_api",
Jukka Rissanenc9aaab72019-05-27 16:01:49 +0800115 "ptp_clock_driver_api",
Anas Nashif72565532017-12-12 08:19:25 -0500116]
Andrew Boie5bd891d2017-09-27 12:59:28 -0700117
118
Andrew Boie945af952017-08-22 13:15:23 -0700119header = """%compare-lengths
Patrik Flykt4344e272019-03-08 14:19:05 -0700120%define lookup-function-name z_object_lookup
Andrew Boie945af952017-08-22 13:15:23 -0700121%language=ANSI-C
Andrew Boie47f8fd12017-10-05 11:11:02 -0700122%global-table
Andrew Boie945af952017-08-22 13:15:23 -0700123%struct-type
124%{
125#include <kernel.h>
Andrew Boie31bdfc02017-11-08 16:38:03 -0800126#include <toolchain.h>
Andrew Boie47f8fd12017-10-05 11:11:02 -0700127#include <syscall_handler.h>
Andrew Boie945af952017-08-22 13:15:23 -0700128#include <string.h>
129%}
130struct _k_object;
Andrew Boie945af952017-08-22 13:15:23 -0700131"""
132
Andy Gross6042ae92018-01-22 14:26:49 -0600133# Different versions of gperf have different prototypes for the lookup
134# function, best to implement the wrapper here. The pointer value itself is
135# turned into a string, we told gperf to expect binary strings that are not
Anas Nashif72565532017-12-12 08:19:25 -0500136# NULL-terminated.
Andrew Boie945af952017-08-22 13:15:23 -0700137footer = """%%
Patrik Flykt4344e272019-03-08 14:19:05 -0700138struct _k_object *z_object_gperf_find(void *obj)
Andrew Boie945af952017-08-22 13:15:23 -0700139{
Patrik Flykt4344e272019-03-08 14:19:05 -0700140 return z_object_lookup((const char *)obj, sizeof(void *));
Andrew Boie945af952017-08-22 13:15:23 -0700141}
Andrew Boie47f8fd12017-10-05 11:11:02 -0700142
Patrik Flykt4344e272019-03-08 14:19:05 -0700143void z_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
Andrew Boie47f8fd12017-10-05 11:11:02 -0700144{
145 int i;
146
147 for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
Flavio Ceolin4218d5f2018-09-17 09:39:51 -0700148 if (wordlist[i].name != NULL) {
Andrew Boie47f8fd12017-10-05 11:11:02 -0700149 func(&wordlist[i], context);
150 }
151 }
152}
Andrew Boie31bdfc02017-11-08 16:38:03 -0800153
154#ifndef CONFIG_DYNAMIC_OBJECTS
Patrik Flykt4344e272019-03-08 14:19:05 -0700155struct _k_object *z_object_find(void *obj)
156 ALIAS_OF(z_object_gperf_find);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800157
Patrik Flykt4344e272019-03-08 14:19:05 -0700158void z_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
159 ALIAS_OF(z_object_gperf_wordlist_foreach);
Andrew Boie31bdfc02017-11-08 16:38:03 -0800160#endif
Andrew Boie945af952017-08-22 13:15:23 -0700161"""
162
163
Andy Gross6042ae92018-01-22 14:26:49 -0600164def write_gperf_table(fp, eh, objs, static_begin, static_end):
Andrew Boie945af952017-08-22 13:15:23 -0700165 fp.write(header)
Andrew Boief0835672019-03-27 15:44:52 -0700166 num_mutexes = eh.get_sys_mutex_counter()
Ulf Magnusson9d343562019-05-07 12:06:35 +0200167 if num_mutexes != 0:
Andrew Boief0835672019-03-27 15:44:52 -0700168 fp.write("static struct k_mutex kernel_mutexes[%d] = {\n" % num_mutexes)
169 for i in range(num_mutexes):
170 fp.write("_K_MUTEX_INITIALIZER(kernel_mutexes[%d])" % i)
Ulf Magnusson9d343562019-05-07 12:06:35 +0200171 if i != num_mutexes - 1:
Andrew Boief0835672019-03-27 15:44:52 -0700172 fp.write(", ")
173 fp.write("};\n")
Andrew Boie945af952017-08-22 13:15:23 -0700174
Wentong Wu5611e922019-06-20 23:51:27 +0800175 num_futex = eh.get_futex_counter()
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200176 if num_futex != 0:
Wentong Wu5611e922019-06-20 23:51:27 +0800177 fp.write("static struct z_futex_data futex_data[%d] = {\n" % num_futex)
178 for i in range(num_futex):
179 fp.write("Z_FUTEX_DATA_INITIALIZER(futex_data[%d])" % i)
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200180 if i != num_futex - 1:
Wentong Wu5611e922019-06-20 23:51:27 +0800181 fp.write(", ")
182 fp.write("};\n")
183
Andrew Boief0835672019-03-27 15:44:52 -0700184 fp.write("%%\n")
Daniel Leunge58b6542018-08-08 11:23:16 -0700185 # Setup variables for mapping thread indexes
186 syms = eh.get_symbols()
187 thread_max_bytes = syms["CONFIG_MAX_THREAD_BYTES"]
188 thread_idx_map = {}
189
190 for i in range(0, thread_max_bytes):
191 thread_idx_map[i] = 0xFF
192
Andrew Boiebca15da2017-10-15 14:17:48 -0700193 for obj_addr, ko in objs.items():
194 obj_type = ko.type_name
Andrew Boie945af952017-08-22 13:15:23 -0700195 # pre-initialized objects fall within this memory range, they are
196 # either completely initialized at build time, or done automatically
197 # at boot during some PRE_KERNEL_* phase
Ulf Magnusson3206e422019-09-03 15:05:01 +0200198 initialized = static_begin <= obj_addr < static_end
Andrew Boie78757072019-07-23 13:29:30 -0700199 is_driver = obj_type.startswith("K_OBJ_DRIVER_")
Andrew Boie945af952017-08-22 13:15:23 -0700200
Andy Gross6042ae92018-01-22 14:26:49 -0600201 byte_str = struct.pack("<I" if eh.little_endian else ">I", obj_addr)
Andrew Boie945af952017-08-22 13:15:23 -0700202 fp.write("\"")
203 for byte in byte_str:
204 val = "\\x%02x" % byte
205 fp.write(val)
206
Andrew Boie78757072019-07-23 13:29:30 -0700207 flags = "0"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200208 if initialized:
Andrew Boie78757072019-07-23 13:29:30 -0700209 flags += " | K_OBJ_FLAG_INITIALIZED"
Ulf Magnussond4c851c2019-09-02 11:11:22 +0200210 if is_driver:
Andrew Boie78757072019-07-23 13:29:30 -0700211 flags += " | K_OBJ_FLAG_DRIVER"
212
213 fp.write("\", {}, %s, %s, %s\n" % (obj_type, flags, str(ko.data)))
Andrew Boie945af952017-08-22 13:15:23 -0700214
Daniel Leunge58b6542018-08-08 11:23:16 -0700215 if obj_type == "K_OBJ_THREAD":
216 idx = math.floor(ko.data / 8)
217 bit = ko.data % 8
218 thread_idx_map[idx] = thread_idx_map[idx] & ~(2**bit)
219
Andrew Boie945af952017-08-22 13:15:23 -0700220 fp.write(footer)
221
Daniel Leunge58b6542018-08-08 11:23:16 -0700222 # Generate the array of already mapped thread indexes
223 fp.write('\n')
224 fp.write('u8_t _thread_idx_map[%d] = {' % (thread_max_bytes))
225
226 for i in range(0, thread_max_bytes):
227 fp.write(' 0x%x, ' % (thread_idx_map[i]))
228
229 fp.write('};\n')
230
Andrew Boie945af952017-08-22 13:15:23 -0700231
Leandro Pereirac2003672018-04-04 13:50:32 -0700232driver_macro_tpl = """
Andrew Boie8345e5e2018-05-04 15:57:57 -0700233#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 -0700234"""
235
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500236
Leandro Pereirac2003672018-04-04 13:50:32 -0700237def write_validation_output(fp):
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700238 fp.write("#ifndef DRIVER_VALIDATION_GEN_H\n")
239 fp.write("#define DRIVER_VALIDATION_GEN_H\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700240
Andrew Boie8345e5e2018-05-04 15:57:57 -0700241 fp.write("""#define Z_SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
242 (Z_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case) || \\
243 Z_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op))
244 """)
Leandro Pereirac2003672018-04-04 13:50:32 -0700245
246 for subsystem in subsystems:
247 subsystem = subsystem.replace("_driver_api", "")
248
249 fp.write(driver_macro_tpl % {
250 "driver_lower": subsystem.lower(),
251 "driver_upper": subsystem.upper(),
252 })
253
Flavio Ceolina7fffa92018-09-13 15:06:35 -0700254 fp.write("#endif /* DRIVER_VALIDATION_GEN_H */\n")
Leandro Pereirac2003672018-04-04 13:50:32 -0700255
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700256
257def write_kobj_types_output(fp):
258 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700259 for kobj, obj_info in kobjects.items():
260 dep, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700261 if kobj == "device":
262 continue
263
Andrew Boie09c22cc2018-06-27 10:25:45 -0700264 if dep:
265 fp.write("#ifdef %s\n" % dep)
266
Andrew Boief20efcf2018-05-23 10:57:39 -0700267 fp.write("%s,\n" % kobject_to_enum(kobj))
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700268
Andrew Boie09c22cc2018-06-27 10:25:45 -0700269 if dep:
270 fp.write("#endif\n")
271
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700272 fp.write("/* Driver subsystems */\n")
273 for subsystem in subsystems:
274 subsystem = subsystem.replace("_driver_api", "").upper()
275 fp.write("K_OBJ_DRIVER_%s,\n" % subsystem)
276
277
278def write_kobj_otype_output(fp):
279 fp.write("/* Core kernel objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700280 for kobj, obj_info in kobjects.items():
281 dep, _ = obj_info
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700282 if kobj == "device":
283 continue
284
Andrew Boie09c22cc2018-06-27 10:25:45 -0700285 if dep:
286 fp.write("#ifdef %s\n" % dep)
287
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500288 fp.write('case %s: ret = "%s"; break;\n' %
289 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700290 if dep:
291 fp.write("#endif\n")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700292
293 fp.write("/* Driver subsystems */\n")
294 for subsystem in subsystems:
295 subsystem = subsystem.replace("_driver_api", "")
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700296 fp.write('case K_OBJ_DRIVER_%s: ret = "%s driver"; break;\n' % (
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700297 subsystem.upper(),
298 subsystem
299 ))
300
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500301
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700302def write_kobj_size_output(fp):
303 fp.write("/* Non device/stack objects */\n")
Andrew Boiec235e162019-03-27 14:27:24 -0700304 for kobj, obj_info in kobjects.items():
305 dep, _ = obj_info
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700306 # device handled by default case. Stacks are not currently handled,
307 # if they eventually are it will be a special case.
Ulf Magnusson3feb8f92019-09-03 14:25:26 +0200308 if kobj in {"device", "_k_thread_stack_element"}:
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700309 continue
310
Andrew Boie09c22cc2018-06-27 10:25:45 -0700311 if dep:
312 fp.write("#ifdef %s\n" % dep)
313
Flavio Ceolin3259ac02018-09-11 13:14:21 -0700314 fp.write('case %s: ret = sizeof(struct %s); break;\n' %
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500315 (kobject_to_enum(kobj), kobj))
Andrew Boie09c22cc2018-06-27 10:25:45 -0700316 if dep:
317 fp.write("#endif\n")
318
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700319
Andrew Boie945af952017-08-22 13:15:23 -0700320def parse_args():
321 global args
322
Anas Nashif72565532017-12-12 08:19:25 -0500323 parser = argparse.ArgumentParser(
324 description=__doc__,
325 formatter_class=argparse.RawDescriptionHelpFormatter)
Andrew Boie945af952017-08-22 13:15:23 -0700326
Leandro Pereirac2003672018-04-04 13:50:32 -0700327 parser.add_argument("-k", "--kernel", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500328 help="Input zephyr ELF binary")
329 parser.add_argument(
Leandro Pereirac2003672018-04-04 13:50:32 -0700330 "-g", "--gperf-output", required=False,
Anas Nashif72565532017-12-12 08:19:25 -0500331 help="Output list of kernel object addresses for gperf use")
Leandro Pereirac2003672018-04-04 13:50:32 -0700332 parser.add_argument(
333 "-V", "--validation-output", required=False,
334 help="Output driver validation macros")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700335 parser.add_argument(
336 "-K", "--kobj-types-output", required=False,
Marc Herbert4a10eea2019-04-16 15:39:45 -0700337 help="Output k_object enum constants")
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700338 parser.add_argument(
339 "-S", "--kobj-otype-output", required=False,
340 help="Output case statements for otype_to_str()")
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700341 parser.add_argument(
342 "-Z", "--kobj-size-output", required=False,
343 help="Output case statements for obj_size_get()")
Andrew Boie945af952017-08-22 13:15:23 -0700344 parser.add_argument("-v", "--verbose", action="store_true",
Anas Nashif72565532017-12-12 08:19:25 -0500345 help="Print extra debugging information")
Andrew Boie945af952017-08-22 13:15:23 -0700346 args = parser.parse_args()
Sebastian Bøe4971d2a2017-12-28 17:34:50 +0100347 if "VERBOSE" in os.environ:
348 args.verbose = 1
Andrew Boie945af952017-08-22 13:15:23 -0700349
350
351def main():
352 parse_args()
353
Leandro Pereirac2003672018-04-04 13:50:32 -0700354 if args.gperf_output:
Marc Herbertf78288b2019-03-05 14:31:44 -0800355 assert args.kernel, "--kernel ELF required for --gperf-output"
Leandro Pereirac2003672018-04-04 13:50:32 -0700356 eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems)
357 syms = eh.get_symbols()
358 max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
359 objs = eh.find_kobjects(syms)
Marc Herbertf78288b2019-03-05 14:31:44 -0800360 if not objs:
361 sys.stderr.write("WARNING: zero kobject found in %s\n"
362 % args.kernel)
Andrew Boie945af952017-08-22 13:15:23 -0700363
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500364 thread_counter = eh.get_thread_counter()
365 if thread_counter > max_threads:
Ulf Magnusson50b9b122019-09-07 14:41:01 +0200366 sys.exit("Too many thread objects ({})\n"
367 "Increase CONFIG_MAX_THREAD_BYTES to {}"
368 .format(thread_counter, -(-thread_counter // 8)))
Andrew Boie818a96d2017-11-03 09:00:35 -0700369
Leandro Pereirac2003672018-04-04 13:50:32 -0700370 with open(args.gperf_output, "w") as fp:
371 write_gperf_table(fp, eh, objs,
372 syms["_static_kernel_objects_begin"],
373 syms["_static_kernel_objects_end"])
374
375 if args.validation_output:
376 with open(args.validation_output, "w") as fp:
377 write_validation_output(fp)
Anas Nashif72565532017-12-12 08:19:25 -0500378
Leandro Pereira39dc7d02018-04-05 13:59:33 -0700379 if args.kobj_types_output:
380 with open(args.kobj_types_output, "w") as fp:
381 write_kobj_types_output(fp)
382
383 if args.kobj_otype_output:
384 with open(args.kobj_otype_output, "w") as fp:
385 write_kobj_otype_output(fp)
Andrew Boie945af952017-08-22 13:15:23 -0700386
Andrew Boie47fa8eb2018-05-16 10:11:17 -0700387 if args.kobj_size_output:
388 with open(args.kobj_size_output, "w") as fp:
389 write_kobj_size_output(fp)
390
Anas Nashif7a08b2b2018-09-16 14:54:44 -0500391
Andrew Boie945af952017-08-22 13:15:23 -0700392if __name__ == "__main__":
393 main()