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
Dynamic Module Loading #2746
Comments
I wonder if there is any plan to support it in future roadmap? |
I am too |
Adding the ability to dynamically allocate stack should be relatively easy at this point. As for memory space, with MMU, each module can be assigned a virtual memory region. At runtime, the MMU takes care of the mapping. Without MMU, it is going to be tricky. |
In the old version of contiki-ng, an elf loader is included. The version after contiki-ng 4.0 does not seem to be supported anymore. |
I think it would be good to explain the use cases a bit more. For example do you need to unload the module and load other modules? Do you need to load more than one module? There could be some simplifying assumptions that we could make vs having a general module loader. |
I have always wanted to use PIE/PIC (Position Independent Executable / Position independent code) with microcontrollers. My initial use case for dynamic linking as a POC would be to create a sort of 3rd stage bootloader that can manage flash partitions, link, and launch generically formatted firmware images. |
@attzonko how much portability of "modules" is needed? would there need to be ability to build a module that could run against any zephyr build? |
I tried doing something similar a few weeks ago. In my case, I wanted a way to run "scripts" on a running MCU - that is, to reserve a buffer in RAM for the code and data, write some code, compile it, send it to the MCU in some way (e.g. UDP) and receive the result of running that code. I did it mostly for ease of development - If I want to experiment with something (e.g. I'm writing a driver for a new device), I can write code and load it, without having to recompile and reflash everything. Similar to experimenting with IPython before writing actual code. (This could also be taken further, to implement a REPL on the MCU).
|
Let me add one point: |
Would using wasm help in any way? https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/build_wamr.md |
hi @dcpleung when I load a module into memory, how do I allocate a memory space for those platforms without MMU? |
Probably would need to implement some advanced dynamic memory allocation service? |
One way to do this is to dedicate the free memory into a mem_slab and allocate blocks from there. |
if we plan to use mem_slab, then I think all platforms could support it, needn't to care about MMU. |
FYI I managed to implement dynamic loading (very similar to |
@paulrouget nice! Any sample code you can share? |
hi all, I tried to implement a draft PR #41700 for this, could you help review it and give some suggestions, about the feature requirements or technical details, all are welcome, thanks. |
Hi - Some thoughts on (initial) use cases and feature requirements. They assume base kernel/system is non-PIC. Use cases - leverage dynamic module to implement
Requirements
Note: This likely needs to be broken up into several features. |
Hi all,
|
So after read all above, does this RTOS has any plan actually is on-going for this features "dynamic elf module loader"? Thanks. It is really usefual for smart-watch & smart-home IoT device, which needs to update firmware functionality from time-to-time.. |
In case you will support this, there is good starting point from here (ARM) https://github.com/bogdanm/udynlink Dynamic loading for MCUs requires some scripting to generate the modules with PIE (e.g. a custom image header + binary data). In addition other questions to be thought of are, would they be run as kernel modules or user applications (i.e. non-priviledge/ privileged-mode). If the modules need access to the zephyr api, all the symbols that the "module" can access need to be defined and linked at run-time. Also if the modules access the zephyr api you would probably need to define which version of the API it uses as function prototypes might change and can create undefined behaviour if modules call API from distinct versions. However, if the modules are intended just for algorithms without access to any type of API then it would be simpler. Oh and lets not forget about debugging our dynamic "modules". You would need a python GDB script to load the correct debugging files (DWARF) automatically so you could access the external modules while debugging. My personal opinion: Im not sure how this would scale as Zephyr supports more architectures. Im sure you would need to write assembly for each port (ARM, xtensa, risc) to load correctly the modules. And then the modules would need to be compiled depending on the architecture they are going to be loaded to (perhaps some metadata + crc + signature). Just my 2 cents on somewhat my experience with ARM dynamic loading. |
PIC (Position Independent Executable / Position independent code) |
I intend on taking this on and continuing the great work started by @chen-png |
I think this would still be highly useful even if it only supported one or two platforms, since right now, this kind of functionality isn't really available on MCUs at all. I'm actually not even sure position independent code is needed at all, everything could be done with a configurable fixed number of "Slots". Imagine you wanted to make a game console. You would just need 2 slots, the main one that could either be a launcher, or a complete game(I'm assuming there would be a way for a program to ask the OS to replace it with another file), and a supervisory slot that one could use to return to the main menu or handle any other tasks that had to be always on. Even the supervisory slot could be just built into the firmware. Or, suppose one wanted to make a smart outlet. You'd probably just need the main "App" that talks to the smart platform, that you'd probably want to be able to switch out to avoid obsolescence, and maybe one extra accessory app to add some fancy extra timing thing. Even if there was only one module you could load at a time it would still be rather useful for a large number of tasks, because you could just put everything you want to do right into that module. Imagine if it was as easy as making an Arduino sketch and exporting as a module file you could save on an SD card! |
So today I finally got back to this idea and got a POC working. In my application, I have a large buffer
This can be seen as a RAM function that is linked separately from the rest of the application. It works nicely as a POC, but it's a bit problematic:
On the other hand, it works, and it has a very small overhead - no dynamic loading and linking is needed. This is very useful for constrained devices. |
For the security and safety aspects, would it be possible to scan the code during the compile/link phases to e.g. assign a security class and then define a signing mechanism that the running host could verify and decide if wants to load it? A while back I saw a paper that uses indirection pointers instead of direct jumps. Idea is that instead of deciding |
@yonsch sure, it would be great to see how your POC works, even if not ready for merging; securing the environment will obvious take a bunch more work, but it's possible to foresee a "loader" that checks code signatures etc. before executing any code. |
Nice discussions and some initial results as well. I was here to look if OpenCV models can be loaded to tiny MCU platforms. Cause this model is big in size, could be that dynamic linking can reduce the overall size. |
MMU is not needed. Without MMU these will have to be compiled as position independent code that never uses absolute references and can be placed anywhere in the physical ram. It just needs to be linked at runtime to kernel symbols. |
Very nice. Can you link to code? Regarding your concerns, unfortunately without memory manager in hardware it is not possible to achieve complete isolation. This is the benefit of MMU. On the other hand, all code running on a system with raw physical memory should be trusted code. You may as well write that code into external flash and then execute in place (xip). I would very much like to see your solution and see if it can be adopted for such use case. |
@teburd let's close this as done. |
If anyone is looking for a |
Just for your info @kinsamanka , they already implemented a dynamic module in subsys as llext https://docs.zephyrproject.org/latest/services/llext/index.html#linkable-loadable-extensions-llext regards |
Reported by XiaoHua Yang:
As a user, I hope zephyr support dynamic loading and linking of modules at run-time. This is useful in applications in which the behavior is intended to be changed after deployment. The module loader can load, relocate, and link standard ELF files that can optionally be stripped off their debugging symbols to keep their size down.
(Imported from Jira ZEP-1264)
The text was updated successfully, but these errors were encountered: