2017-08-22 22:15:23 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
#
|
|
|
|
# Copyright (c) 2017 Intel Corporation
|
|
|
|
#
|
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import argparse
|
|
|
|
import pprint
|
|
|
|
import os
|
|
|
|
import struct
|
2018-01-22 21:26:49 +01:00
|
|
|
from elf_helper import ElfHelper
|
2017-08-22 22:15:23 +02:00
|
|
|
|
2017-09-27 21:59:28 +02:00
|
|
|
kobjects = [
|
2017-12-12 14:19:25 +01:00
|
|
|
"k_alert",
|
|
|
|
"k_msgq",
|
|
|
|
"k_mutex",
|
|
|
|
"k_pipe",
|
|
|
|
"k_sem",
|
|
|
|
"k_stack",
|
|
|
|
"k_thread",
|
|
|
|
"k_timer",
|
|
|
|
"_k_thread_stack_element",
|
|
|
|
"device"
|
|
|
|
]
|
2017-09-27 21:59:28 +02:00
|
|
|
|
|
|
|
subsystems = [
|
2017-12-12 14:19:25 +01:00
|
|
|
"adc_driver_api",
|
|
|
|
"aio_cmp_driver_api",
|
|
|
|
"counter_driver_api",
|
|
|
|
"crypto_driver_api",
|
2018-02-09 22:58:37 +01:00
|
|
|
"dma_driver_api",
|
2017-12-12 14:19:25 +01:00
|
|
|
"flash_driver_api",
|
|
|
|
"gpio_driver_api",
|
|
|
|
"i2c_driver_api",
|
|
|
|
"i2s_driver_api",
|
|
|
|
"ipm_driver_api",
|
|
|
|
"pinmux_driver_api",
|
|
|
|
"pwm_driver_api",
|
|
|
|
"entropy_driver_api",
|
|
|
|
"rtc_driver_api",
|
|
|
|
"sensor_driver_api",
|
|
|
|
"spi_driver_api",
|
|
|
|
"uart_driver_api",
|
|
|
|
]
|
2017-09-27 21:59:28 +02:00
|
|
|
|
|
|
|
|
2017-08-22 22:15:23 +02:00
|
|
|
header = """%compare-lengths
|
|
|
|
%define lookup-function-name _k_object_lookup
|
|
|
|
%language=ANSI-C
|
2017-10-05 20:11:02 +02:00
|
|
|
%global-table
|
2017-08-22 22:15:23 +02:00
|
|
|
%struct-type
|
|
|
|
%{
|
|
|
|
#include <kernel.h>
|
2017-11-09 01:38:03 +01:00
|
|
|
#include <toolchain.h>
|
2017-10-05 20:11:02 +02:00
|
|
|
#include <syscall_handler.h>
|
2017-08-22 22:15:23 +02:00
|
|
|
#include <string.h>
|
|
|
|
%}
|
|
|
|
struct _k_object;
|
|
|
|
%%
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
2018-01-22 21:26:49 +01:00
|
|
|
# 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
|
2017-12-12 14:19:25 +01:00
|
|
|
# NULL-terminated.
|
2017-08-22 22:15:23 +02:00
|
|
|
footer = """%%
|
2017-11-09 01:38:03 +01:00
|
|
|
struct _k_object *_k_object_gperf_find(void *obj)
|
2017-08-22 22:15:23 +02:00
|
|
|
{
|
|
|
|
return _k_object_lookup((const char *)obj, sizeof(void *));
|
|
|
|
}
|
2017-10-05 20:11:02 +02:00
|
|
|
|
2017-11-09 01:38:03 +01:00
|
|
|
void _k_object_gperf_wordlist_foreach(_wordlist_cb_func_t func, void *context)
|
2017-10-05 20:11:02 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = MIN_HASH_VALUE; i <= MAX_HASH_VALUE; i++) {
|
|
|
|
if (wordlist[i].name) {
|
|
|
|
func(&wordlist[i], context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-11-09 01:38:03 +01:00
|
|
|
|
|
|
|
#ifndef CONFIG_DYNAMIC_OBJECTS
|
|
|
|
struct _k_object *_k_object_find(void *obj)
|
|
|
|
ALIAS_OF(_k_object_gperf_find);
|
|
|
|
|
|
|
|
void _k_object_wordlist_foreach(_wordlist_cb_func_t func, void *context)
|
|
|
|
ALIAS_OF(_k_object_gperf_wordlist_foreach);
|
|
|
|
#endif
|
2017-08-22 22:15:23 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
2018-01-22 21:26:49 +01:00
|
|
|
def write_gperf_table(fp, eh, objs, static_begin, static_end):
|
2017-08-22 22:15:23 +02:00
|
|
|
fp.write(header)
|
|
|
|
|
2017-10-15 23:17:48 +02:00
|
|
|
for obj_addr, ko in objs.items():
|
|
|
|
obj_type = ko.type_name
|
2017-08-22 22:15:23 +02:00
|
|
|
# pre-initialized objects fall within this memory range, they are
|
|
|
|
# either completely initialized at build time, or done automatically
|
|
|
|
# at boot during some PRE_KERNEL_* phase
|
|
|
|
initialized = obj_addr >= static_begin and obj_addr < static_end
|
|
|
|
|
2018-01-22 21:26:49 +01:00
|
|
|
byte_str = struct.pack("<I" if eh.little_endian else ">I", obj_addr)
|
2017-08-22 22:15:23 +02:00
|
|
|
fp.write("\"")
|
|
|
|
for byte in byte_str:
|
|
|
|
val = "\\x%02x" % byte
|
|
|
|
fp.write(val)
|
|
|
|
|
2017-12-12 14:19:25 +01:00
|
|
|
fp.write(
|
|
|
|
"\",{},%s,%s,%d\n" %
|
|
|
|
(obj_type,
|
|
|
|
"K_OBJ_FLAG_INITIALIZED" if initialized else "0",
|
|
|
|
ko.data))
|
2017-08-22 22:15:23 +02:00
|
|
|
|
|
|
|
fp.write(footer)
|
|
|
|
|
|
|
|
|
2018-04-04 22:50:32 +02:00
|
|
|
driver_macro_tpl = """
|
|
|
|
#define _SYSCALL_DRIVER_%(driver_upper)s(ptr, op) _SYSCALL_DRIVER_GEN(ptr, op, %(driver_lower)s, %(driver_upper)s)
|
|
|
|
"""
|
|
|
|
|
|
|
|
def write_validation_output(fp):
|
|
|
|
fp.write("#ifndef __DRIVER_VALIDATION_GEN_H__\n")
|
|
|
|
fp.write("#define __DRIVER_VALIDATION_GEN_H__\n")
|
|
|
|
|
|
|
|
fp.write("""#define _SYSCALL_DRIVER_GEN(ptr, op, driver_lower_case, driver_upper_case) \\
|
|
|
|
do { \\
|
|
|
|
_SYSCALL_OBJ(ptr, K_OBJ_DRIVER_##driver_upper_case); \\
|
|
|
|
_SYSCALL_DRIVER_OP(ptr, driver_lower_case##_driver_api, op); \\
|
|
|
|
} while (0)\n\n""");
|
|
|
|
|
|
|
|
for subsystem in subsystems:
|
|
|
|
subsystem = subsystem.replace("_driver_api", "")
|
|
|
|
|
|
|
|
fp.write(driver_macro_tpl % {
|
|
|
|
"driver_lower": subsystem.lower(),
|
|
|
|
"driver_upper": subsystem.upper(),
|
|
|
|
})
|
|
|
|
|
|
|
|
fp.write("#endif /* __DRIVER_VALIDATION_GEN_H__ */\n")
|
|
|
|
|
2017-08-22 22:15:23 +02:00
|
|
|
def parse_args():
|
|
|
|
global args
|
|
|
|
|
2017-12-12 14:19:25 +01:00
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description=__doc__,
|
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
2017-08-22 22:15:23 +02:00
|
|
|
|
2018-04-04 22:50:32 +02:00
|
|
|
parser.add_argument("-k", "--kernel", required=False,
|
2017-12-12 14:19:25 +01:00
|
|
|
help="Input zephyr ELF binary")
|
|
|
|
parser.add_argument(
|
2018-04-04 22:50:32 +02:00
|
|
|
"-g", "--gperf-output", required=False,
|
2017-12-12 14:19:25 +01:00
|
|
|
help="Output list of kernel object addresses for gperf use")
|
2018-04-04 22:50:32 +02:00
|
|
|
parser.add_argument(
|
|
|
|
"-V", "--validation-output", required=False,
|
|
|
|
help="Output driver validation macros")
|
2017-08-22 22:15:23 +02:00
|
|
|
parser.add_argument("-v", "--verbose", action="store_true",
|
2017-12-12 14:19:25 +01:00
|
|
|
help="Print extra debugging information")
|
2017-08-22 22:15:23 +02:00
|
|
|
args = parser.parse_args()
|
2017-12-28 17:34:50 +01:00
|
|
|
if "VERBOSE" in os.environ:
|
|
|
|
args.verbose = 1
|
2017-08-22 22:15:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
parse_args()
|
|
|
|
|
2018-04-04 22:50:32 +02:00
|
|
|
if args.gperf_output:
|
|
|
|
eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems)
|
|
|
|
syms = eh.get_symbols()
|
|
|
|
max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8
|
|
|
|
objs = eh.find_kobjects(syms)
|
|
|
|
|
|
|
|
if eh.get_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.gperf_output, "w") as fp:
|
|
|
|
write_gperf_table(fp, eh, objs,
|
|
|
|
syms["_static_kernel_objects_begin"],
|
|
|
|
syms["_static_kernel_objects_end"])
|
|
|
|
|
|
|
|
if args.validation_output:
|
|
|
|
with open(args.validation_output, "w") as fp:
|
|
|
|
write_validation_output(fp)
|
2017-12-12 14:19:25 +01:00
|
|
|
|
2017-08-22 22:15:23 +02:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|