Skip to content

Commit

Permalink
llext: add support for library building
Browse files Browse the repository at this point in the history
Build libraries of modules, as specified in their cmake files.

Signed-off-by: Guennadi Liakhovetski <[email protected]>
  • Loading branch information
lyakh committed Dec 9, 2024
1 parent f50bff1 commit 6cabe05
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 45 deletions.
37 changes: 33 additions & 4 deletions scripts/llext_offset_calc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand All @@ -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__":
Expand Down
126 changes: 85 additions & 41 deletions scripts/xtensa-build-zephyr.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

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)
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')):
Expand All @@ -955,45 +962,83 @@ 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)

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 = sof_lib_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 / '..' / 'sof-ipc4-lib' / 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(sof_lib_dir, lib_name,
lib_dir, alias_libname)

def install_platform(platform, sof_output_dir, platf_build_environ, platform_wconfig):

Expand Down Expand Up @@ -1042,8 +1087,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
Expand Down

0 comments on commit 6cabe05

Please sign in to comment.