Skip to content
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

lmdk: How to convert and build loadable modules #488

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 84 additions & 3 deletions getting_started/loadable_modules/lmdk_user_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,86 @@ What is LMDK

LMDK(Loadable Module Development Kit) is a standalone package required to build loadable module. It is independent from SOF FW but contains necessary data structures to interact with it.

.. code-block:: bash

$ python scripts/lmdk/libraries_build.py -l dummy -k "/path/to/signing/key.pem"

Latest headers pack is being deployed with FW and its versioning is keept in sof\src\include\module\module\api_ver.h . Every change in headers must be marked in that header(todo: automation).
softwarecki marked this conversation as resolved.
Show resolved Hide resolved
Creating deployment header pack is done by calling:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what a 'headers pack' means.


.. code-block:: bash

$ python scripts/lmdk/header_pack.py

These headers should be extracted in include directory of lmdk with the same include path as it is in the sof project.

.. code-block:: cmake

target_compile_definitions(dummy PRIVATE CONFIG_XTENSA=1
CONFIG_IPC_MAJOR_4=1
CONFIG_LIBRARY=1
XCHAL_HAVE_HIFI3=1
SOF_MODULE_API_PRIVATE=1)

set(LMDK_DIR_INCLUDE ../../../lmdk/include)

target_include_directories(up_down_mixer PRIVATE "${LMDK_DIR_INCLUDE}"
"${LMDK_DIR_INCLUDE}/src/include"
"${LMDK_DIR_INCLUDE}/src/include/sof/audio/module_adapter/iadk"
"${LMDK_DIR_INCLUDE}/posix/include"
"${LMDK_DIR_INCLUDE}/posix/include/sof"

Good example how to prepare module for using lmdk exported headers is included dummy module.

How to prepare MODULE to be loadable
************************************

Loadable modules are using functions provided by native_system_services which are narrowed to only neccesary and safe functions. For example all dynamic allocations are done on strict size local heap_mem
softwarecki marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the definition of 'safe' in this context?

declared in a body of the module.

.. code-block:: c

static struct native_system_service_api* system_service;
uint32_t heap_mem[2048] __attribute__((section(".heap_mem"))) __attribute__((aligned(4096)));

Each module also has to declare as a loadable and has prepared manifest which is specific for each.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is that manifest?


.. code-block:: c

DECLARE_LOADABLE_MODULE_API_VERSION(dummy);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid this term.
mockup or example?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stub, placeholder, example


static void* entry_point(void* mod_cfg, void* parent_ppl, void** mod_ptr)
{
system_service = *(const struct native_system_agent**)mod_ptr;

return &up_down_mixer_interface;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha that's interesting, I was told this component is deprecated...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@plbossart I don't understand, can you elaborate?

}

__attribute__((section(".module")))
const struct sof_man_module_manifest dummy_module_manifest = {
.module = {
.name = "DUMMY",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example_module or something

.uuid = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?? why can't we use a regular UUID.

.entry_point = (uint32_t)dummyPackageEntryPoint,
.type = {
.load_type = SOF_MAN_MOD_TYPE_MODULE,
.domain_ll = 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are DP modules supported?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@plbossart Native loadable libraries (LMDK) supports DP processing if they provide a processing function based on the sink/source interface.

int (*process)(struct processing_module *mod,
               struct sof_source **sources, int num_of_sources,
               struct sof_sink **sinks, int num_of_sinks);

},
.affinity_mask = 3,
softwarecki marked this conversation as resolved.
Show resolved Hide resolved
}
};



How to build
************
Designers of lmdk prepared two options of building loadable modules. Using them is depend from needs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider rewording, this does not read well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also explain which one should be use when. You are just listing two solutions without any explanations on pros/cons.


Using CMake scripts
===================
To build example loadable library execute:
.. code-block:: bash

.. code-block:: bash

$ cd libraries/example
$ mkdir build
Expand All @@ -21,5 +96,11 @@ To build example loadable library execute:
$ cmake -DRIMAGE_COMMAND="/path/to/rimage" -DSIGNING_KEY="/path/to/signing/key.pem" ..
$ cmake --build .

Here RIMAGE_COMMAND is path to rimage executable binary, SIGNING_KEY is path to
signing key for rimage. `LMDK <https://github.com/thesofproject/sof/pull/7354>`
Using Python scripts
====================
Building module using python

.. code-block:: bash

$ python scripts/lmdk/libraries_build.py -l dummy -k "/path/to/signing/key.pem"

Loading