diff --git a/.codespellrc b/.codespellrc index 14770824d320c..4ed2e6b695cf6 100644 --- a/.codespellrc +++ b/.codespellrc @@ -9,6 +9,7 @@ exclude-file = .codespell-ignore-lines skip = LICENSE, */CODEOWNERS, + */system/zbus/images/*, # Ignore seemingly misspelled words. # lowercase: case insensitive diff --git a/Documentation/applications/system/zbus/images/zbus_anatomy.svg b/Documentation/applications/system/zbus/images/zbus_anatomy.svg new file mode 100644 index 0000000000000..e9bc6c79cefc9 --- /dev/null +++ b/Documentation/applications/system/zbus/images/zbus_anatomy.svg @@ -0,0 +1,3 @@ + + + diff --git a/Documentation/applications/system/zbus/images/zbus_observation_mask.svg b/Documentation/applications/system/zbus/images/zbus_observation_mask.svg new file mode 100644 index 0000000000000..4405a8f3e4aed --- /dev/null +++ b/Documentation/applications/system/zbus/images/zbus_observation_mask.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/applications/system/zbus/images/zbus_operations.svg b/Documentation/applications/system/zbus/images/zbus_operations.svg new file mode 100644 index 0000000000000..419cc6c3d5d5f --- /dev/null +++ b/Documentation/applications/system/zbus/images/zbus_operations.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Documentation/applications/system/zbus/images/zbus_overview.svg b/Documentation/applications/system/zbus/images/zbus_overview.svg new file mode 100644 index 0000000000000..24861bbbe3375 --- /dev/null +++ b/Documentation/applications/system/zbus/images/zbus_overview.svg @@ -0,0 +1,3 @@ + + + diff --git a/Documentation/applications/system/zbus/images/zbus_type_of_observers.svg b/Documentation/applications/system/zbus/images/zbus_type_of_observers.svg new file mode 100644 index 0000000000000..1bc29e3dadf16 --- /dev/null +++ b/Documentation/applications/system/zbus/images/zbus_type_of_observers.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/Documentation/applications/system/zbus/index.rst b/Documentation/applications/system/zbus/index.rst new file mode 100644 index 0000000000000..ab7eac19cb63c --- /dev/null +++ b/Documentation/applications/system/zbus/index.rst @@ -0,0 +1,210 @@ +========================== +``zbus`` ZBus message bus +========================== + +Port of the `zbus `_ +message bus to NuttX, built entirely on native NuttX primitives. ZBus +implements many-to-many communication through **channels** (typed shared +messages) observed by **observers**, keeping publishers and consumers +fully decoupled. + +.. figure:: images/zbus_overview.svg + :alt: zbus usage overview + :width: 75% + + A typical zbus application architecture. + +Channels and observers are defined statically, in any source file, with +declarative macros. The definitions are collected at link time through +iterable sections (see the Iterable Sections component documentation) -- +there is no runtime registration and no central list to maintain. + +.. figure:: images/zbus_anatomy.svg + :alt: zbus anatomy + :width: 70% + + ZBus anatomy: channels, observers and observations. + +Observer types +============== + +.. figure:: images/zbus_type_of_observers.svg + :alt: zbus observer types + :width: 70% + + The four observer types. + +======================== =================================================== +Type Behavior +======================== =================================================== +Listener Callback executed synchronously in the publisher + context (``ZBUS_LISTENER_DEFINE``). +Subscriber Receives channel references through a message + queue; waits with ``zbus_sub_wait()`` + (``ZBUS_SUBSCRIBER_DEFINE``). +Message subscriber Receives a *copy* of every published message, in + order; waits with ``zbus_sub_wait_msg()`` + (``ZBUS_MSG_SUBSCRIBER_DEFINE``, + ``CONFIG_ZBUS_MSG_SUBSCRIBER``). +Async listener Callback executed on a dedicated task with a + copy of the message + (``ZBUS_ASYNC_LISTENER_DEFINE``, + ``CONFIG_ZBUS_ASYNC_LISTENER``). +======================== =================================================== + +Runtime observers (``zbus_chan_add_obs()``/``zbus_chan_rm_obs()``, +``CONFIG_ZBUS_RUNTIME_OBSERVERS``), per-observation notification masks, +observer enable/disable, message validators and channel user data are +also supported. + +.. figure:: images/zbus_observation_mask.svg + :alt: zbus observation mask + :width: 75% + + Observer enable/disable and per-observation masks: disabling the + observer (b) silences every channel; masking observations (c, d) + silences individual channels. + +Example +======= + +The figure below shows the kind of decoupled architecture zbus enables: +every block only talks to channels, so each one can be replaced without +touching the others. + +.. figure:: images/zbus_operations.svg + :alt: zbus sensor-based application + :width: 85% + + A sensor-based application built on zbus. + +.. code-block:: c + + #include + + struct acc_msg + { + int x; + int y; + int z; + }; + + static void listener_cb(const struct zbus_channel *chan) + { + const struct acc_msg *msg = zbus_chan_const_msg(chan); + printf("x=%d y=%d z=%d\n", msg->x, msg->y, msg->z); + } + + ZBUS_LISTENER_DEFINE(acc_listener, listener_cb); + ZBUS_SUBSCRIBER_DEFINE(acc_subscriber, 4); + + ZBUS_CHAN_DEFINE(acc_chan, /* Name */ + struct acc_msg, /* Message type */ + NULL, /* Validator */ + NULL, /* User data */ + ZBUS_OBSERVERS(acc_listener, /* Observers, in */ + acc_subscriber),/* priority order */ + ZBUS_MSG_INIT(.x = 0, .y = 0, .z = 0)); + + /* Publisher: */ + + struct acc_msg msg = { 1, 10, 100 }; + zbus_chan_pub(&acc_chan, &msg, 1000); + + /* Subscriber thread: */ + + const struct zbus_channel *chan; + if (zbus_sub_wait(&acc_subscriber, &chan, ZBUS_FOREVER) == 0) + { + zbus_chan_read(chan, &msg, 500); + } + +A complete runnable example is available in ``apps/examples/zbus`` +(``CONFIG_EXAMPLES_ZBUS``), and a cmocka test suite covering the whole +API in ``apps/testing/zbus`` (``CONFIG_TESTING_ZBUS``). + +Not ported +========== + +The following Zephyr zbus features are **not available** in this port: + +* **Multi-domain proxy agent** (``CONFIG_ZBUS_PROXY_AGENT``): bridges + channels between domains/cores over IPC. Experimental upstream and + tied to the Zephyr IPC service; a NuttX equivalent would be built on + rpmsg and is left as future work. +* **Publishing from interrupt handlers**: the Zephyr original allows + ``zbus_chan_pub()`` from ISRs with ``K_NO_WAIT``. This port is a + userspace library and its primitives (semaphores, message queues, lazy + initialization) are not ISR-safe: interrupt handling belongs to the + driver, which should hand the data to a thread (the usual NuttX + pattern) that then publishes it. ``test_timer_driven_publisher`` in + ``apps/testing/zbus`` shows the pattern with a kernel timer interrupt + delivering a signal to a sampling thread. +* **Priority boost (Highest Locker Protocol)** + (``CONFIG_ZBUS_PRIORITY_BOOST``): the Zephyr hand-rolled protection + against priority inversion during the notification process. Not + needed: enable the native ``CONFIG_PRIORITY_INHERITANCE`` so the + channel semaphores get equivalent protection from the kernel. +* **net_buf pools and pool isolation** + (``CONFIG_ZBUS_MSG_SUBSCRIBER_BUF_*``): obsolete by design in this + port -- message queues copy the payload on ``mq_send``, so no shared + reference-counted buffers exist at all. +* **Static/user-provided runtime observer nodes** + (``CONFIG_ZBUS_RUNTIME_OBSERVERS_NODE_ALLOC_STATIC/NONE``): runtime + observer nodes are always heap-allocated in this port. + +Differences from the Zephyr original +==================================== + +* Timeouts are plain milliseconds (``int32_t``): ``ZBUS_NO_WAIT`` (0) and + ``ZBUS_FOREVER`` (-1) replace ``K_NO_WAIT``/``K_FOREVER``. +* Subscriber queues are POSIX message queues opened lazily on first API + use through the kernel ``file_mq_*`` interface, making them usable from + any task (a ``mqd_t`` descriptor would die with the opening task). +* Initialization is lazy (``pthread_once`` on the first API call) + replacing the Zephyr ``SYS_INIT`` hook; no explicit init call is + needed. +* Async listeners run on a dedicated task per listener (spawned on + first use; priority and stack size are configurable) instead of the + Zephyr system work queue. + +Configuration +============= + +Requirements: + +* The board linker script must provide the zbus iterable sections, either + by including ```` inside ``.text`` (see the + ``linum-stm32h753bi`` board) or through + ``CONFIG_ITERABLE_SECTIONS_LINKER_INSERT`` + (zero-touch mode; see its help text for the MEMORY-layout constraint). +* ``CONFIG_MQ_MAXMSGSIZE`` must be at least + ``CONFIG_ZBUS_MSG_SUBSCRIBER_MAX_MSG_SIZE`` plus the size of a pointer + when message subscribers or async listeners are used, otherwise their + queues fail to open with ``-EINVAL``. +* FLAT build (the library uses the kernel ``file_mq_*`` interface + directly). + +Main options: + +* ``CONFIG_ZBUS`` -- enable the library. +* ``CONFIG_ZBUS_CHANNEL_NAME`` / ``CONFIG_ZBUS_OBSERVER_NAME`` -- name + fields and lookup by name. +* ``CONFIG_ZBUS_CHANNEL_ID`` -- numeric channel identifiers + (``ZBUS_CHAN_DEFINE_WITH_ID``, ``zbus_chan_from_id()``). +* ``CONFIG_ZBUS_MSG_SUBSCRIBER`` -- message subscribers + (+ ``_MAX_MSG_SIZE``, ``_QUEUE_SIZE``). +* ``CONFIG_ZBUS_ASYNC_LISTENER`` -- async listeners (+ ``_PRIORITY``, + ``_STACKSIZE`` of their tasks). +* ``CONFIG_ZBUS_RUNTIME_OBSERVERS`` -- runtime observers. +* ``CONFIG_ZBUS_CHANNEL_PUBLISH_STATS`` -- publish timestamp/count. +* ``CONFIG_ZBUS_ASSERT_MOCK`` -- invalid parameters return ``-EFAULT`` + instead of asserting (for tests). + +Credits +======= + +The zbus design and the diagrams in this page come from the upstream +`Zephyr zbus documentation +`_ +by Rodrigo Peixoto and contributors (Apache License 2.0). diff --git a/Documentation/components/index.rst b/Documentation/components/index.rst index fe60af7b9851c..edd1415ede23d 100644 --- a/Documentation/components/index.rst +++ b/Documentation/components/index.rst @@ -13,6 +13,7 @@ case, you can head to the :doc:`reference <../reference/index>`. binfmt.rst concurrency/index.rst + iterable_sections.rst drivers/index.rst nxflat.rst nxgraphics/index.rst diff --git a/Documentation/components/iterable_sections.rst b/Documentation/components/iterable_sections.rst new file mode 100644 index 0000000000000..4659d4ad166ae --- /dev/null +++ b/Documentation/components/iterable_sections.rst @@ -0,0 +1,170 @@ +================= +Iterable Sections +================= + +Iterable sections provide **link-time registration** of ``struct`` +instances: an instance defined with :c:macro:`STRUCT_SECTION_ITERABLE` in +any compilation unit is placed in a dedicated linker input section. The +linker collects all instances into a contiguous, name-sorted array +delimited by ``__list_start``/``__list_end`` symbols, which +the code can then iterate like a plain C array -- no runtime registration +calls, no central list to maintain. + +This is the same mechanism used by the Zephyr RTOS ``STRUCT_SECTION_*`` +macros. The first user of this infrastructure is the zbus message bus +port (``apps/system/zbus``, from nuttx-apps). + +C API +===== + +The macros are provided by ``include/nuttx/iterable_sections.h``: + +.. code-block:: c + + #include + + struct my_entry + { + const char *name; + int value; + }; + + /* In any .c file (const places the instance in ROM): */ + + const STRUCT_SECTION_ITERABLE(my_entry, entry_foo) = + { + .name = "foo", + .value = 42, + }; + + /* In the file that iterates: declare the section boundaries once, at + * file scope, then loop with a caller-declared pointer. + */ + + STRUCT_SECTION_DECLARE(my_entry); + + void print_entries(void) + { + FAR struct my_entry *entry; + + STRUCT_SECTION_FOREACH(my_entry, entry) + { + printf("%s = %d\n", entry->name, entry->value); + } + } + +Available macros: + +* ``STRUCT_SECTION_ITERABLE(type, varname)`` -- define an instance inside + the iterable section ``._.static.``. The variable name + is part of the input section name, so the linker's ``SORT_BY_NAME()`` + defines the iteration order (instances may encode ordering in their + names). +* ``STRUCT_SECTION_DECLARE(type)`` -- declare the boundary symbols (file + scope), required before iterating. +* ``STRUCT_SECTION_FOREACH(type, iterator)`` -- for-loop over all + instances; ``iterator`` is a pointer declared by the caller, as with + ``list_for_every_entry()``. +* ``STRUCT_SECTION_GET(type, i, dst)`` -- random access by index. +* ``STRUCT_SECTION_COUNT(type, dst)`` -- number of instances. +* ``STRUCT_SECTION_START/END/START_EXTERN/END_EXTERN`` -- direct access + to the boundary symbols. + +Linker integration +================== + +The collection step needs linker script support. Two mechanisms are +available; both rely on the fact that the linker scripts listed in +``ARCHSCRIPT`` are preprocessed with CPP (arm, arm64, risc-v, xtensa, +x86_64 and tricore), so ``#include`` and ``#ifdef CONFIG_*`` work inside +them. + +Board script include (first-class mechanism) +-------------------------------------------- + +The board linker script includes the central fragments, which expand to +nothing unless a subsystem using iterable sections is enabled: + +.. code-block:: text + + .text : + { + ... + *(.gnu.linkonce.r.*) + #include + _etext = ABSOLUTE(.); + } > flash + + .data : + { + _sdata = ABSOLUTE(.); + ... + #include + . = ALIGN(4); + _edata = ABSOLUTE(.); + } > sram AT > flash + +* ``common-rom.ld`` collects the read-only (``const``) iterable sections + and must be included inside the read-only output section (typically + ``.text``, before ``_etext``). +* ``common-ram.ld`` collects mutable *initialized* iterable sections and + must be included inside ``.data`` (between ``_sdata`` and ``_edata``) + so the startup FLASH-to-RAM copy initializes the entries. +* Subsystems add their sections to these central files, guarded by their + Kconfig option (see ``include/nuttx/linker/common-rom.ld`` for the zbus + example). + +Supplementary INSERT script (zero-touch mode) +--------------------------------------------- + +With ``CONFIG_ITERABLE_SECTIONS_LINKER_INSERT`` the central script +``include/nuttx/linker/common-insert.ld`` is added to the ``ARCHSCRIPT`` +list by ``tools/Config.mk`` and supplements the board script through the +GNU ld ``INSERT AFTER`` command, so **no board script modification is +needed**. Subsystems add their fragment (a ``SECTIONS { ... } INSERT +AFTER .text`` block, see ``include/nuttx/linker/zbus.ld``) to that +central file, guarded by their Kconfig option. + +This mode has constraints, discovered the hard way and worth knowing +before choosing it: + +* GNU ld only (``INSERT`` is not supported by the macOS ld64). +* The INSERT script must come *before* the board script on the linker + command line. Adding it via ``ARCHSCRIPT`` from ``tools/Config.mk`` + guarantees that, because ``Config.mk`` is included by the board + ``Make.defs`` before it appends its own script. (The reversed order + fails with ``.text not found for insert``.) +* GNU ld assigns an INSERTed output section to a ``MEMORY`` region by + *attribute matching in declaration order*, not by inheriting the anchor + section's region. The ROM/flash region must therefore be the first + region compatible with read-only sections. Boards declaring a generic + ``rwx`` region at a lower address first (e.g. an ITCM at ``0x0``) are + incompatible with this mode and must use the board script include. +* Giving the inserted section an explicit address is **not** a fix: a + section with an explicit address does not consume the memory region, + so the next region-allocated section overlaps it. + +Alignment rules +=============== + +Instances are aligned to the natural alignment of their type +(``STRUCT_SECTION_ITERABLE`` adds ``__aligned__(__alignof__(type))``), and +``sizeof`` is always a multiple of ``alignof``, so the collected section +can be indexed as a plain array with no padding between entries from +different compilation units. The fragments additionally align the list +boundaries to 4 bytes. + +Adding a new iterable type +========================== + +1. Define the instances with ``STRUCT_SECTION_ITERABLE(mytype, name)``. +2. Add ``ITERABLE_SECTION(mytype)`` to + ``include/nuttx/linker/common-rom.ld`` (const) or ``common-ram.ld`` + (mutable initialized), guarded by the subsystem Kconfig option. +3. Iterate with ``STRUCT_SECTION_FOREACH(mytype, it)`` after + ``STRUCT_SECTION_DECLARE(mytype);`` at file scope. + +Caveat on generated linker scripts: the preprocessed ``.ld.tmp`` files +only depend on the board script and ``.config``; after editing the +central fragments during development, remove the ``.tmp`` files (or run +``make clean``) to force regeneration. diff --git a/Documentation/platforms/arm/stm32h7/boards/linum-stm32h753bi/index.rst b/Documentation/platforms/arm/stm32h7/boards/linum-stm32h753bi/index.rst index 9b469c9c80af3..01e0e026c1790 100644 --- a/Documentation/platforms/arm/stm32h7/boards/linum-stm32h753bi/index.rst +++ b/Documentation/platforms/arm/stm32h7/boards/linum-stm32h753bi/index.rst @@ -1298,3 +1298,28 @@ This example demonstrates how to use the CAN-FD peripherals can0 and can1 with t can0 051 [8] 00 11 22 33 44 55 66 77 can0 051 [16] 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF + +zbus +---- + +Enables the zbus message bus library (``apps/system/zbus``, a port of the +Zephyr zbus — see :doc:`its documentation +`) with all observer types (listeners, +subscribers, message subscribers, async listeners, ISR publisher and +runtime observers), together with its example application:: + + nsh> zbus + zbus: publishing 5 messages to acc_chan + zbus: listener: x=1 y=10 z=100 + zbus: subscriber: x=1 y=10 z=100 + ... + zbus: done + +The cmocka test suite from ``apps/testing/zbus`` is also included and can +be used to validate the whole zbus API on the board:: + + nsh> cmocka_zbus_test + [==========] tests: Running 16 test(s). + ... + [==========] tests: 16 test(s) run. + [ PASSED ] 16 test(s). diff --git a/Kconfig b/Kconfig index e0cfa1c37bec6..1b1cb0003b76f 100644 --- a/Kconfig +++ b/Kconfig @@ -2957,6 +2957,29 @@ config DEBUG_LINK_MAP and debugging magic section games, and for seeing which pieces of code get eliminated with DEBUG_OPT_UNUSED_SECTIONS. +config ITERABLE_SECTIONS_LINKER_INSERT + bool "Collect iterable sections through a supplementary INSERT linker script" + default n + depends on ARCH_TOOLCHAIN_GNU + ---help--- + Zero-touch mode for link-time iterable sections + (include/nuttx/iterable_sections.h): instead of the board linker + script including , the supplementary + script is added to ARCHSCRIPT and + supplements the board script with GNU ld "INSERT AFTER .text"; + subsystems add their INSERT fragments to that central file. + + Leave disabled for boards whose linker script already includes + the common fragments. + + Constraints: requires GNU ld, a board script with an output + section named ".text", and a MEMORY layout where the ROM/flash + region is the first region compatible with read-only sections + (GNU ld assigns INSERTed sections to a region by attribute + matching, in declaration order). Boards declaring a generic + rwx region at a lower address first (e.g. ITCM at 0x0) must use + the common-rom.ld include instead. + config CCACHE bool "Use ccache" default n diff --git a/boards/arm/stm32h7/linum-stm32h753bi/configs/zbus/defconfig b/boards/arm/stm32h7/linum-stm32h753bi/configs/zbus/defconfig new file mode 100644 index 0000000000000..ea87116489927 --- /dev/null +++ b/boards/arm/stm32h7/linum-stm32h753bi/configs/zbus/defconfig @@ -0,0 +1,74 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ALLOW_MIT_COMPONENTS=y +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="linum-stm32h753bi" +CONFIG_ARCH_BOARD_LINUM_STM32H753BI=y +CONFIG_ARCH_CHIP="stm32h7" +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32H753BI=y +CONFIG_ARCH_CHIP_STM32H7=y +CONFIG_ARCH_CHIP_STM32H7_CORTEXM7=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_SETJMP_H=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV7M_DCACHE=y +CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y +CONFIG_ARMV7M_DTCM=y +CONFIG_ARMV7M_ICACHE=y +CONFIG_BOARD_LOOPSPERMSEC=43103 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_EXAMPLES_ALARM=y +CONFIG_EXAMPLES_ZBUS=y +CONFIG_FS_PROCFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=4096 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBM=y +CONFIG_LINE_MAX=64 +CONFIG_MM_REGIONS=4 +CONFIG_MQ_MAXMSGSIZE=96 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_DISABLE_VCONFIG=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=245760 +CONFIG_RAM_START=0x20010000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_RTC_ALARM=y +CONFIG_RTC_DATETIME=y +CONFIG_RTC_DRIVER=y +CONFIG_SCHED_CPULOAD_SYSCLK=y +CONFIG_SCHED_WAITPID=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_STM32_PWR=y +CONFIG_STM32_RTC=y +CONFIG_STM32_USART1=y +CONFIG_SYSTEM_NSH=y +CONFIG_TASK_NAME_SIZE=20 +CONFIG_TESTING_CMOCKA=y +CONFIG_TESTING_ZBUS=y +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_ZBUS=y +CONFIG_ZBUS_ASYNC_LISTENER=y +CONFIG_ZBUS_CHANNEL_ID=y +CONFIG_ZBUS_CHANNEL_NAME=y +CONFIG_ZBUS_CHANNEL_PUBLISH_STATS=y +CONFIG_ZBUS_MSG_SUBSCRIBER=y +CONFIG_ZBUS_OBSERVER_NAME=y +CONFIG_ZBUS_RUNTIME_OBSERVERS=y diff --git a/boards/arm/stm32h7/linum-stm32h753bi/scripts/flash.ld b/boards/arm/stm32h7/linum-stm32h753bi/scripts/flash.ld index b726e5c457607..036b6b4c5ebf5 100644 --- a/boards/arm/stm32h7/linum-stm32h753bi/scripts/flash.ld +++ b/boards/arm/stm32h7/linum-stm32h753bi/scripts/flash.ld @@ -126,6 +126,7 @@ SECTIONS *(.got) *(.gcc_except_table) *(.gnu.linkonce.r.*) +#include _etext = ABSOLUTE(.); } > flash @@ -156,6 +157,7 @@ SECTIONS *(.data .data.*) *(.gnu.linkonce.d.*) CONSTRUCTORS +#include . = ALIGN(4); _edata = ABSOLUTE(.); } > sram AT > flash diff --git a/include/nuttx/iterable_sections.h b/include/nuttx/iterable_sections.h new file mode 100644 index 0000000000000..a997d936cc9da --- /dev/null +++ b/include/nuttx/iterable_sections.h @@ -0,0 +1,121 @@ +/**************************************************************************** + * include/nuttx/iterable_sections.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Iterable sections: link-time registration of struct instances. + * + * A struct instance defined with STRUCT_SECTION_ITERABLE() in any + * compilation unit is placed in a dedicated input section named + * "._.static.". The board linker script collects + * these input sections (sorted by name) into a contiguous array delimited + * by the __list_start/__list_end symbols by + * including (const data, inside the .text or + * .rodata output section) and (mutable + * initialized data, inside the .data output section, so that the startup + * FLASH-to-RAM copy initializes it). + * + * The collection is only available on architectures whose linker scripts + * are preprocessed with CPP (arm, arm64, risc-v, xtensa, x86_64, tricore) + * and on boards whose scripts include the common-*.ld fragments. + */ + +#ifndef __INCLUDE_NUTTX_ITERABLE_SECTIONS_H +#define __INCLUDE_NUTTX_ITERABLE_SECTIONS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Define a struct instance inside an iterable section. A "const" + * qualifier may be prepended at the point of use to place the instance in + * ROM. Each instance is aligned to the natural alignment of its type so + * that the collected section can be indexed as a plain C array. The + * variable name is part of the input section name so that the linker's + * SORT_BY_NAME() defines the iteration order (instances may encode + * ordering in their names). + */ + +#define STRUCT_SECTION_ITERABLE(struct_type, varname) \ + struct struct_type varname \ + used_data \ + aligned_data(__alignof__(struct struct_type)) \ + locate_data("._" #struct_type ".static." #varname) + +/* Start/end symbols provided by the linker script fragments */ + +#define STRUCT_SECTION_START(struct_type) _##struct_type##_list_start +#define STRUCT_SECTION_END(struct_type) _##struct_type##_list_end + +#define STRUCT_SECTION_START_EXTERN(struct_type) \ + extern struct struct_type STRUCT_SECTION_START(struct_type)[] +#define STRUCT_SECTION_END_EXTERN(struct_type) \ + extern struct struct_type STRUCT_SECTION_END(struct_type)[] + +/* Declare both boundary symbols of an iterable section. Place it at file + * scope (followed by a semicolon) in every file that iterates with + * STRUCT_SECTION_FOREACH. + */ + +#define STRUCT_SECTION_DECLARE(struct_type) \ + STRUCT_SECTION_START_EXTERN(struct_type); \ + STRUCT_SECTION_END_EXTERN(struct_type) + +/* Iterate over every instance of an iterable section. "iterator" is a + * pointer variable (FAR struct struct_type *) declared by the caller, as + * with list_for_every_entry(); the boundary symbols must be in scope + * (STRUCT_SECTION_DECLARE). + */ + +#define STRUCT_SECTION_FOREACH(struct_type, iterator) \ + for ((iterator) = STRUCT_SECTION_START(struct_type); \ + (iterator) < STRUCT_SECTION_END(struct_type); \ + (iterator)++) + +/* Get the i-th element of an iterable section (no bounds checking) */ + +#define STRUCT_SECTION_GET(struct_type, i, dst) \ + do \ + { \ + STRUCT_SECTION_START_EXTERN(struct_type); \ + *(dst) = &STRUCT_SECTION_START(struct_type)[i]; \ + } \ + while (0) + +/* Number of elements in an iterable section */ + +#define STRUCT_SECTION_COUNT(struct_type, dst) \ + do \ + { \ + STRUCT_SECTION_START_EXTERN(struct_type); \ + STRUCT_SECTION_END_EXTERN(struct_type); \ + *(dst) = STRUCT_SECTION_END(struct_type) - \ + STRUCT_SECTION_START(struct_type); \ + } \ + while (0) + +#endif /* __INCLUDE_NUTTX_ITERABLE_SECTIONS_H */ diff --git a/include/nuttx/linker/common-insert.ld b/include/nuttx/linker/common-insert.ld new file mode 100644 index 0000000000000..c652ecfe0a1b0 --- /dev/null +++ b/include/nuttx/linker/common-insert.ld @@ -0,0 +1,38 @@ +/**************************************************************************** + * include/nuttx/linker/common-insert.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Supplementary linker script for the iterable sections "zero-touch" mode + * (CONFIG_ITERABLE_SECTIONS_LINKER_INSERT): added to ARCHSCRIPT by + * tools/Config.mk, it supplements -- does not replace -- the board linker + * script through the GNU ld INSERT command, so boards need no edit. + * + * Subsystem fragments are included below, each guarded by its Kconfig + * option; every fragment provides its own SECTIONS { ... } INSERT AFTER + * block. See Documentation/components/iterable_sections.rst for the + * constraints of this mode (GNU ld, command-line ordering, MEMORY layout). + */ + +#include + +#ifdef CONFIG_ZBUS +# include +#endif diff --git a/include/nuttx/linker/common-ram.ld b/include/nuttx/linker/common-ram.ld new file mode 100644 index 0000000000000..8145ccb16bfd5 --- /dev/null +++ b/include/nuttx/linker/common-ram.ld @@ -0,0 +1,43 @@ +/**************************************************************************** + * include/nuttx/linker/common-ram.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Mutable (initialized) iterable sections. Boards opt in by adding, + * INSIDE their .data output section (between _sdata and _edata, so the + * startup FLASH-to-RAM copy initializes the entries): + * + * #include + * + * Every block below is guarded by its subsystem's Kconfig option, so this + * file expands to nothing on configurations that do not use iterable + * sections (zero binary impact). + */ + +#include +#include + +/* Extension point for subsystems that need initialized RAM iterable + * sections; blocks are added below, each guarded by its Kconfig option. + */ + +/* zbus needs no RAM iterable sections: notification masks live in .bss + * and are initialized at runtime from ROM-preserved values. + */ diff --git a/include/nuttx/linker/common-rom.ld b/include/nuttx/linker/common-rom.ld new file mode 100644 index 0000000000000..6e4ea2dbafcf0 --- /dev/null +++ b/include/nuttx/linker/common-rom.ld @@ -0,0 +1,53 @@ +/**************************************************************************** + * include/nuttx/linker/common-rom.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Read-only iterable sections. Boards opt in by adding, INSIDE their + * read-only output section (typically .text, before _etext): + * + * #include + * + * Every block below is guarded by its subsystem's Kconfig option, so this + * file expands to nothing on configurations that do not use iterable + * sections (zero binary impact). + */ + +#include +#include + +/* Subsystem blocks are added below, each guarded by its Kconfig option: + * + * #ifdef CONFIG_MYSUBSYS + * ITERABLE_SECTION(mysubsys_entry) + * #endif + */ + +/* zbus message bus. In the INSERT mode + * (CONFIG_ITERABLE_SECTIONS_LINKER_INSERT) the zbus sections come from + * through common-insert.ld instead, so they must + * not be emitted here too. + */ + +#if defined(CONFIG_ZBUS) && !defined(CONFIG_ITERABLE_SECTIONS_LINKER_INSERT) +ITERABLE_SECTION(zbus_channel) +ITERABLE_SECTION(zbus_observer) +ITERABLE_SECTION(zbus_channel_observation) +#endif diff --git a/include/nuttx/linker/iterable_sections.ld b/include/nuttx/linker/iterable_sections.ld new file mode 100644 index 0000000000000..433e68e19b9d1 --- /dev/null +++ b/include/nuttx/linker/iterable_sections.ld @@ -0,0 +1,43 @@ +/**************************************************************************** + * include/nuttx/linker/iterable_sections.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* CPP macro emitting the linker statements that collect one iterable + * section (see include/nuttx/iterable_sections.h). This file is meant to + * be included from linker scripts that are preprocessed with CPP (the + * ARCHSCRIPT .tmp rule). + * + * The macro must be expanded INSIDE an output section (e.g. .text or + * .data). KEEP() protects the entries from --gc-sections and + * SORT_BY_NAME() defines the iteration order. + */ + +#ifndef __INCLUDE_NUTTX_LINKER_ITERABLE_SECTIONS_LD +#define __INCLUDE_NUTTX_LINKER_ITERABLE_SECTIONS_LD + +#define ITERABLE_SECTION(name) \ + . = ALIGN(4); \ + _##name##_list_start = .; \ + KEEP(*(SORT_BY_NAME(._##name.static.*))); \ + _##name##_list_end = .; \ + . = ALIGN(4); + +#endif /* __INCLUDE_NUTTX_LINKER_ITERABLE_SECTIONS_LD */ diff --git a/include/nuttx/linker/zbus.ld b/include/nuttx/linker/zbus.ld new file mode 100644 index 0000000000000..89e1d7bc03422 --- /dev/null +++ b/include/nuttx/linker/zbus.ld @@ -0,0 +1,67 @@ +/**************************************************************************** + * include/nuttx/linker/zbus.ld + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Supplementary linker script providing the zbus iterable sections without + * editing the board linker script ("zero-touch" mode). Included by + * , which CONFIG_ITERABLE_SECTIONS_LINKER_INSERT + * adds to ARCHSCRIPT (see tools/Config.mk). The INSERT command makes this + * script supplement -- not replace -- the board script. + * + * Constraints of this mode: + * - GNU ld only (INSERT is not supported by macOS ld64), and the INSERT + * script must come BEFORE the board script on the command line (the + * ARCHSCRIPT hook guarantees that ordering). + * - The board script must define an output section named ".text". + * - The ROM/flash region must be the first MEMORY region compatible + * with read-only sections: GNU ld assigns the INSERTed section to a + * region by attribute matching in declaration order, so a board that + * declares a generic rwx region at a lower address first (e.g. ITCM + * at 0x0) would pull these sections into the wrong region. Such + * boards must use the include instead. + * + * Boards that include in their script should + * NOT enable the INSERT mode (the common-rom.ld zbus block is disabled + * when this mode is selected, so enabling it by mistake is harmless but + * pointless). + */ + +SECTIONS +{ + .zbus : SUBALIGN(4) + { + . = ALIGN(4); + _zbus_channel_list_start = .; + KEEP(*(SORT_BY_NAME(._zbus_channel.static.*))); + _zbus_channel_list_end = .; + + . = ALIGN(4); + _zbus_observer_list_start = .; + KEEP(*(SORT_BY_NAME(._zbus_observer.static.*))); + _zbus_observer_list_end = .; + + . = ALIGN(4); + _zbus_channel_observation_list_start = .; + KEEP(*(SORT_BY_NAME(._zbus_channel_observation.static.*))); + _zbus_channel_observation_list_end = .; + } +} +INSERT AFTER .text; diff --git a/tools/Config.mk b/tools/Config.mk index bc5d2ffd54256..ed6b3dac538d7 100644 --- a/tools/Config.mk +++ b/tools/Config.mk @@ -861,3 +861,17 @@ LOWERMAP = A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R UPPER_CASE = $(call ULMAP,$(UPPERMAP),$(1)) LOWER_CASE = $(call ULMAP,$(LOWERMAP),$(1)) + +# Iterable sections "zero-touch" mode: supplement the board linker script +# with the central INSERT fragment (include/nuttx/linker/common-insert.ld, +# which includes the per-subsystem fragments) instead of requiring the +# board script to include common-rom.ld. +# +# The fragment is added through ARCHSCRIPT (not EXTRALINKCMDS) because GNU +# ld requires the INSERT script to come BEFORE the script that defines the +# target section on the command line; this file is included by the board +# Make.defs before it appends its own script, so the fragment lands first. + +ifeq ($(CONFIG_ITERABLE_SECTIONS_LINKER_INSERT),y) + ARCHSCRIPT += $(TOPDIR)$(DELIM)include$(DELIM)nuttx$(DELIM)linker$(DELIM)common-insert.ld +endif