Implementing the Dynamic Application Loader
The Tock kernel supports an optional dynamic application loader component that allows an external application to store and execute new applications.
Dynamic application loading uses the app_loader capsule. This will setup the
bridge between the userspace application and the kernel for loading new
applications. The app_loader capsule requires a dynamic_binary_storage
driver to store and load the application, so we need to set that up as well.
Configuring the Kernel
We will use components to add app_loader to the kernel. We will also set up
some syscall driver types to make it portable across different hardware. To add
the proper drivers, include this in the top-level board main.rs file:
Add required components
#![allow(unused)] fn main() { //-------------------------------------------------------------------------- // Syscall Driver Type Definitions //-------------------------------------------------------------------------- type FlashUser = nrf52840::nvmc::Nvmc; type NonVolatilePages = components::dynamic_binary_storage::NVPages<FlashUser>; type DynamicBinaryStorage<'a> = kernel::dynamic_binary_storage::SequentialDynamicBinaryStorage< 'static, 'static, nrf52840::chip::NRF52<'a, Nrf52840DefaultPeripherals<'a>>, kernel::process::ProcessStandardDebugFull, NonVolatilePages, >; type AppLoaderDriver = capsules_extra::app_loader::AppLoader< DynamicBinaryStorage<'static>, DynamicBinaryStorage<'static>, >; //-------------------------------------------------------------------------- // Dynamic App Loading //-------------------------------------------------------------------------- // Create the dynamic binary flasher. let dynamic_binary_storage = components::dynamic_binary_storage::SequentialBinaryStorageComponent::new( virtual_flash_dbs, loader, ) .finalize(components::sequential_binary_storage_component_static!( FlashUser, nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>, kernel::process::ProcessStandardDebugFull, )); // Create the dynamic app loader capsule. let dynamic_app_loader = components::app_loader::AppLoaderComponent::new( board_kernel, capsules_extra::app_loader::DRIVER_NUM, dynamic_binary_storage, dynamic_binary_storage, ) .finalize(components::app_loader_component_static!( DynamicBinaryStorage<'static>, DynamicBinaryStorage<'static>, )); }
Note:
- The definition of the
FlashUsertype is hardware dependent.- If there are other applications that use the
IsolatedNonvolatileStoragecapsule, we have to virtualize the flash. In that case, theFlashUsertype will look something like:#![allow(unused)] fn main() { type FlashUser = capsules_core::virtualizers::virtual_flash::FlashUser<'static, nrf52840::nvmc::Nvmc>; }and then we pass the virtual flash instance to the
dynamic_binary_storageinstance.
Update the Platform definition
The Platform struct defines all of the features supported by a Tock platform.
For the app_loader to be usable, we need to add a reference to the capsule to
the Platform struct:
#![allow(unused)] fn main() { pub struct Platform { ... dynamic_app_loader: &'static AppLoaderDriver, ... } let platform = Platform { ... dynamic_app_loader, ... }; }
And make it accessible to userspace by adding to the with_driver function:
#![allow(unused)] fn main() { impl SyscallDriverLookup for Platform { fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R where F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, { match driver_num { ... capsules_extra::app_loader::DRIVER_NUM => f(Some(self.dynamic_app_loader)), ... } } } }