llext: Simple hello world test case
Adds a very simple hello world test case for llext. The loadable extension is built and then included as a binary array into the test making it very easy to load, debug, and inspect. The extension is built using the same toolchain as the base image by default. Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
This commit is contained in:
parent
09f38b5f20
commit
b7f3182f79
6 changed files with 138 additions and 0 deletions
26
tests/subsys/llext/CMakeLists.txt
Normal file
26
tests/subsys/llext/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2023 Intel Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(llext_test)
|
||||
|
||||
add_subdirectory(hello_world)
|
||||
|
||||
target_sources(app PRIVATE src/test_llext_simple.c)
|
||||
|
||||
target_include_directories(app PRIVATE
|
||||
${ZEPHYR_BASE}/include
|
||||
${ZEPHYR_BASE}/kernel/include
|
||||
${ZEPHYR_BASE}/arch/${ARCH}/include
|
||||
)
|
||||
|
||||
set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/)
|
||||
|
||||
generate_inc_file_for_target(
|
||||
app
|
||||
${HELLO_WORLD_LLEXT}
|
||||
${gen_dir}/hello_world.inc
|
||||
)
|
||||
|
||||
add_dependencies(app hello_world)
|
17
tests/subsys/llext/hello_world/CMakeLists.txt
Normal file
17
tests/subsys/llext/hello_world/CMakeLists.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Copyright (c) 2023 Intel Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(hello_world)
|
||||
|
||||
# TODO check which architecture is being used
|
||||
set(CMAKE_C_FLAGS "-mlong-calls" "-mthumb")
|
||||
|
||||
add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/hello_world.llext
|
||||
COMMAND ${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -c -o ${PROJECT_BINARY_DIR}/hello_world.llext ${PROJECT_SOURCE_DIR}/hello_world.c
|
||||
)
|
||||
|
||||
set(HELLO_WORLD_LLEXT ${PROJECT_BINARY_DIR}/hello_world.llext PARENT_SCOPE)
|
||||
|
||||
add_custom_target(hello_world DEPENDS ${PROJECT_BINARY_DIR}/hello_world.llext)
|
25
tests/subsys/llext/hello_world/hello_world.c
Normal file
25
tests/subsys/llext/hello_world/hello_world.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* This very simple hello world C code can be used as a test case for building
|
||||
* probably the simplest loadable extension. It requires a single symbol be
|
||||
* linked, section relocation support, and the ability to export and call out to
|
||||
* a function.
|
||||
*/
|
||||
|
||||
/* Various build options should be documented here to generate the test elf for
|
||||
* each architecture.
|
||||
*
|
||||
* armv7-thumb: -mlong-call -mthumb -c -o hello_world_armv7_thumb.elf hello_world.c
|
||||
*/
|
||||
|
||||
extern void printk(char *fmt, ...);
|
||||
|
||||
extern void hello_world(void)
|
||||
{
|
||||
printk("hello world\n");
|
||||
}
|
8
tests/subsys/llext/prj.conf
Normal file
8
tests/subsys/llext/prj.conf
Normal file
|
@ -0,0 +1,8 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_ZTEST_NEW_API=y
|
||||
CONFIG_ZTEST_STACK_SIZE=8192
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_MODE_IMMEDIATE=y
|
||||
CONFIG_LLEXT=y
|
||||
CONFIG_LLEXT_HEAP_SIZE=32
|
||||
CONFIG_LLEXT_LOG_LEVEL_DBG=y
|
51
tests/subsys/llext/src/test_llext_simple.c
Normal file
51
tests/subsys/llext/src/test_llext_simple.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/ztest.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/llext/llext.h>
|
||||
#include <zephyr/llext/buf_loader.h>
|
||||
|
||||
#ifdef CONFIG_ARM /* ARMV7 */
|
||||
const static uint8_t hello_world_elf[] __aligned(4) = {
|
||||
#include "hello_world.inc"
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Attempt to load, list, list symbols, call a fn, and unload a
|
||||
* hello world extension for each supported architecture
|
||||
*
|
||||
* This requires a single linked symbol (printk) and a single
|
||||
* exported symbol from the extension ( void hello_world(void))
|
||||
*/
|
||||
ZTEST(llext, test_llext_simple)
|
||||
{
|
||||
const char name[16] = {'h', 'e', 'l', 'l', 'o', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
struct llext_buf_loader buf_loader =
|
||||
LLEXT_BUF_LOADER(hello_world_elf, ARRAY_SIZE(hello_world_elf));
|
||||
struct llext_loader *loader = &buf_loader.loader;
|
||||
struct llext *ext;
|
||||
const void * const printk_fn = llext_find_sym(NULL, "printk");
|
||||
|
||||
zassert_equal(printk_fn, printk, "printk should be an exported symbol");
|
||||
|
||||
int res = llext_load(loader, name, &ext);
|
||||
|
||||
zassert_ok(res, "load should succeed");
|
||||
|
||||
const void * const hello_world_fn = llext_find_sym(&ext->sym_tab, "hello_world");
|
||||
|
||||
zassert_not_null(hello_world_fn, "hello_world should be an exported symbol");
|
||||
|
||||
res = llext_call_fn(ext, "hello_world");
|
||||
|
||||
zassert_ok(res, "calling hello world should succeed");
|
||||
|
||||
llext_unload(ext);
|
||||
}
|
||||
|
||||
ZTEST_SUITE(llext, NULL, NULL, NULL, NULL, NULL);
|
11
tests/subsys/llext/testcase.yaml
Normal file
11
tests/subsys/llext/testcase.yaml
Normal file
|
@ -0,0 +1,11 @@
|
|||
common:
|
||||
tags: llext
|
||||
tests:
|
||||
llext.simple.arm:
|
||||
filter: not CONFIG_CPU_HAS_MMU
|
||||
arch_allow: arm
|
||||
extra_configs:
|
||||
- CONFIG_ARM_MPU=n
|
||||
# Broken platforms
|
||||
platform_exclude:
|
||||
- nuvoton_pfm_m487 # See #63167
|
Loading…
Add table
Add a link
Reference in a new issue