- Notifications
You must be signed in to change notification settings - Fork13
Dynamically load apps to zephyr RTOS
License
rgujju/Dynamic_App_Loading
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Minimal example of dynamic apps for Cortex-M
Doxygen docs »
This is a minimal example of having dynamic apps with syscall functionality. It is divided into 2 parts, the kerneland the app. The kernel is responsible for loading the app and handling syscall functionality. The syscall functionalityis implemented usingzephyr syscalls.
At the moment the kernel is nothing but zephyr and 2 functions, theSetLed andLoadApp.The syscall functionality is implemented in themodules/sys_module while the app loading is implemented in themodules/app_loader.
The kernel contains the actual implementation ofSetLed, This code does not get compiled into the app again. So this APIcan be changed without needing to rebuild the app.
There are some changes required in zephyr to support this. Have a look at [zephyr changes](#Changes required in zephyr) and a diffhere
The app is compiled as a Position independent Code.The following flags are used:-fpic -msingle-pic-base -mpic-register=r9 -mno-pic-data-is-text-relative -mlong-calls.This creates an executable which can be run from any memory location given that the GOT address is in the registerR9.This value is given as a parameter while calling the app, so this gets placed inR0.TheAppStart function defined inapp_startup.s is used to copy the value fromR0 toR9. This function contains thefirst instruction that gets executed when the app is started. Followed by themain function defined in app. This sequence isdefined using the app linker scriptapp_base.ld.
gcc generates the executable in elf which contains a lot of information and is quite large for a mcu. So this elf file isconverted intoTINF, which can be easily loaded onto a mcu.
The current example app blinky inapps/blinky turns on the green LED while the kernel turns on the red LED on the STM32F429i-DISC1 board.But should be able to port to any arm cortex m board.
To learn more about GOT and PIC refer theAcknowledgements, they do a much better job of explaining the concepts.
Mainly to learn about the GOT, PIC, memory layout of mcu, elf format, and a lot more.Gained a lot of knowledge from this project.
This example is for the STM32F429i DISC1 board. But should beportable to any other mcu.
1 Build libsys_module.a. This is a static library aka archive. The app will be linked to this archive.
cd kernelmkdir buildcd buildcmake .. -DBOARD=stm32f429i_disc1 -DUSERLIB=1make userlib
A folder calleduserlib will be created. This folder will contain everything required to build the app.
It contains the header and archive files.
Copy this folder to the apps folder.cp -R userlib ../../apps/
This app turns on LED1. There is some extra code in the example to purposely populate the data and bss sections
And also to verify if the GOT is copied properly. ie global variable access.cd apps/blinkymkdir build/cd buildcmake ..make
This will createblinky.elf file. This file now needs to be converted into TINF.
python3 ../../../elf2tinf/elf2tinf.py --major 1 --minor 0 blinky.elf blinky
This will generate 2 files, theblinky.tinf andblinky_tinf.h
blink.tinf is in a binary format which can be loaded over uart, ble, usb, etc.
blinky_tinf.h is the same binary data in the form of a header file, so the app can be tested easily, bycompiling into the kernel, without implementing the actual transfer of the binary to the mcu.
More details about this tool is in the README.md in folder elf2tinf
Copy theblinky_tinf file to the kernel include folder.cp -rf blinky_tinf.h ../../../kernel/include
cd kernel/build
Build the kernel, this is the code that will actually load the app and run itcmake .. -DBOARD=stm32f429i_disc1 -DUSERLIB=0make clean Need to clean the build files of the userlib.makeThis will generate themain.elf file which needs to be loaded onto the board.
This can vary depending on your method. but if zephyr flash method works for you then simplymake flash
User documentation is in header files
To go deeper see the source files
Online docs:https://rgujju.github.io/Dynamic_App_Loading/html/index.html
- This project uses the STM32F429 mcu but should be portable to any mcu.
- Zephyr makes porting extremely easy. Simply change the
-DBOARDparam given to cmake to match your board - Modify theapps/blinky/CMakeLists.txt mainly theMCU andMCU_SPEC
- To port to other architecture need to modify how the GOT base address is passed to the app
- Cannot reset thread stack to 0x00 while entering userpsace
- Statically allocated stack.
- No stack overflow detection yet
Have a look at the diffhere
Allocate space in the userspace thread stack for GOT, bss and data section of dynamic app. Right now I am just notresetting the thread stack to 0 or 0xaaaaaaaa while entering userspace so that it does not overwrite these sections.
The thread stack is statically allocated due to limiations in zephyr heap allocator. The current heap implementationcannot allocate stack which is aligned properly according to MPU
Do not compile syscall APIs as static inline while building userlib, and set
CONFIG_USERLIB=1and__ZEPHYR_USER__=1CONFIG_USERLIB=1is used to remove thestatic inlinefrom the syscall declaration so that the API is exported.__ZEPHYR_USER__=1is used to compile only the userspace version of the syscall- The modified api definition is formed as follows
externint8_tz_impl_some_api(uint8_ta,uint8_tb);#ifndefCONFIG_USERLIBstaticinline#endifint8_tsome_api(uint8_ta,uint8_tb){#ifdefCONFIG_USERSPACEif (z_syscall_trap()) {return (int8_t)arch_syscall_invoke2(*(uintptr_t*)&Led_Num,*(uintptr_t*)&Led_State,K_SYSCALL_SETLED);}#endifcompiler_barrier();returnz_impl_SetLed(Led_Num,Led_State);}
- The source of the C files not to be compiled in the userlib must be inside
#ifndef CONFIG_USERLIB .. #endif - Only the generated syscall header files and its dependent header filesare required in the userlib so a typical module can be compiled as follows
module_name.c
#include<zephyr.h>#include<device.h>#include"<module_name>.h"#ifndefCONFIG_USERLIBint8_tz_impl_some_api(uint8_ta,uint8_tb){ ...}int8_tz_vrfy_some_api(uint8_ta,uint8_tb){}#include<syscalls/some_api_mrsh.c>#endif/*CONFIG_USERLIB*/
module_name.h
#ifndefCONFIG_USERLIB_syscallint8_tsome_api(uint8_ta,uint8_tb);#endif# The source for jumping to the syscall willgetincludedfromhere#include<syscalls/module_name.h>
- Should be able to just add
#include <syscalls/file_name.h>along with dependencies to include the APIs from that file.
Following resources helped me:
- https://github.com/bogdanm/udynlink
- https://github.com/pebble-dev/RebbleOS/blob/master/rcore/appmanager.c
- https://dl.acm.org/doi/abs/10.1145/1067170.1067188
- https://github.com/tock/tock
- https://www.airs.com/blog/archives/38
- 40 part explaination about linkers
- https://www.technovelty.org/linux/plt-and-got-the-key-to-code-sharing-and-dynamic-libraries.html
- Explains PLT and GOT
- https://stackoverflow.com/questions/3322911/what-do-linkers-do/33690144#33690144
- Explains relocation with a proper worked out example
- https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031#51308031
- Explains PIE relocation with a proper worked out example
- https://stac47.github.io/c/relocation/elf/tutorial/2018/03/01/understanding-relocation-elf.html
- worked out example of relocation in dynamic and static linking
- Dynamic linking
- load time relocation
- https://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries
- https://www.youtube.com/watch?v=wYmhUbhkbhQ-Demonstrates load time relocation
- PIC - Position Independent code
- For Cortex-M
- https://stackoverflow.com/questions/5619178/how-to-write-dynamic-loader-for-bare-metal-arm-application
- Explains how to do jump tables (jumptables) using C struct
- https://stackoverflow.com/questions/50655162/stm32-position-independent-binaries
- Position independent code
- https://github.com/embedded2014/elf-loader
- https://github.com/martinribelotta/elfloader
- ELF Loader
- http://www.chibios.com/forum/viewtopic.php?f=3&t=1229
- partial linking and comparison of different dynamic loading options
- https://stackoverflow.com/questions/44632383/dynamically-load-code-on-embedded-target
- Shows partial linking
- In the ld documentation check out --relocatable and --just-symbols
- https://static.docs.arm.com/ihi0044/f/IHI0044F_aaelf.pdf
- ARM ELF Format
- https://stackoverflow.com/questions/5619178/how-to-write-dynamic-loader-for-bare-metal-arm-application
- load time relocation
About
Dynamically load apps to zephyr RTOS
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.