diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 5341d14e4ddd..6c33d91626cd 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -52,6 +52,7 @@ CONFIG_INTEL_MODULES=y CONFIG_LIBRARY_MANAGER=y CONFIG_LIBRARY_AUTH_SUPPORT=y CONFIG_LIBRARY_BASE_ADDRESS=0xa0688000 +CONFIG_LIBRARY_BUILD_LIB=y # SOF / logging CONFIG_SOF_LOG_LEVEL_INF=y diff --git a/app/boards/intel_adsp_ace30_ptl.conf b/app/boards/intel_adsp_ace30_ptl.conf index d7c1979b63a4..62106d05e02e 100644 --- a/app/boards/intel_adsp_ace30_ptl.conf +++ b/app/boards/intel_adsp_ace30_ptl.conf @@ -36,6 +36,9 @@ CONFIG_ZEPHYR_NATIVE_DRIVERS=y # SOF / loadable modules CONFIG_INTEL_MODULES=y CONFIG_LIBRARY_MANAGER=y +CONFIG_LIBRARY_BASE_ADDRESS=0xa0688000 +CONFIG_LIBRARY_BUILD_LIB=y +CONFIG_LIBRARY_DEFAULT_MODULAR=n # SOF / logging CONFIG_SOF_LOG_LEVEL_INF=y @@ -44,6 +47,9 @@ CONFIG_SOF_LOG_LEVEL_INF=y CONFIG_COUNTER=y CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_L3_HEAP=y +CONFIG_LLEXT=y +CONFIG_LLEXT_STORAGE_WRITABLE=y +CONFIG_MODULES=y # Zephyr / device drivers CONFIG_CLOCK_CONTROL=y diff --git a/scripts/llext_offset_calc.py b/scripts/llext_offset_calc.py index cef0662449bf..0f302a8cbe12 100755 --- a/scripts/llext_offset_calc.py +++ b/scripts/llext_offset_calc.py @@ -6,6 +6,8 @@ import argparse import pathlib import os +from elftools.elf.elffile import ELFFile +from elftools.elf.constants import SH_FLAGS args = None @@ -21,6 +23,34 @@ def parse_args(): args = parser.parse_args() +def get_elf_size(elf_name): + start = 0xffffffff + # SOF_MODULE_DRAM_LINK_END + min_start = 0x08000000 + end = 0 + with open(elf_name, 'rb') as f_elf: + elf = ELFFile(f_elf) + + for section in elf.iter_sections(): + s_flags = section.header['sh_flags'] + + if not s_flags & SH_FLAGS.SHF_ALLOC: + continue + + # Ignore detached sections, to be used in DRAM, their addresses + # are below min_start + if section.header['sh_addr'] < min_start: + continue + + if section.header['sh_addr'] < start: + start = section.header['sh_addr'] + if section.header['sh_addr'] + section.header['sh_size'] > end: + end = section.header['sh_addr'] + section.header['sh_size'] + + size = end - start + + return size + def main(): global args @@ -34,13 +64,12 @@ def main(): except OSError: size = 0 - # Failure will raise an exception - f_size = open(f_output, "w") - + size += get_elf_size(args.input) + 0xfff # align to a page border - size += os.path.getsize(args.input) + 0xfff size &= ~0xfff + # Failure will raise an exception + f_size = open(f_output, "w") f_size.write(f'0x{size:x}\n') if __name__ == "__main__": diff --git a/scripts/xtensa-build-zephyr.py b/scripts/xtensa-build-zephyr.py index 5ce0c633ae7c..a31a93c96d7e 100755 --- a/scripts/xtensa-build-zephyr.py +++ b/scripts/xtensa-build-zephyr.py @@ -926,19 +926,26 @@ def build_platforms(): symlinks=True, ignore_dangling_symlinks=True, dirs_exist_ok=True) -def install_lib(sof_lib_dir, abs_build_dir, platform_wconfig): +def install_lib(platform, sof_output_dir, abs_build_dir, platform_wconfig): """[summary] Sign loadable llext modules, if any, copy them to the deployment tree and create UUID links for the kernel to find and load them.""" global signing_key - with os.scandir(str(abs_build_dir)) as iter: - if args.key_type_subdir != "none": - sof_lib_dir = sof_lib_dir / args.key_type_subdir + libs = dict() + lib_uuids = dict() + rimage_cmd = shlex.split(platform_wconfig.get('rimage.path'))[0] + _ws_args = platform_wconfig.get("rimage.extra-args") + + sof_lib_dir = sof_output_dir / '..' / 'sof-ipc4-lib' / platform - sof_lib_dir.mkdir(parents=True, exist_ok=True) + if args.key_type_subdir != "none": + sof_lib_dir = sof_lib_dir / args.key_type_subdir + + sof_lib_dir.mkdir(parents=True, exist_ok=True) + with os.scandir(str(abs_build_dir)) as iter: for entry in iter: if (not entry.is_dir or not entry.name.endswith('_llext')): @@ -955,45 +962,87 @@ def install_lib(sof_lib_dir, abs_build_dir, platform_wconfig): # eq_iir_llext/eq_iir.llext llext_base = entry.name[:-6] llext_file = llext_base + '.llext' - - dst = sof_lib_dir / llext_file - - rimage_cfg = entry_path / 'rimage_config.toml' - llext_input = entry_path / (llext_base + '.llext') - llext_output = entry_path / (llext_file + '.ri') - - # See why the shlex() parsing step is required at - # https://docs.zephyrproject.org/latest/develop/west/sign.html#rimage - # and in Zephyr commit 030b740bd1ec - rimage_cmd = shlex.split(platform_wconfig.get('rimage.path'))[0] - sign_cmd = [rimage_cmd, "-o", str(llext_output), - "-e", "-c", str(rimage_cfg), - "-k", str(signing_key), "-l", "-r"] - _ws_args = platform_wconfig.get("rimage.extra-args") - if _ws_args is not None: - sign_cmd.extend(shlex.split(_ws_args)) - sign_cmd.append(str(llext_input)) - execute_command(sign_cmd, cwd=west_top) - - # An intuitive way to make this multiline would be - # with (open(dst, 'wb') as fdst, open(llext_output, 'rb') as fllext, - # open(llext_output.with_suffix('.llext.xman'), 'rb') as fman): - # but a Python version, used on Windows errored out on this. - # Thus we're left with a choice between a 150-character - # long line and an illogical split like this - with open(dst, 'wb') as fdst, open(llext_output, 'rb') as fllext, open( - llext_output.with_suffix('.ri.xman'), 'rb') as fman: - # Concatenate the manifest and the llext - shutil.copyfileobj(fman, fdst) - shutil.copyfileobj(fllext, fdst) + lib_name = '' + + lib_fname = entry_path / 'lib_name.txt' + if os.path.exists(lib_fname): + with open(lib_fname, 'r') as libs_f: + lib_name = libs_f.read() + if lib_name not in libs.keys(): + libs[lib_name] = [] + libs[lib_name].append(str(entry_path / llext_file)) + else: + dst = sof_lib_dir / llext_file + + rimage_cfg = entry_path / 'rimage_config.toml' + llext_input = entry_path / (llext_base + '.llext') + llext_output = entry_path / (llext_file + '.ri') + + # See why the shlex() parsing step is required at + # https://docs.zephyrproject.org/latest/develop/west/sign.html#rimage + # and in Zephyr commit 030b740bd1ec + sign_cmd = [rimage_cmd, "-o", str(llext_output), + "-e", "-c", str(rimage_cfg), + "-k", str(signing_key), "-l", "-r"] + if _ws_args is not None: + sign_cmd.extend(shlex.split(_ws_args)) + sign_cmd.append(str(llext_input)) + execute_command(sign_cmd, cwd=west_top) + + # An intuitive way to make this multiline would be + # with (open(dst, 'wb') as fdst, open(llext_output, 'rb') as fllext, + # open(llext_output.with_suffix('.llext.xman'), 'rb') as fman): + # but a Python version, used on Windows errored out on this. + # Thus we're left with a choice between a 150-character + # long line and an illogical split like this + with open(dst, 'wb') as fdst, open(llext_output, 'rb') as fllext, open( + llext_output.with_suffix('.ri.xman'), 'rb') as fman: + # Concatenate the manifest and the llext + shutil.copyfileobj(fman, fdst) + shutil.copyfileobj(fllext, fdst) # Create symbolic links for all UUIDs with open(uuids, 'r') as uuids_f: for uuid in uuids_f: - linkname = uuid.strip() + '.bin' - symlink_or_copy(sof_lib_dir, llext_file, - sof_lib_dir, linkname) + if os.path.exists(lib_fname): + if lib_name not in lib_uuids.keys(): + lib_uuids[lib_name] = [] + lib_uuids[lib_name].append(uuid.strip()) + else: + linkname = uuid.strip() + '.bin' + symlink_or_copy(sof_lib_dir, llext_file, + sof_lib_dir, linkname) + + lib_install_dir = sof_output_dir / platform + if args.key_type_subdir != "none": + lib_install_dir = lib_install_dir / args.key_type_subdir + + for key in libs.keys(): + lib_path = abs_build_dir / ''.join(['lib', key, '.ri']) + sign_cmd = [rimage_cmd, "-o", str(lib_path), "-e", + "-c", str(abs_build_dir / 'misc' / 'generated' / 'rimage_config_full.toml'), + "-k", str(signing_key), "-l", "-r"] + if _ws_args is not None: + sign_cmd.extend(shlex.split(_ws_args)) + sign_cmd.extend(libs[key]) + execute_command(sign_cmd, cwd=west_top) + lib_name = ''.join(['sof-', platform, '-', key, '.ri']) + dst = lib_install_dir / lib_name + with open(dst, 'wb') as fdst, open(lib_path, 'rb') as fllext, open( + lib_path.with_suffix('.ri.xman'), 'rb') as fman: + # Concatenate the manifest and the llext + shutil.copyfileobj(fman, fdst) + shutil.copyfileobj(fllext, fdst) + + for p_alias in platform_configs[platform].aliases: + lib_dir = sof_output_dir / p_alias + if args.key_type_subdir != "none": + lib_dir = lib_dir / args.key_type_subdir + lib_dir.mkdir(parents=True, exist_ok=True) + alias_libname = ''.join(['sof-', p_alias, '-', key, '.ri']) + symlink_or_copy(lib_install_dir, lib_name, + lib_dir, alias_libname) def install_platform(platform, sof_output_dir, platf_build_environ, platform_wconfig): @@ -1042,8 +1091,7 @@ def install_platform(platform, sof_output_dir, platf_build_environ, platform_wco symlink_or_copy(install_key_dir, output_fwname, install_key_dir, f"sof-{p_alias}.ri") if args.deployable_build and platform_configs[platform].ipc4: - install_lib(sof_output_dir / '..' / 'sof-ipc4-lib' / platform, abs_build_dir, - platform_wconfig) + install_lib(platform, sof_output_dir, abs_build_dir, platform_wconfig) # sof-info/ directory diff --git a/src/audio/aria/llext/CMakeLists.txt b/src/audio/aria/llext/CMakeLists.txt index 080581dbcdb6..d6a6e0411fc1 100644 --- a/src/audio/aria/llext/CMakeLists.txt +++ b/src/audio/aria/llext/CMakeLists.txt @@ -6,4 +6,5 @@ sof_llext_build("aria" ../aria_hifi5.c ../aria_hifi3.c ../aria_generic.c + LIB openmodules ) diff --git a/src/audio/asrc/llext/CMakeLists.txt b/src/audio/asrc/llext/CMakeLists.txt index 93f26a228913..8ef1d2e26fa6 100644 --- a/src/audio/asrc/llext/CMakeLists.txt +++ b/src/audio/asrc/llext/CMakeLists.txt @@ -7,4 +7,5 @@ sof_llext_build("asrc" ../asrc_farrow.c ../asrc_farrow_generic.c ../asrc_ipc4.c + LIB openmodules ) diff --git a/src/audio/codec/dts/llext/CMakeLists.txt b/src/audio/codec/dts/llext/CMakeLists.txt index f73dc4d3123b..23ace9bd95ac 100644 --- a/src/audio/codec/dts/llext/CMakeLists.txt +++ b/src/audio/codec/dts/llext/CMakeLists.txt @@ -5,6 +5,7 @@ if(CONFIG_DTS_CODEC_STUB) sof_llext_build("dts" SOURCES ../dts.c ../dts_stub.c + LIB openmodules ) target_include_directories(dts_llext_lib PRIVATE "../../../../../third_party/include" diff --git a/src/audio/crossover/llext/CMakeLists.txt b/src/audio/crossover/llext/CMakeLists.txt index 0adb2631e60f..b4b6e9def9b1 100644 --- a/src/audio/crossover/llext/CMakeLists.txt +++ b/src/audio/crossover/llext/CMakeLists.txt @@ -5,4 +5,5 @@ sof_llext_build("crossover" SOURCES ../crossover.c ../crossover_generic.c ../crossover_ipc4.c + LIB openmodules ) diff --git a/src/audio/dcblock/llext/CMakeLists.txt b/src/audio/dcblock/llext/CMakeLists.txt index 9aa677d05be4..63a95013ab5f 100644 --- a/src/audio/dcblock/llext/CMakeLists.txt +++ b/src/audio/dcblock/llext/CMakeLists.txt @@ -7,4 +7,5 @@ sof_llext_build("dcblock" ../dcblock_hifi3.c ../dcblock_hifi4.c ../dcblock_ipc4.c + LIB openmodules ) diff --git a/src/audio/drc/llext/CMakeLists.txt b/src/audio/drc/llext/CMakeLists.txt index e658c3acfe0b..d12e94790597 100644 --- a/src/audio/drc/llext/CMakeLists.txt +++ b/src/audio/drc/llext/CMakeLists.txt @@ -8,4 +8,5 @@ sof_llext_build("drc" ../drc_hifi3.c ../drc_hifi4.c ../drc_math_hifi3.c + LIB openmodules ) diff --git a/src/audio/eq_fir/llext/CMakeLists.txt b/src/audio/eq_fir/llext/CMakeLists.txt index 9b4f47308c49..df4b3a16c89e 100644 --- a/src/audio/eq_fir/llext/CMakeLists.txt +++ b/src/audio/eq_fir/llext/CMakeLists.txt @@ -3,8 +3,9 @@ sof_llext_build("eq_fir" SOURCES ../eq_fir_hifi3.c - ../eq_fir_hifi2ep.c - ../eq_fir_generic.c - ../eq_fir.c - ../eq_fir_ipc4.c + ../eq_fir_hifi2ep.c + ../eq_fir_generic.c + ../eq_fir.c + ../eq_fir_ipc4.c + LIB openmodules ) diff --git a/src/audio/eq_iir/llext/CMakeLists.txt b/src/audio/eq_iir/llext/CMakeLists.txt index 535455105515..9b5d956e82b0 100644 --- a/src/audio/eq_iir/llext/CMakeLists.txt +++ b/src/audio/eq_iir/llext/CMakeLists.txt @@ -5,4 +5,5 @@ sof_llext_build("eq_iir" SOURCES ../eq_iir.c ../eq_iir_ipc4.c ../eq_iir_generic.c + LIB openmodules ) diff --git a/src/audio/google/llext_ctc/CMakeLists.txt b/src/audio/google/llext_ctc/CMakeLists.txt index 440e0fbe6ad2..c04c9765bf1d 100644 --- a/src/audio/google/llext_ctc/CMakeLists.txt +++ b/src/audio/google/llext_ctc/CMakeLists.txt @@ -6,6 +6,7 @@ sof_llext_build("google_ctc_audio_processing" SOURCES ../google_ctc_audio_processing.c ../google_ctc_audio_processing_ipc4.c ../google_ctc_audio_processing_mock.c + LIB openmodules ) target_include_directories(google_ctc_audio_processing_llext_lib PRIVATE "${sof_top_dir}/third_party/include" diff --git a/src/audio/google/llext_rtc/CMakeLists.txt b/src/audio/google/llext_rtc/CMakeLists.txt index 0847fbc8bc57..7cf47276d62e 100644 --- a/src/audio/google/llext_rtc/CMakeLists.txt +++ b/src/audio/google/llext_rtc/CMakeLists.txt @@ -2,6 +2,7 @@ if(CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK) sof_llext_build("google_rtc_audio_processing" SOURCES ../google_rtc_audio_processing.c ../google_rtc_audio_processing_mock.c + LIB openmodules ) target_include_directories(google_rtc_audio_processing_llext_lib PRIVATE "${sof_top_dir}/third_party/include" diff --git a/src/audio/igo_nr/llext/CMakeLists.txt b/src/audio/igo_nr/llext/CMakeLists.txt index 2e974cae7945..3f336184fb7c 100644 --- a/src/audio/igo_nr/llext/CMakeLists.txt +++ b/src/audio/igo_nr/llext/CMakeLists.txt @@ -5,6 +5,7 @@ if(CONFIG_DTS_CODEC_STUB) sof_llext_build("igo_nr" SOURCES ../igo_nr.c ../igo_nr_stub.c + LIB openmodules ) target_include_directories(igo_nr_llext_lib PRIVATE "../../../../third_party/include" diff --git a/src/audio/mfcc/llext/CMakeLists.txt b/src/audio/mfcc/llext/CMakeLists.txt index a3184ecbc150..688342751d75 100644 --- a/src/audio/mfcc/llext/CMakeLists.txt +++ b/src/audio/mfcc/llext/CMakeLists.txt @@ -8,4 +8,5 @@ sof_llext_build("mfcc" ../mfcc_generic.c ../mfcc_hifi3.c ../mfcc_hifi4.c + LIB openmodules ) diff --git a/src/audio/mixin_mixout/llext/CMakeLists.txt b/src/audio/mixin_mixout/llext/CMakeLists.txt index fc5278dc47b0..300130fbe82e 100644 --- a/src/audio/mixin_mixout/llext/CMakeLists.txt +++ b/src/audio/mixin_mixout/llext/CMakeLists.txt @@ -6,4 +6,5 @@ sof_llext_build("mixin_mixout" ../mixin_mixout_hifi3.c ../mixin_mixout_hifi5.c ../mixin_mixout_generic.c + LIB openmodules ) diff --git a/src/audio/multiband_drc/llext/CMakeLists.txt b/src/audio/multiband_drc/llext/CMakeLists.txt index 73c0c4136c30..dbafe5164220 100644 --- a/src/audio/multiband_drc/llext/CMakeLists.txt +++ b/src/audio/multiband_drc/llext/CMakeLists.txt @@ -5,4 +5,5 @@ sof_llext_build("multiband_drc" SOURCES ../multiband_drc.c ../multiband_drc_generic.c ../multiband_drc_ipc4.c + LIB openmodules ) diff --git a/src/audio/mux/llext/CMakeLists.txt b/src/audio/mux/llext/CMakeLists.txt index c17801d9af67..d23b29f5588d 100644 --- a/src/audio/mux/llext/CMakeLists.txt +++ b/src/audio/mux/llext/CMakeLists.txt @@ -5,4 +5,5 @@ sof_llext_build("mux" SOURCES ../mux.c ../mux_generic.c ../mux_ipc4.c + LIB openmodules ) diff --git a/src/audio/rtnr/llext/CMakeLists.txt b/src/audio/rtnr/llext/CMakeLists.txt index 3d028ace0adf..1abba6c3befc 100644 --- a/src/audio/rtnr/llext/CMakeLists.txt +++ b/src/audio/rtnr/llext/CMakeLists.txt @@ -5,6 +5,7 @@ if(CONFIG_COMP_RTNR_STUB) sof_llext_build("rtnr" SOURCES ../rtnr.c ../rtnr_stub.c + LIB openmodules ) else() message(FATAL_ERROR "Add library linking support in src/audio/rtnr/llext/CMakeFiles.txt") diff --git a/src/audio/selector/llext/CMakeLists.txt b/src/audio/selector/llext/CMakeLists.txt index e8c3fbc911a4..460b547e64c6 100644 --- a/src/audio/selector/llext/CMakeLists.txt +++ b/src/audio/selector/llext/CMakeLists.txt @@ -4,4 +4,5 @@ sof_llext_build("selector" SOURCES ../selector.c ../selector_generic.c + LIB openmodules ) diff --git a/src/audio/src/llext/CMakeLists.txt b/src/audio/src/llext/CMakeLists.txt index 84a0bc4465df..dfb9782ee941 100644 --- a/src/audio/src/llext/CMakeLists.txt +++ b/src/audio/src/llext/CMakeLists.txt @@ -11,6 +11,7 @@ sof_llext_build("src" ../src_common.c ../src_ipc4.c ../src_lite.c + LIB openmodules ) else() sof_llext_build("src" @@ -21,5 +22,6 @@ sof_llext_build("src" ../src.c ../src_common.c ../src_ipc4.c + LIB openmodules ) endif() diff --git a/src/audio/tdfb/llext/CMakeLists.txt b/src/audio/tdfb/llext/CMakeLists.txt index 3f9e301947dd..3a12afea12ca 100644 --- a/src/audio/tdfb/llext/CMakeLists.txt +++ b/src/audio/tdfb/llext/CMakeLists.txt @@ -8,4 +8,5 @@ sof_llext_build("tdfb" ../tdfb_hifiep.c ../tdfb_hifi3.c ../tdfb_ipc4.c + LIB openmodules ) diff --git a/src/audio/volume/llext/CMakeLists.txt b/src/audio/volume/llext/CMakeLists.txt index 74a78873eba6..ca33117f0a67 100644 --- a/src/audio/volume/llext/CMakeLists.txt +++ b/src/audio/volume/llext/CMakeLists.txt @@ -10,4 +10,5 @@ sof_llext_build("volume" ../volume_hifi4_with_peakvol.c ../volume.c ../volume_ipc4.c + LIB openmodules ) diff --git a/src/library_manager/Kconfig b/src/library_manager/Kconfig index 7791e8839ac2..598551a6c650 100644 --- a/src/library_manager/Kconfig +++ b/src/library_manager/Kconfig @@ -41,6 +41,14 @@ config LIBRARY_DEFAULT_MODULAR code has tristate Kconfig entries, they will default to "m" if this option is selected. +config LIBRARY_BUILD_LIB + bool "Pack LLEXT modules into a library" + depends on LLEXT + help + The first option to build LLEXT modules is to pack one module per + file. This option enables packing of all enabled modules into a single + module library. + config LIBRARY_BASE_ADDRESS hex "Base address for memory, dedicated to loadable modules" default 0 diff --git a/src/samples/audio/smart_amp_test_llext/CMakeLists.txt b/src/samples/audio/smart_amp_test_llext/CMakeLists.txt index 2218f41423b5..804ab497d4e7 100644 --- a/src/samples/audio/smart_amp_test_llext/CMakeLists.txt +++ b/src/samples/audio/smart_amp_test_llext/CMakeLists.txt @@ -3,4 +3,5 @@ sof_llext_build("smart_amp_test" SOURCES ../smart_amp_test_ipc4.c + LIB openmodules ) diff --git a/tools/rimage/config/lnl.toml.h b/tools/rimage/config/lnl.toml.h index 247a4975f9c8..3209b93d7ac9 100644 --- a/tools/rimage/config/lnl.toml.h +++ b/tools/rimage/config/lnl.toml.h @@ -24,31 +24,31 @@ index = __COUNTER__ -#ifdef CONFIG_COMP_MIXIN_MIXOUT +#if defined(CONFIG_COMP_MIXIN_MIXOUT) || defined(LLEXT_FORCE_ALL_MODULAR) #include