-
Notifications
You must be signed in to change notification settings - Fork 327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LLEXT multiple modules #9090
LLEXT multiple modules #9090
Conversation
752cbf2
to
7f78163
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just minor optimization questions.
src/audio/eq_iir/eq_iir.c
Outdated
#if CONFIG_COMP_IIR_MODULE | ||
/* modular: llext dynamic link */ | ||
|
||
static const struct module_interface *loadable_eq_iir_main(void *mod_cfg, | ||
void *parent_ppl, | ||
void **mod_ptr) | ||
{ | ||
return &eq_iir_interface; | ||
} | ||
|
||
static const struct sof_man_module_manifest eq_iir_manifest __section(".module") __used = { | ||
.module = { | ||
.name = "EQIIR", | ||
.uuid = {0xE6, 0xC0, 0x50, 0x51, 0xF9, 0x27, 0xC8, 0x4E, | ||
0x83, 0x51, 0xC7, 0x05, 0xB6, 0x42, 0xD1, 0x2F}, | ||
.entry_point = (uint32_t)loadable_eq_iir_main, | ||
.type = { | ||
.load_type = SOF_MAN_MOD_TYPE_LLEXT, | ||
.domain_ll = 1, | ||
}, | ||
.affinity_mask = 1, | ||
} | ||
}; | ||
|
||
static const struct sof_module_api_build_info buildinfo __section(".mod_buildinfo") __used = { | ||
.format = SOF_MODULE_API_BUILD_INFO_FORMAT, | ||
.api_version_number.full = SOF_MODULE_API_CURRENT_VERSION, | ||
}; | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all of this can be expressed as a single macro i.e.
SOF_DECLARE_MODULE(name, interface, uuid);
@@ -0,0 +1,99 @@ | |||
# Copyright (c) 2024 Intel Corporation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming this file will be shrunk/replaced when Zephyr llext cmake helpers are used ?
add_llext_command(TARGET ${MODULE} | ||
POST_BUILD | ||
COMMAND ${SOF_BASE}scripts/llext_link_helper.py | ||
--text-addr="0xa06ea000" -f ${proc_in_file} ${CMAKE_C_COMPILER} -- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where does this address come from ? Does it need to come from platform / DT or Kconfig ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lgirdwood right, now this is a good question, let's talk about this. These address values come originally from the original loadable module concept, whereby we build modules for a fixed address in memory - I think that holds for system services too, probably for IADK as well. Having those addresses helps - it makes linking at run time easier, internal address references are already correct, but it does mean that we need to maintain those addresses somehow somewhere. The original one, that is now used for the smart-amp was exactly the address used in some old examples. Now for mixin-mixout and eq-iir I picked up some addresses "similar" to smart-amp but far enough from it... But you're right, we need to come up with a system of how to assign these addresses or maybe to aim to get rid of them completely and to perform full run-time linking / relocation instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the very least don't copy/paste/diverge it in every module. Define it in one place and ta-da: you can paste your explanation above in that place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, we can have a comment today and have a per platform memory address for this in the Zephyr llext core as next steps, probably best to align with @teburd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had some ideas around this by reusing the devicetree flash partitions or something like it, which is also used by mcuboot to designate memory regions for images.
E.g. imagine a set of partitions described for fixed location modules/applications akin to this dts:
https://github.com/zephyrproject-rtos/zephyr/blob/main/boards/nxp/frdm_k64f/frdm_k64f.dts#L229
I think @dapperlo would also be interested (also using parts of llext) zephyrproject-rtos/zephyr#72258
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interested indeed. I need to ramp on the context for this use-case, but there is a desire for fixed address extensions and the load-time benefits that comes from it.
Nodes in the dts sounds reasonable, routing loaded .llext
blobs could then use a label/attribute in blob header to associate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, we can have a comment today and have a per platform memory address for this in the Zephyr llext core as next steps, probably best to align with @teburd
It isn't just per platform, it's also per module. This is the starting address of this module on this platform. So, we could have a per-platform address range for loadable modules and then per-module offsets defined in modules themselves? But that would mean some co-ordination in terms of sufficiently large offsets. I'm not sure how large is the usable address range e.g. on MTL? If it's large enough we could just dedicate an MB per module?
Alternatively: we already have TOMLs per platform that include all modules, so I'm wondering if we could add in all those locations like
sof/tools/rimage/config/mtl.toml.h
Line 29 in 374d2d6
#ifdef CONFIG_COMP_COPIER |
#define ${MODULE}_base 0x...
statements (e.g. #define smart_amp_test_base 0xa06ca000
) but I'm not sure we'd be able to pull those out into cmake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.g. imagine a set of partitions described for fixed location modules/applications akin to this dts:
https://github.com/zephyrproject-rtos/zephyr/blob/main/boards/nxp/frdm_k64f/frdm_k64f.dts#L229
@teburd yes, looks good, with a slight inconvenience that we now have on MTL something like 28 modules. Maybe a separate .dts, included into the main one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no issue with toml either but I’ll need help in understanding how we piece this together. Do we need to link the extensions to be placed appropriately with a custom linker script per extension slot? Sure seems like it to me at first glance but please do correct me if wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@teburd no, I tried very hard and so far have succeeded in avoiding custom linker scripts. I "only" provide section addresses to the linker on the command line. For that I only take a single base address as input and calculate all further addresses automatically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No blockers really, a few comments inline.
src/include/sof/common.h
Outdated
#ifndef typeof | ||
#define typeof __typeof__ | ||
#endif | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we have a Zephyr solution for this? We should be shrinking, not growing the sof/common.h.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could just replace all typeof()
with __typeof__()
, I haven't found anything global in Zephyr, they have two "local" definitions in arch/arm/include/cortex_m/cmse.h and in drivers/usb/device/usb_dc_rpi_pico.c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kv2019i I think I'll do that - replace that patch with a switch to __typeof__()
globally in SOF
-o ${MODULE}_pre.so $<TARGET_OBJECTS:${MODULE}> | ||
COMMAND ${COPY_CMD} | ||
COMMAND_EXPAND_LISTS | ||
--text-addr="0xa06ca000" -f ${proc_in_file} ${CMAKE_C_COMPILER} -- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This magic address does pop out given this is no way platform specific file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CMake files are 95% copy/paste/diverge! CMake sucks but it has functions and macros. Define a new sof_add_llext()
function and problem solved.
project(smart_amp_test) | ||
|
||
SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) | ||
cmake_path(SET SOF_BASE NORMALIZE ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The quadruple ..
is quite ugly, how about ${APPLICATION_SOURCE_DIR}/..
instead?
# extract UUID value - drop the 'uuid = ' part of the assignment line | ||
string(REGEX REPLACE "^[ \t]*uuid *= \"([0-9A-F\-]*)\"" "\\1" uuid ${line}) | ||
file(APPEND ${ZEPHYR_BINARY_DIR}/${MODULE}_llext/llext.uuid "${uuid}\n") | ||
endforeach() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fairly complex regex, please don't copy/paste/diverge it in every module. Make this a macro or function in zephyr/CMakeLists.txt
Warning: CMake function can't "return" anything: they can only set "pseudo-return" variables. Find a very simple macro example in ef563eb
COMMAND ${CMAKE_C_COMPILER} -E ${CMAKE_CURRENT_LIST_DIR}/llext.toml.h -P -DREM= | ||
-I${SOF_BASE} -I${SOF_BASE}src | ||
-imacros ../include/generated/autoconf.h | ||
-o rimage_config.toml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one does not return anything so it is trivial to make it a shared function in zephyr/CMakeLists.txt
add_llext_command(TARGET ${MODULE} | ||
POST_BUILD | ||
COMMAND ${SOF_BASE}scripts/llext_link_helper.py | ||
--text-addr="0xa06ea000" -f ${proc_in_file} ${CMAKE_C_COMPILER} -- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the very least don't copy/paste/diverge it in every module. Define it in one place and ta-da: you can paste your explanation above in that place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- suffix confusion
- mass CMake duplication
llext_input = entry_path / (llext_base + '.so') | ||
llext_output = entry_path / llext_file | ||
llext_input = entry_path / (llext_base + '.llext') | ||
llext_output = entry_path / (llext_file + '.ri') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Err... no, please don't go from .llext
to .ri
and then BACK to .llext
where each step is a different file type; this is incredibly confusing!
One suggestion:
.llext
because that's what comes from Zephyr so you don't have a choice?.ri0
because that's the first rimage stage. Similar tozephyr_pre0
- Either
.ri
or.llext.ri
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marc-hb yeah, .llext -> something else -> .llext is ugly, I agree. There was a wish to have .llext as the final suffix, but now with the use of Zephyr cmake .llext comes out of those functions. Maybe yes - .llext.ri
would be a good option for the final output
I think this PR should be split in (at least) two PRs:
|
When compiled with '-std=c99' or newer 'typeof' is unavailable and '__typeof__' should be used instead [1]. [1] https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Add 3 macros to simplify LLEXT module implementation and use them in mixin-mixout and eq_iir. Only two of them can be used in smart_amp_test_ipc4.c so far, because it's also used for LMDK-style module building. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Zephyr now provides a convenient cmake API for LLEXT modules, update SOF to use it by defining common cmake functions. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
west.configuration.get() already returns a string, no need to call 'str()' on it again. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Convert mixin-mixout to a loadable llext module. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Build eq-iir as a loadable llext module. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Export additional symbols, needed for modules like eq_iir and mixin-mixout. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
If module_adapter_new() fails in lib_manager_module_create(), lib_manager_free_module() must be called to free allocated resources. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Some components like mixin-mixout implement multiple modules internally. They should be handled by LLEXT as a single ELF object, including for use-counting. But at the SOF level they implement multiple module adapter drivers. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
@marc-hb individual commits like mixin-mixout and eq-iir have become much smaller now (and don't say you didn't ask for that), so, maybe 1 PR would be acceptable |
CI: a single alsabat failure on LNL shouldn't be related https://sof-ci.01.org/sofpr/PR9090/build4606/devicetest/index.html?model=LNLM_SDW_AIOC&testcase=check-alsabat-headset-playback-997 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good to go, the remaining opens are all second order and can be resolved incrementally. The important thing here is to get this code to the CI devs for integration into test/build/sign services.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comments addressed, refresh +1
Looks like this was merged broken: https://github.com/thesofproject/sof/actions/runs/9030070149/job/24813622867
cc: @LaurentiuM1234 |
|
This converts two more modules: mixin-mixout and eq_iir to llext modules. This has an added complexity of mixin-mixout containing two module-adapter drivers. This PR currently contains #9013 with an expectation of that being merged soon, after which the first 7 commits will be dropped from this one.