Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (c) 2017 Intel Corporation |
| 4 | # |
| 5 | # SPDX-License-Identifier: Apache-2.0 |
| 6 | |
| 7 | import sys |
| 8 | import argparse |
| 9 | import pprint |
| 10 | import os |
| 11 | import struct |
Andy Gross | 6042ae9 | 2018-01-22 14:26:49 -0600 | [diff] [blame] | 12 | from elf_helper import ElfHelper |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 13 | |
Andrew Boie | 5bd891d | 2017-09-27 12:59:28 -0700 | [diff] [blame] | 14 | kobjects = [ |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 15 | "k_alert", |
| 16 | "k_msgq", |
| 17 | "k_mutex", |
| 18 | "k_pipe", |
| 19 | "k_sem", |
| 20 | "k_stack", |
| 21 | "k_thread", |
| 22 | "k_timer", |
| 23 | "_k_thread_stack_element", |
| 24 | "device" |
| 25 | ] |
Andrew Boie | 5bd891d | 2017-09-27 12:59:28 -0700 | [diff] [blame] | 26 | |
| 27 | subsystems = [ |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 28 | "adc_driver_api", |
| 29 | "aio_cmp_driver_api", |
| 30 | "counter_driver_api", |
| 31 | "crypto_driver_api", |
Andrew Boie | ce6c8f3 | 2018-02-09 13:58:37 -0800 | [diff] [blame] | 32 | "dma_driver_api", |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 33 | "flash_driver_api", |
| 34 | "gpio_driver_api", |
| 35 | "i2c_driver_api", |
| 36 | "i2s_driver_api", |
| 37 | "ipm_driver_api", |
Manivannan Sadhasivam | 26babfc | 2018-05-03 23:46:58 +0530 | [diff] [blame] | 38 | "led_driver_api", |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 39 | "pinmux_driver_api", |
| 40 | "pwm_driver_api", |
| 41 | "entropy_driver_api", |
| 42 | "rtc_driver_api", |
| 43 | "sensor_driver_api", |
| 44 | "spi_driver_api", |
| 45 | "uart_driver_api", |
| 46 | ] |
Andrew Boie | 5bd891d | 2017-09-27 12:59:28 -0700 | [diff] [blame] | 47 | |
| 48 | |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 49 | header = """%compare-lengths |
| 50 | %define lookup-function-name _k_object_lookup |
| 51 | %language=ANSI-C |
Andrew Boie | 47f8fd1 | 2017-10-05 11:11:02 -0700 | [diff] [blame] | 52 | %global-table |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 53 | %struct-type |
| 54 | %{ |
| 55 | #include <kernel.h> |
Andrew Boie | 31bdfc0 | 2017-11-08 16:38:03 -0800 | [diff] [blame] | 56 | #include <toolchain.h> |
Andrew Boie | 47f8fd1 | 2017-10-05 11:11:02 -0700 | [diff] [blame] | 57 | #include <syscall_handler.h> |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 58 | #include <string.h> |
| 59 | %} |
| 60 | struct _k_object; |
| 61 | %% |
| 62 | """ |
| 63 | |
| 64 | |
Andy Gross | 6042ae9 | 2018-01-22 14:26:49 -0600 | [diff] [blame] | 65 | # Different versions of gperf have different prototypes for the lookup |
| 66 | # function, best to implement the wrapper here. The pointer value itself is |
| 67 | # turned into a string, we told gperf to expect binary strings that are not |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 68 | # NULL-terminated. |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 69 | footer = """%% |
Andrew Boie | 31bdfc0 | 2017-11-08 16:38:03 -0800 | [diff] [blame] | 70 | struct _k_object *_k_object_gperf_find(void *obj) |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 71 | { |
| 72 | return _k_object_lookup((const char *)obj, sizeof(void *)); |
| 73 | } |
Andrew Boie | 47f8fd1 | 2017-10-05 11:11:02 -0700 | [diff] [blame] | 74 | |
Andrew Boie | 31bdfc0 | 2017-11-08 16:38:03 -0800 | [diff] [blame] | 75 | void _k_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context) |
Andrew Boie | 47f8fd1 | 2017-10-05 11:11:02 -0700 | [diff] [blame] | 76 | { |
| 77 | int i; |
| 78 | |
| 79 | for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) { |
| 80 | if (wordlist[i].name) { |
| 81 | func(&wordlist[i], context); |
| 82 | } |
| 83 | } |
| 84 | } |
Andrew Boie | 31bdfc0 | 2017-11-08 16:38:03 -0800 | [diff] [blame] | 85 | |
| 86 | #ifndef CONFIG_DYNAMIC_OBJECTS |
| 87 | struct _k_object *_k_object_find(void *obj) |
| 88 | ALIAS_OF(_k_object_gperf_find); |
| 89 | |
| 90 | void _k_object_wordlist_foreach(_wordlist_cb_func_t func, void *context) |
| 91 | ALIAS_OF(_k_object_gperf_wordlist_foreach); |
| 92 | #endif |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 93 | """ |
| 94 | |
| 95 | |
Andy Gross | 6042ae9 | 2018-01-22 14:26:49 -0600 | [diff] [blame] | 96 | def write_gperf_table(fp, eh, objs, static_begin, static_end): |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 97 | fp.write(header) |
| 98 | |
Andrew Boie | bca15da | 2017-10-15 14:17:48 -0700 | [diff] [blame] | 99 | for obj_addr, ko in objs.items(): |
| 100 | obj_type = ko.type_name |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 101 | # pre-initialized objects fall within this memory range, they are |
| 102 | # either completely initialized at build time, or done automatically |
| 103 | # at boot during some PRE_KERNEL_* phase |
| 104 | initialized = obj_addr >= static_begin and obj_addr < static_end |
| 105 | |
Andy Gross | 6042ae9 | 2018-01-22 14:26:49 -0600 | [diff] [blame] | 106 | byte_str = struct.pack("<I" if eh.little_endian else ">I", obj_addr) |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 107 | fp.write("\"") |
| 108 | for byte in byte_str: |
| 109 | val = "\\x%02x" % byte |
| 110 | fp.write(val) |
| 111 | |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 112 | fp.write( |
| 113 | "\",{},%s,%s,%d\n" % |
| 114 | (obj_type, |
| 115 | "K_OBJ_FLAG_INITIALIZED" if initialized else "0", |
| 116 | ko.data)) |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 117 | |
| 118 | fp.write(footer) |
| 119 | |
| 120 | |
Leandro Pereira | c200367 | 2018-04-04 13:50:32 -0700 | [diff] [blame] | 121 | driver_macro_tpl = """ |
| 122 | #define _SYSCALL_DRIVER_%(driver_upper)s(ptr, op) _SYSCALL_DRIVER_GEN(ptr, op, %(driver_lower)s, %(driver_upper)s) |
| 123 | """ |
| 124 | |
| 125 | def write_validation_output(fp): |
| 126 | fp.write("#ifndef __DRIVER_VALIDATION_GEN_H__\n") |
| 127 | fp.write("#define __DRIVER_VALIDATION_GEN_H__\n") |
| 128 | |
| 129 | fp.write("""#define _SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\ |
| 130 | do { \\ |
| 131 | _SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case); \\ |
| 132 | _SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op); \\ |
| 133 | } while (0)\n\n"""); |
| 134 | |
| 135 | for subsystem in subsystems: |
| 136 | subsystem = subsystem.replace("_driver_api", "") |
| 137 | |
| 138 | fp.write(driver_macro_tpl % { |
| 139 | "driver_lower": subsystem.lower(), |
| 140 | "driver_upper": subsystem.upper(), |
| 141 | }) |
| 142 | |
| 143 | fp.write("#endif /* __DRIVER_VALIDATION_GEN_H__ */\n") |
| 144 | |
Leandro Pereira | 39dc7d0 | 2018-04-05 13:59:33 -0700 | [diff] [blame] | 145 | |
| 146 | def write_kobj_types_output(fp): |
| 147 | fp.write("/* Core kernel objects */\n") |
| 148 | for kobj in kobjects: |
| 149 | if kobj == "device": |
| 150 | continue |
| 151 | |
| 152 | if kobj.startswith("k_"): |
| 153 | kobj = kobj[2:] |
| 154 | elif kobj.startswith("_k_"): |
| 155 | kobj = kobj[2:] |
| 156 | |
| 157 | fp.write("K_OBJ_%s,\n" % kobj.upper()) |
| 158 | |
| 159 | fp.write("/* Driver subsystems */\n") |
| 160 | for subsystem in subsystems: |
| 161 | subsystem = subsystem.replace("_driver_api", "").upper() |
| 162 | fp.write("K_OBJ_DRIVER_%s,\n" % subsystem) |
| 163 | |
| 164 | |
| 165 | def write_kobj_otype_output(fp): |
| 166 | fp.write("/* Core kernel objects */\n") |
| 167 | for kobj in kobjects: |
| 168 | if kobj == "device": |
| 169 | continue |
| 170 | |
| 171 | if kobj.startswith("k_"): |
| 172 | kobj = kobj[2:] |
| 173 | elif kobj.startswith("_k_"): |
| 174 | kobj = kobj[2:] |
| 175 | |
| 176 | fp.write('case K_OBJ_%s: return "%s";\n' % ( |
| 177 | kobj.upper(), |
| 178 | kobj |
| 179 | )) |
| 180 | |
| 181 | fp.write("/* Driver subsystems */\n") |
| 182 | for subsystem in subsystems: |
| 183 | subsystem = subsystem.replace("_driver_api", "") |
| 184 | fp.write('case K_OBJ_DRIVER_%s: return "%s driver";\n' % ( |
| 185 | subsystem.upper(), |
| 186 | subsystem |
| 187 | )) |
| 188 | |
| 189 | |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 190 | def parse_args(): |
| 191 | global args |
| 192 | |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 193 | parser = argparse.ArgumentParser( |
| 194 | description=__doc__, |
| 195 | formatter_class=argparse.RawDescriptionHelpFormatter) |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 196 | |
Leandro Pereira | c200367 | 2018-04-04 13:50:32 -0700 | [diff] [blame] | 197 | parser.add_argument("-k", "--kernel", required=False, |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 198 | help="Input zephyr ELF binary") |
| 199 | parser.add_argument( |
Leandro Pereira | c200367 | 2018-04-04 13:50:32 -0700 | [diff] [blame] | 200 | "-g", "--gperf-output", required=False, |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 201 | help="Output list of kernel object addresses for gperf use") |
Leandro Pereira | c200367 | 2018-04-04 13:50:32 -0700 | [diff] [blame] | 202 | parser.add_argument( |
| 203 | "-V", "--validation-output", required=False, |
| 204 | help="Output driver validation macros") |
Leandro Pereira | 39dc7d0 | 2018-04-05 13:59:33 -0700 | [diff] [blame] | 205 | parser.add_argument( |
| 206 | "-K", "--kobj-types-output", required=False, |
| 207 | help="Output k_object enum values") |
| 208 | parser.add_argument( |
| 209 | "-S", "--kobj-otype-output", required=False, |
| 210 | help="Output case statements for otype_to_str()") |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 211 | parser.add_argument("-v", "--verbose", action="store_true", |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 212 | help="Print extra debugging information") |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 213 | args = parser.parse_args() |
Sebastian Bøe | 4971d2a | 2017-12-28 17:34:50 +0100 | [diff] [blame] | 214 | if "VERBOSE" in os.environ: |
| 215 | args.verbose = 1 |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 216 | |
| 217 | |
| 218 | def main(): |
| 219 | parse_args() |
| 220 | |
Leandro Pereira | c200367 | 2018-04-04 13:50:32 -0700 | [diff] [blame] | 221 | if args.gperf_output: |
| 222 | eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems) |
| 223 | syms = eh.get_symbols() |
| 224 | max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8 |
| 225 | objs = eh.find_kobjects(syms) |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 226 | |
Leandro Pereira | c200367 | 2018-04-04 13:50:32 -0700 | [diff] [blame] | 227 | if eh.get_thread_counter() > max_threads: |
| 228 | sys.stderr.write("Too many thread objects (%d)\n" % thread_counter) |
| 229 | sys.stderr.write("Increase CONFIG_MAX_THREAD_BYTES to %d\n", |
| 230 | -(-thread_counter // 8)) |
| 231 | sys.exit(1) |
Andrew Boie | 818a96d | 2017-11-03 09:00:35 -0700 | [diff] [blame] | 232 | |
Leandro Pereira | c200367 | 2018-04-04 13:50:32 -0700 | [diff] [blame] | 233 | with open(args.gperf_output, "w") as fp: |
| 234 | write_gperf_table(fp, eh, objs, |
| 235 | syms["_static_kernel_objects_begin"], |
| 236 | syms["_static_kernel_objects_end"]) |
| 237 | |
| 238 | if args.validation_output: |
| 239 | with open(args.validation_output, "w") as fp: |
| 240 | write_validation_output(fp) |
Anas Nashif | 7256553 | 2017-12-12 08:19:25 -0500 | [diff] [blame] | 241 | |
Leandro Pereira | 39dc7d0 | 2018-04-05 13:59:33 -0700 | [diff] [blame] | 242 | if args.kobj_types_output: |
| 243 | with open(args.kobj_types_output, "w") as fp: |
| 244 | write_kobj_types_output(fp) |
| 245 | |
| 246 | if args.kobj_otype_output: |
| 247 | with open(args.kobj_otype_output, "w") as fp: |
| 248 | write_kobj_otype_output(fp) |
Andrew Boie | 945af95 | 2017-08-22 13:15:23 -0700 | [diff] [blame] | 249 | |
| 250 | if __name__ == "__main__": |
| 251 | main() |