Commit 57011e4c authored by Luca Burelli's avatar Luca Burelli Committed by Alberto Escolar
Browse files

llext: add a "modules" Kconfig tristate example



This adds a new sample to demonstrate the use of tristate symbols
in Kconfig to build a function as an llext module or as a built-in
part of Zephyr.

Signed-off-by: default avatarLuca Burelli <l.burelli@arduino.cc>
parent baa3b6a5
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(fs_shell)

if(CONFIG_HELLO_WORLD_MODE STREQUAL "m")

  # Build the llext ...

  set(ext_name hello_world)
  set(ext_src src/${ext_name}_ext.c)
  set(ext_bin ${ZEPHYR_BINARY_DIR}/${ext_name}.llext)
  set(ext_inc ${ZEPHYR_BINARY_DIR}/include/generated/${ext_name}_ext.inc)
  add_llext_target(${ext_name}_ext
    OUTPUT  ${ext_bin}
    SOURCES ${ext_src}
  )
  generate_inc_file_for_target(app ${ext_bin} ${ext_inc})

  # ...and the code for loading and running it

  target_sources(app PRIVATE
    src/main_module.c
  )

elseif(CONFIG_HELLO_WORLD_MODE STREQUAL "y")

  # Just build the two files together

  target_sources(app PRIVATE
    src/main_builtin.c
    src/hello_world_ext.c
  )

else()
  message(FATAL_ERROR "Please choose 'y' or 'm' for CONFIG_HELLO_WORLD_MODE")
endif()
+18 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2024 Intel Corporation.

mainmenu "LLEXT functionality test"

source "Kconfig.zephyr"

config HELLO_WORLD_MODE
	tristate "Include the hello_world function"
	default m
	help
	  This enables building the hello_world function, implemented in
	  hello_world_ext.c, either as an llext module or as a built-in part of
	  Zephyr.

	  If you select 'm', the hello_world function will be built as an llext
	  "module". If you select 'y', the hello_world function will be directly
	  linked in the Zephyr image.
+63 −0
Original line number Diff line number Diff line
.. zephyr:code-sample:: llext-modules
   :name: Linkable loadable extensions "module" sample
   :relevant-api: llext

    Call a function in a loadable extension module,
    either built-in or loaded at runtime.

Overview
********

This sample demonstrates the use of the :ref:`llext` subsystem in Zephyr. The
llext subsystem allows for the loading of relocatable ELF files at runtime;
their symbols can be accessed and functions called.

Specifically, this shows how to call a simple "hello world" function,
implemented in :zephyr_file:`samples/subsys/llext/modules/src/hello_world_ext.c`.
This is achieved in two different ways, depending on the value of the Kconfig
symbol ``CONFIG_HELLO_WORLD_MODE``:

- if it is ``y``, the function is directly compiled and called by the Zephyr
  application. The caller code used in this case is in
  :zephyr_file:`samples/subsys/llext/modules/src/main_builtin.c`.

- if it is ``m``, the function is compiled as an llext and it is included in
  the application as a binary blob. At runtime, the llext subsystem is used to
  load the extension and call the function. The caller code is in
  :zephyr_file:`samples/subsys/llext/modules/src/main_module.c`.

Requirements
************

A board with a supported llext architecture and console. This can also be
executed in QEMU emulation on the :ref:`qemu_xtensa <qemu_xtensa>` or
:ref:`qemu_cortex_r5 <qemu_cortex_r5>` virtual boards.

Building and running
********************

- The following commands build and run the sample so that the files are linked
  together in the same binary:

  .. zephyr-app-commands::
     :zephyr-app: samples/subsys/llext/modules
     :board: qemu_xtensa
     :goals: build run
     :west-args: -T sample.llext.modules.builtin_build
     :compact:

- The following commands build and run the sample so that the extension code is
  compiled separately and included in the Zephyr image as a binary blob:

  .. zephyr-app-commands::
     :zephyr-app: samples/subsys/llext/modules
     :board: qemu_xtensa
     :goals: build run
     :west-args: -T sample.llext.modules.module_build
     :compact:

  Take a look at :zephyr_file:`samples/subsys/llext/modules/sample.yaml` for the
  additional architecture-specific configurations required in this case.

To build for a different board, replace ``qemu_xtensa`` in the commands above
with the desired board name.
+14 −0
Original line number Diff line number Diff line
CONFIG_LOG=y
CONFIG_LOG_MODE_IMMEDIATE=y

CONFIG_MODULES=y

# LLEXT is only required when loading the extension at runtime. Since in this
# basic example there's only one llext, leaving it in when building the
# extension as a built-in is redundant; in a real application, however, there
# could be other uses of the llext subsystem.

CONFIG_LLEXT=y
CONFIG_LLEXT_LOG_LEVEL_DBG=y
CONFIG_LLEXT_HEAP_SIZE=64
CONFIG_LLEXT_TYPE_ELF_RELOCATABLE=y
+35 −0
Original line number Diff line number Diff line
common:
  tags: llext
  arch_allow:
    - arm
    - xtensa
  platform_exclude:
    - apollo4p_evb            # See #73443
    - apollo4p_blue_kxr_evb   # See #73443
    - numaker_pfm_m487        # See #63167
  integration_platforms:
    - qemu_xtensa
    - qemu_cortex_r5
    - mps2/an385
  harness: console
sample:
  name: CONFIG_MODULES test
  description: Call code directly and from extensions
tests:
  sample.llext.modules.module_build:
    filter: not CONFIG_MPU and not CONFIG_MMU and not CONFIG_SOC_SERIES_S32ZE
    extra_configs:
      - CONFIG_HELLO_WORLD_MODE=m
      - arch:arm:CONFIG_ARM_MPU=n
      - arch:xtensa:CONFIG_LLEXT_STORAGE_WRITABLE=y
    harness_config:
      type: one_line
      regex:
        - "Hello, world, from an llext!"
  sample.llext.modules.builtin_build:
    extra_configs:
      - CONFIG_HELLO_WORLD_MODE=y
    harness_config:
      type: one_line
      regex:
        - "Hello, world, from the main binary!"
Loading