概要
をヒントに、
Flashに置いたhello_world.llextから関数を動的ロードして実行する実験を行う。
ボード
こちらを使う
https://docs.zephyrproject.org/latest/boards/nxp/frdm_mcxn947/doc/index.html
コーディング
フラッシュからの読み出しということで、NXPのFMUというペリフェラルを使えばよいとのことなので、
それでもって、読み出し部分のAPIを実装した。
struct flash_loader_wrapper {
struct llext_loader loader; // Must be top
uintptr_t base;
size_t pos;
const struct device* dev;
};
static const struct device *flash_ctl_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller));
static int _read(struct llext_loader *ldr, void *dest, size_t len)
{
struct flash_loader_wrapper *flw = CONTAINER_OF(ldr, struct flash_loader_wrapper, loader);
int rc = flash_read(flw->dev, flw->base + flw->pos, dest, len);
if (rc == 0) {
LOG_INF("loaded addr :%p size:%d\n", (void*)(flw->base + flw->pos), len);
flw->pos += len;
}
return rc;
}
static int _seek(struct llext_loader *ldr, size_t pos)
{
struct flash_loader_wrapper *flw = CONTAINER_OF(ldr, struct flash_loader_wrapper, loader);
flw->pos = pos;
LOG_INF("seeked pos:%d\n", flw->pos);
return 0;
}
static void init_flash_loader_wrapper(struct flash_loader_wrapper *flw, const struct device *dev, uintptr_t flash_base)
{
flw->dev = dev;
flw->pos = 0;
flw->base = flash_base;
flw->loader.read = _read;
flw->loader.seek = _seek;
}
そして、以下のようにしてローダを今回実装したものに指定する。
int main(void)
{
LOG_INF("Calling hello world as a module");
#ifdef LOAD_FROM_FLASH_ADDR
struct flash_loader_wrapper flw = {0};
init_flash_loader_wrapper(&flw, flash_ctl_dev, LOAD_FROM_FLASH_ADDR);
struct llext_loader *ldr = &flw.loader;
#else
size_t llext_buf_len = ARRAY_SIZE(llext_buf);
struct llext_buf_loader buf_loader = LLEXT_BUF_LOADER(llext_buf, llext_buf_len);
struct llext_loader *ldr = &buf_loader.loader;
#endif
...
..
ソースコードは以下にコミットしておいた。
https://github.com/zephyrproject-rtos/zephyr/commit/1105af8d04c28eeafad92c9c5b08bf7dba597206
ビルド
CONFIG_ARM_MPUの無効化が必要とのことなので、CMakeのオプションを直接指定してビルドする
$ west build -p -b frdm_mcxn947/mcxn947/cpu0 -T sample.llext.modules.module_build samples/subsys/llext/modules/ -- -DCONFIG_ARM_MPU=n
.llextのFlash
LinkServerのフラッシュツールは、.llext拡張子のファイルはサポート外のようなエラーが出たので、
llext拡張子をbinにしたバイナリを事前に用意しておこう。
cp ~/zephyrproject/zephyr/build/llext/hello_world.llext /tmp/hello.bin
そして、適当な位置に焼き込む。
/usr/local/LinkServer_26.3.123/LinkServer flash MCXN947:FRDM-MCXN947 load /tmp/hello.bin:0x100000
念の為Dumpして、焼けたことを確認しておこう...
$ /usr/local/LinkServer_26.3.123/LinkServer flash MCXN947:FRDM-MCXN947 dump 0x100000 16 ./dumped_0x100000
$ hexdump -c ./dumped_0x100000
0000000 177 E L F 001 001 001 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000010
ちゃんとELFヘッダがあるな![]()
動作確認
$ west flash
起動ログを見てみよう
*** Booting Zephyr OS build v4.4.0-539-g1105af8d04c2 ***
[00:00:00.014,000] <inf> app: Calling hello world as a module
[00:00:00.020,000] <dbg> llext: do_llext_load: Loading ELF data...
[00:00:00.026,000] <inf> app: seeked pos:0
[00:00:00.031,000] <inf> app: loaded addr :0x100000 size:52
[00:00:00.037,000] <dbg> llext: llext_load_elf_data: Loading relocatable ELF
[00:00:00.044,000] <inf> app: seeked pos:504
[00:00:00.049,000] <inf> app: loaded addr :0x1001f8 size:520
[00:00:00.055,000] <dbg> llext: do_llext_load: Finding ELF tables...
[00:00:00.062,000] <dbg> llext: llext_find_tables: section 0 at 0: name 0, type 0, flags 0, addr 0, align 0, size 0, link 0, info 0
[00:00:00.074,000] <dbg> llext: llext_find_tables: section 1 at 0x34: name 31, type 1, flags 0x6, addr 0, align 0x4, size 24, link 0, info 0
省略...
[00:00:01.076,000] <inf> app: loaded addr :0x100148 size:16
[00:00:01.082,000] <dbg> elf: arch_elf_relocate: 2 300025f8 300025a5 hello_world
[00:00:01.090,000] <dbg> llext: llext_export_symbols: sym 0x300025a5 name hello_world
[00:00:01.098,000] <dbg> llext: do_llext_load: Loaded llext: 337 bytes in heap, .text at 0x300025a4, .rodata at 0x300025c4
[00:00:01.110,000] <inf> llext: Loaded extension ext
Hello, world, from an llext!
[00:00:01.118,000] <dbg> llext: llext_free_regions: freeing memory region 0
[00:00:01.125,000] <dbg> llext: llext_free_regions: freeing memory region 2
[00:00:01.132,000] <dbg> llext: llext_free_regions: freeing memory region 4
[00:00:01.140,000] <dbg> llext: llext_free_regions: freeing memory region 5
[00:00:01.147,000] <dbg> llext: llext_free_regions: freeing memory region 6
[00:00:01.155,000] <dbg> llext: llext_free_regions: freeing memory region 7
素晴らしい![]()
seekやloadも動いてそうだ。
感想
Zephyrが公式にこういったサブシステムを実装してくれているのは助かる。
.llext自体はelfとはいえ軽量そうだし、
ネットワーク経由などで、外部からAppをFlashに引き込んでおき、動的ロードなんてこともできそう![]()