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

loadable modules: add support for loading modules on Xtensa #62433

Merged
merged 17 commits into from
Dec 1, 2023

Conversation

lyakh
Copy link
Collaborator

@lyakh lyakh commented Sep 8, 2023

This is based on an earlier version of #57086 . The latter has a few more commits now, but the final state isn't very different from my snapshot - @teburd has fixed a couple of bugs that I also found and fixed in this PR, added support for some ARM specific features, and started work on Xtensa relocation code, which isn't used here yet. So far this code can load shared objects, built as PIC, which don't need relocation. This is still WiP, I expect comments, fixes, and a couple more iterations of this.

@teburd
Copy link
Collaborator

teburd commented Sep 20, 2023

I've worked on incorporating the EXPORT_SYMBOL work from this PR, which was great. I've reused some existing macros/linker scripts that are useful beyond just ace to do that. Iterable sections and common-ram.ld for now. So same general idea but slight variation on how its implemented.

Ideally in the base image the symbol table would be const and placed in rom for most systems, and in loadable modules perhaps a custom linker section could be constructed and then imported to determine which symbols are actually intentionally exported as opposed to the ones marked extern as I've done so far.

For loadable modules we likely want the symbol table to be still placed in RAM so that it can be updated on relocation.

I don't think generally we can rely on module_peek though. When memory is allocated for a loadable module, on MMU systems especially though also for MPU systems, we likely need to setup some memory permissions (e.g. RO, RW, RX) for the various sections and I don't think its enough to simply point at an arbitrary address in the ELF stream to do that. So module_peek is unlikely to make it in without maybe some pre-defined page aligned sections making the elf stream potentially much bigger than it needs to be.

I could be wrong though, and please correct me if so!

@lyakh
Copy link
Collaborator Author

lyakh commented Sep 21, 2023

I don't think generally we can rely on module_peek though.

@teburd I thought it would be a bit controversial. But so far I see only one implementation of module operations in your PR - one for buffers. And in it your module_buf_read() does just a memcpy(), so it does assume direct access to that memory. And as you see .module_peek() is extremely convenient - it eliminates the need to copy large memory areas of unknown size, both saving memory and time. I'd very much like to find a way to cleanly integrate it.

@teburd
Copy link
Collaborator

teburd commented Sep 21, 2023

I don't think generally we can rely on module_peek though.

@teburd I thought it would be a bit controversial. But so far I see only one implementation of module operations in your PR - one for buffers. And in it your module_buf_read() does just a memcpy(), so it does assume direct access to that memory. And as you see .module_peek() is extremely convenient - it eliminates the need to copy large memory areas of unknown size, both saving memory and time. I'd very much like to find a way to cleanly integrate it.

So just to clarify my thinking here... and put into github our conversation a bit

Not all streams will come from memory that can be mapped into an addressable space, its very likely some elfs will come from off-chip flash that can be read from and copied out but not mapped.

At the same time I completely agree that if you have memory that can be directly mapped, and you happen to have an elf file that is padded and aligned appropriately... as is I believe your case, it should be entirely supported to directly map the elf.

In the buffer case, its pretty lame that there's allocations for things like elf headers and section headers when its... right there and can be pointed at.

So to support all of these cases I think a little bit of rethinking on the module stream interface is needed to support it.

Basic idea would be to modify module_stream_read to take... the stream, memory kind (rx, ro, rw, metadata), and length to read as parameters, while returning a void *.

e.g.

void* module_read(struct module_stream *ms, enum module_mem_kind *mk, size_t sz);

The stream itself can be the allocator then when it needs to be, or it can simply pass back a pointer into the elf. And since the stream API is overrideable it means any of the above scenarios is easily dealt with, leaving the load and link functions to do what the need to without worrying about it or having branching all over the place.

This is likely worth doing after the initial PR though as the initial PR is already quite close and mostly needs one other architecture to work imo.

@lyakh
Copy link
Collaborator Author

lyakh commented Sep 26, 2023

void* module_read(struct module_stream *ms, enum module_mem_kind *mk, size_t sz);

