From 39dc7d03f706d9983ac7583047712457f4c54b05 Mon Sep 17 00:00:00 2001 From: Leandro Pereira Date: Thu, 5 Apr 2018 13:59:33 -0700 Subject: [PATCH] scripts: gen_kobject_list: Generate enums and case statements Adding a new kernel object type or driver subsystem requires changes in various different places. This patch makes it easier to create those devices by generating as much as possible in compile time. No behavior change. Signed-off-by: Leandro Pereira --- CMakeLists.txt | 3 ++ cmake/kobj.cmake | 27 ++++++++++++ doc/kernel/usermode/kernelobjects.rst | 14 ------- doc/kernel/usermode/syscalls.rst | 6 ++- kernel/userspace.c | 59 ++------------------------- scripts/gen_kobject_list.py | 58 ++++++++++++++++++++++++++ tests/unit/lib/crc/CMakeLists.txt | 2 +- tests/unit/unittest.cmake | 11 +++-- 8 files changed, 106 insertions(+), 74 deletions(-) create mode 100644 cmake/kobj.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 8485612b6ed..d016150cc4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -376,6 +376,8 @@ add_custom_command( ) add_custom_target(driver_validation_h_target DEPENDS ${DRV_VALIDATION}) +include($ENV{ZEPHYR_BASE}/cmake/kobj.cmake) +gen_kobj(KOBJ_INCLUDE_PATH) # Generate offsets.c.obj from offsets.c # Generate offsets.h from offsets.c.obj @@ -390,6 +392,7 @@ add_dependencies( offsets syscall_list_h_target syscall_macros_h_target driver_validation_h_target + kobj_types_h_target ) add_custom_command( diff --git a/cmake/kobj.cmake b/cmake/kobj.cmake new file mode 100644 index 00000000000..b9e5dba75e0 --- /dev/null +++ b/cmake/kobj.cmake @@ -0,0 +1,27 @@ +function(gen_kobj gen_dir_out) + if (PROJECT_BINARY_DIR) + set(gen_dir ${PROJECT_BINARY_DIR}/include/generated) + else () + set(gen_dir ${CMAKE_BINARY_DIR}/include/generated) + endif () + + set(KOBJ_TYPES ${gen_dir}/kobj-types-enum.h) + set(KOBJ_OTYPE ${gen_dir}/otype-to-str.h) + + file(MAKE_DIRECTORY ${gen_dir}) + + add_custom_command( + OUTPUT ${KOBJ_TYPES} ${KOBJ_OTYPE} + COMMAND + ${PYTHON_EXECUTABLE} + $ENV{ZEPHYR_BASE}/scripts/gen_kobject_list.py + --kobj-types-output ${KOBJ_TYPES} + --kobj-otype-output ${KOBJ_OTYPE} + $<$:--verbose> + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + add_custom_target(kobj_types_h_target DEPENDS ${KOBJ_TYPES} ${KOBJ_OTYPE}) + + set(${gen_dir_out} ${gen_dir} PARENT_SCOPE) + +endfunction () diff --git a/doc/kernel/usermode/kernelobjects.rst b/doc/kernel/usermode/kernelobjects.rst index 765ecfae822..efd45196145 100644 --- a/doc/kernel/usermode/kernelobjects.rst +++ b/doc/kernel/usermode/kernelobjects.rst @@ -211,13 +211,6 @@ Creating New Core Kernel Objects * In ``scripts/gen_kobject_list.py``, add the name of the struct to the :py:data:`kobjects` list. -* The name of the enumerated type is derived from the name of the struct. - Take the name of the struct, remove the first two characters, convert to - uppercase, and prepend ``K_OBJ_`` to it. Add the enum to - :cpp:enum:`k_objects` in include/kernel.h. For example, ``struct k_foo`` - should be enumerated as ``K_OBJ_FOO``. -* Add a string representation for the enum to the - :c:func:`otype_to_str()` function in kernel/userspace.c Instances of the new struct should now be tracked. @@ -229,13 +222,6 @@ what API struct they are set to. * In ``scripts/gen_kobject_list.py``, add the name of the API struct for the new subsystem to the :py:data:`subsystems` list. -* Take the name of the API struct, remove the trailing "_driver_api" from its - name, convert to uppercase, and prepend ``K_OBJ_DRIVER_`` to it. This is - the name of the enumerated type, which should be added to - :cpp:enum:`k_objects` in include/kernel.h. For example, ``foo_driver_api`` - should be enumerated as ``K_OBJ_DRIVER_FOO``. -* Add a string representation for the enum to the - :c:func:`otype_to_str()` function in ``kernel/userspace.c`` Driver instances of the new subsystem should now be tracked. diff --git a/doc/kernel/usermode/syscalls.rst b/doc/kernel/usermode/syscalls.rst index a8f2525c101..b4b135fc726 100644 --- a/doc/kernel/usermode/syscalls.rst +++ b/doc/kernel/usermode/syscalls.rst @@ -293,7 +293,11 @@ Several macros exist to validate arguments: fails. The latter should only be used for the most obvious of tests. * :c:macro:`_SYSCALL_DRIVER_OP()` checks at runtime if a driver - instance is capable of performing a particular operation. + instance is capable of performing a particular operation. While this + macro can be used by itself, it's mostly a building block for macros + that are automatically generated for every driver subsytem. For + instance, to validate the GPIO driver, one could use the + :c:macro:`_SYSCALL_DRIVER_GPIO()` macro. If any check fails, a kernel oops will be triggered which will kill the calling thread. This is done instead of returning some error condition to diff --git a/kernel/userspace.c b/kernel/userspace.c index abedeec24d3..af78e3f58a8 100644 --- a/kernel/userspace.c +++ b/kernel/userspace.c @@ -28,61 +28,10 @@ const char *otype_to_str(enum k_objects otype) */ #ifdef CONFIG_PRINTK switch (otype) { - /* Core kernel objects */ - case K_OBJ_ALERT: - return "k_alert"; - case K_OBJ_MSGQ: - return "k_msgq"; - case K_OBJ_MUTEX: - return "k_mutex"; - case K_OBJ_PIPE: - return "k_pipe"; - case K_OBJ_SEM: - return "k_sem"; - case K_OBJ_STACK: - return "k_stack"; - case K_OBJ_THREAD: - return "k_thread"; - case K_OBJ_TIMER: - return "k_timer"; - case K_OBJ__THREAD_STACK_ELEMENT: - return "k_thread_stack_t"; - - /* Driver subsystems */ - case K_OBJ_DRIVER_ADC: - return "adc driver"; - case K_OBJ_DRIVER_AIO_CMP: - return "aio comparator driver"; - case K_OBJ_DRIVER_COUNTER: - return "counter driver"; - case K_OBJ_DRIVER_CRYPTO: - return "crypto driver"; - case K_OBJ_DRIVER_DMA: - return "dma driver"; - case K_OBJ_DRIVER_FLASH: - return "flash driver"; - case K_OBJ_DRIVER_GPIO: - return "gpio driver"; - case K_OBJ_DRIVER_I2C: - return "i2c driver"; - case K_OBJ_DRIVER_I2S: - return "i2s driver"; - case K_OBJ_DRIVER_IPM: - return "ipm driver"; - case K_OBJ_DRIVER_PINMUX: - return "pinmux driver"; - case K_OBJ_DRIVER_PWM: - return "pwm driver"; - case K_OBJ_DRIVER_ENTROPY: - return "entropy driver"; - case K_OBJ_DRIVER_RTC: - return "realtime clock driver"; - case K_OBJ_DRIVER_SENSOR: - return "sensor driver"; - case K_OBJ_DRIVER_SPI: - return "spi driver"; - case K_OBJ_DRIVER_UART: - return "uart driver"; + /* otype-to-str.h is generated automatically during build by + * gen_kobject_list.py + */ +#include default: return "?"; } diff --git a/scripts/gen_kobject_list.py b/scripts/gen_kobject_list.py index 559b2f0f09b..a1e95c99fe4 100755 --- a/scripts/gen_kobject_list.py +++ b/scripts/gen_kobject_list.py @@ -141,6 +141,51 @@ def write_validation_output(fp): fp.write("#endif /* __DRIVER_VALIDATION_GEN_H__ */\n") + +def write_kobj_types_output(fp): + fp.write("/* Core kernel objects */\n") + for kobj in kobjects: + if kobj == "device": + continue + + if kobj.startswith("k_"): + kobj = kobj[2:] + elif kobj.startswith("_k_"): + kobj = kobj[2:] + + fp.write("K_OBJ_%s,\n" % kobj.upper()) + + fp.write("/* Driver subsystems */\n") + for subsystem in subsystems: + subsystem = subsystem.replace("_driver_api", "").upper() + fp.write("K_OBJ_DRIVER_%s,\n" % subsystem) + + +def write_kobj_otype_output(fp): + fp.write("/* Core kernel objects */\n") + for kobj in kobjects: + if kobj == "device": + continue + + if kobj.startswith("k_"): + kobj = kobj[2:] + elif kobj.startswith("_k_"): + kobj = kobj[2:] + + fp.write('case K_OBJ_%s: return "%s";\n' % ( + kobj.upper(), + kobj + )) + + fp.write("/* Driver subsystems */\n") + for subsystem in subsystems: + subsystem = subsystem.replace("_driver_api", "") + fp.write('case K_OBJ_DRIVER_%s: return "%s driver";\n' % ( + subsystem.upper(), + subsystem + )) + + def parse_args(): global args @@ -156,6 +201,12 @@ def parse_args(): parser.add_argument( "-V", "--validation-output", required=False, help="Output driver validation macros") + parser.add_argument( + "-K", "--kobj-types-output", required=False, + help="Output k_object enum values") + parser.add_argument( + "-S", "--kobj-otype-output", required=False, + help="Output case statements for otype_to_str()") parser.add_argument("-v", "--verbose", action="store_true", help="Print extra debugging information") args = parser.parse_args() @@ -187,6 +238,13 @@ def main(): with open(args.validation_output, "w") as fp: write_validation_output(fp) + if args.kobj_types_output: + with open(args.kobj_types_output, "w") as fp: + write_kobj_types_output(fp) + + if args.kobj_otype_output: + with open(args.kobj_otype_output, "w") as fp: + write_kobj_otype_output(fp) if __name__ == "__main__": main() diff --git a/tests/unit/lib/crc/CMakeLists.txt b/tests/unit/lib/crc/CMakeLists.txt index 3baa1c5b525..c18a2238240 100644 --- a/tests/unit/lib/crc/CMakeLists.txt +++ b/tests/unit/lib/crc/CMakeLists.txt @@ -1,3 +1,3 @@ -include($ENV{ZEPHYR_BASE}/tests/unit/unittest.cmake) project(none) +include($ENV{ZEPHYR_BASE}/tests/unit/unittest.cmake) diff --git a/tests/unit/unittest.cmake b/tests/unit/unittest.cmake index e0d7caaf68f..e63bab39c7e 100644 --- a/tests/unit/unittest.cmake +++ b/tests/unit/unittest.cmake @@ -18,17 +18,22 @@ if(NOT SOURCES) set(SOURCES main.c) endif() +add_executable(testbinary ${SOURCES}) + +include($ENV{ZEPHYR_BASE}/cmake/kobj.cmake) +add_dependencies(testbinary kobj_types_h_target) +gen_kobj(KOBJ_GEN_DIR) + list(APPEND INCLUDE tests/ztest/include tests/include include . - ) - -add_executable(testbinary ${SOURCES}) +) target_compile_options(testbinary PRIVATE -Wall + -I ${KOBJ_GEN_DIR} ${EXTRA_CPPFLAGS_AS_LIST} ${EXTRA_CFLAGS_AS_LIST} $<$:${EXTRA_CXXFLAGS_AS_LIST}>