mk doesn't have to be a pointer, does it? Otherwise - yes! One could also simplify the API a bit more by removing module_seek() and adding an offset to module_read() but that's optional - I'm fine either way.

The stream itself can be the allocator then when it needs to be, or it can simply pass back a pointer into the elf. And since the stream API is overrideable it means any of the above scenarios is easily dealt with, leaving the load and link functions to do what the need to without worrying about it or having branching all over the place.
This is likely worth doing after the initial PR though as the initial PR is already quite close and mostly needs one other architecture to work imo.

As also just discussed offline, internal allocation is difficult because it's unknown when to free that memory. I think we need an additional memory pointer for the call. The caller will provide a buffer - be it allocated, on stack or static. And if the caller knows, that they can peek at the image, they'll supply NULL for the buffer

Otherwise this version now works both with twister with the added here Xtensa ELF object, and with SOF.

lyakh added a commit to lyakh/sof that referenced this pull request Sep 26, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
@lyakh lyakh force-pushed the ldlib-wip branch 3 times, most recently from 59d326b to 43be0a5 Compare September 29, 2023 12:35
lyakh added a commit to lyakh/sof that referenced this pull request Sep 29, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
@lyakh lyakh force-pushed the ldlib-wip branch 3 times, most recently from e38866f to a4472f8 Compare October 3, 2023 15:49
lyakh added a commit to lyakh/sof that referenced this pull request Oct 3, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
lyakh added a commit to lyakh/sof that referenced this pull request Oct 4, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
lyakh added a commit to lyakh/sof that referenced this pull request Oct 4, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
lyakh added a commit to lyakh/sof that referenced this pull request Oct 4, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
@lyakh
Copy link
Collaborator Author

lyakh commented Oct 26, 2023

This now temporarily includes #64381 until it's merged

@lyakh
Copy link
Collaborator Author

lyakh commented Oct 27, 2023

This is an interesting failure "Illegal use of the EPSR" https://github.com/zephyrproject-rtos/zephyr/actions/runs/6665109962/job/18114283475?pr=62433 @teburd any ideas?

@lyakh
Copy link
Collaborator Author

lyakh commented Oct 27, 2023

This is an interesting failure "Illegal use of the EPSR" https://github.com/zephyrproject-rtos/zephyr/actions/runs/6665109962/job/18114283475?pr=62433 @teburd any ideas?

This failure only happens on Cortex M3 and it's introduced by dbd17fa i.e. by the commit, that switches from copying ELF sections to using them in their existing buffers. Other tested ARM architectures work with that configuration, only Cortex M3 has a problem with it.

@teburd
Copy link
Collaborator

teburd commented Nov 3, 2023

This is an interesting failure "Illegal use of the EPSR" https://github.com/zephyrproject-rtos/zephyr/actions/runs/6665109962/job/18114283475?pr=62433 @teburd any ideas?

No ideas from me no, I can try and take a look at this closer today. There's another issue on cortex-m7 as well with dcache involved.

Maybe alignment related?

It might be worth trying to break this PR up a bit into some small PRs that get merged incrementally. PLT/GOT support with -fPIC, xtensa support, and maybe lastly the peek + copy-free usage perhaps?

@lyakh
Copy link
Collaborator Author

lyakh commented Nov 6, 2023

It might be worth trying to break this PR up a bit into some small PRs that get merged incrementally. PLT/GOT support with -fPIC, xtensa support, and maybe lastly the peek + copy-free usage perhaps?

@teburd can we do it in a different order - first add llext_peek() and then add PLT? I'd prefer to add Xtensa support on top of a peek-enabled implementation directly?

@lyakh lyakh force-pushed the ldlib-wip branch 2 times, most recently from 7d8ce76 to 36a50b9 Compare November 9, 2023 16:40
@cfriedt
Copy link
Member

cfriedt commented Nov 29, 2023

None on my end, but there may be a couple of still relevant compliance issues. Likely the EXPORT_SYMBOL() warnings can be ignored.

Add support for running a modular "Hello world" example on Xtensa.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Loadable modules can contain global (not "static") functions, even if
they aren't exported for use by other modules, e.g. when a module is
built from multiple .c files. Such functions are then also included
in link tables and have to be re-linked.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extend the llext_load() / llext_unload() API to let it be called
repeatedly for the same extension to increment or decrement its
reference counter respectively. We use a mutex to protect the counter
and make both llext_load() and llext_unload() return the use-count to
let the caller identify when the first loading and the last unloading
took place.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
If a function fails it should release all the resources it has
managed to acquire. Fix llext_load() to free memory that it has
allocated in case of an error.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extensions should be able to selectively export their global symbols.
Add a LL_EXTENSION_SYMBOL() macro for that. Change the present
.sym_tab to be a temporary symbol table of all global symbols in an
extensions, used only during linking for internal purposes. Add a new
.exp_tab symbol table to store symbols, exported by an extension
permanently.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Use an element size explicitly when calculating the array size and
use the calculated size for memset().

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
The llext list should be internal to llext.c, remove its scanning
from shell.c, export a function for that instead.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
llext_list() is an exported function that returns a pointer to the
llext internal extension list. That list should only be accessible
directly inside llext, while holding a lock. Remove the function.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
a new llext object is completely initialised with zeros after
allocation, no need to additionally set members of an embedded into
it array to NULL.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Use an existing mutex to also protect the global llext list.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
When using the LLEXT buffer loader we now avoid copying extensions
from storage to allocated memory by pointing directly into the stored
image. We then also perform linking and relocation in that memory,
which modifies its contents. However, this is impossible if that
storage is read-only. Add a Kconfig flag to distinguish between
writable and read-only storage types. Also use that flag to decide,
whether the extension image in test_llext_simple.c should be defined
as const or not.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
@lyakh
Copy link
Collaborator Author

lyakh commented Nov 29, 2023

None on my end, but there may be a couple of still relevant compliance issues. Likely the EXPORT_SYMBOL() warnings can be ignored.

@cfriedt I cleaned up a couple of checkpatch / compliance failures, the rest are false positives: EXPORT_SYMBOL() in a separate file unlike Linux kernel, and a const array that has no need to be static. If you have no further objections, maybe you could drop your request for change as fulfilled.

@cfriedt cfriedt self-requested a review November 29, 2023 16:51
@cfriedt cfriedt dismissed their stale review November 29, 2023 16:52

I'm not blocking anymore

lyakh added a commit to lyakh/sof that referenced this pull request Nov 30, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
@lyakh
Copy link
Collaborator Author

lyakh commented Dec 1, 2023

@nashif @teburd @pillo79 status update: only EXPORT_SYMBOL() checkpatch complaints remaining, CI clean otherwise

@pillo79 pillo79 self-requested a review December 1, 2023 10:33
lyakh added a commit to lyakh/sof that referenced this pull request Dec 1, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Copy link
Collaborator

@teburd teburd left a comment

Choose a reason for hiding this comment

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

We might need a few CI checks fixed, let me look, but approved

@nashif
Copy link
Member

nashif commented Dec 1, 2023

overriding checkpatch as false negatives.

@nashif nashif merged commit dbea13a into zephyrproject-rtos:main Dec 1, 2023
24 of 25 checks passed
@lyakh lyakh deleted the ldlib-wip branch December 1, 2023 15:35
lyakh added a commit to lyakh/sof that referenced this pull request Dec 5, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433 is
the counterpart to this work.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
lyakh added a commit to lyakh/sof that referenced this pull request Dec 6, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433
introduced updates, needed for SOF, update to a version, containing
it.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
lyakh added a commit to lyakh/sof that referenced this pull request Dec 8, 2023
Zephyr PR zephyrproject-rtos/zephyr#62433
introduced updates, needed for SOF, update to a version, containing
it.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
@henrikbrixandersen henrikbrixandersen added the area: llext Linkable Loadable Extensions label Jul 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Base OS Base OS Library (lib/os) area: C Library C Standard Library area: Kernel area: llext Linkable Loadable Extensions area: Logging area: Xtensa Xtensa Architecture platform: Intel ADSP Intel Audio platforms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants