Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introducing relocatable library loading
* Introducing relocatable library loading Using an relocatable elf loader, patches and modules can be loaded to arbitrary memory locations. Position-independent ELFs are not supported. This enables running multiple patches simultaneously. Referencing dynamic loading libraries is not possible with relocatable libraries. So a mechanism was needed to locate a library providing a missing symbol. The approach taken is prefixing exported symbols with the library name and one underscore. So loading a dynamic library containing an unreferenced symbol `lib1_factory` causes the loader to load `/lib/lib1.elf` and look inside for the symbol `lib1_facory`. This does not work for C++ function names as they are mangled. Prefixing a function name in C++ does not prefix the corresponding symbol name. So in order to use C++ function in dynamic loaded libraries, an `extern "C"` declaration is required. Exported classes need to be pure virtual. Uploading a patch into flash does not include any referenced dynamic libraries, so an sdcard will be required for those cases. * No more hard-linking Patches used to hard-link with the firmware. That broke patches when the firmware is changed, those had to be compiled again. Now patches only link to API symbols, those have a longer lifetime. * Introducing separation between firmware and API Every symbol in firmware was exposed to patches. Now there is a separate `api` directory containing declarations that can be used in patches. * Dynamic memory allocation Patch memory usage was statically allocated, the benefit is that if a patch compiles, it 'd be certain to execute too. Now patches that occupy more memory than is available will only fail during loading. * Memory fragmentation It is possible to load patch A and then patch B. But when patch A is stopped and patch C is started, it is possible that there is not enough continuous space for patch C, even when patch B and C could run simultaneously. The best approach is to stop patch B too when patch A is stopped. This is currently not enforced. The alternative approach (not implemented) is to partition memory into segments so that a certain fixed number of patches can always run. But that 'd prevent one patch to use more memory than a quarter if the partitioning is for four patches. The memory fragmentation problem can be mitigated by modifying objects that 'd allocate a significant percentage of continuous memory (say, 4MB of sdram) into objects that allocate multiple blocks (say, 16 blocks of 256KB each). * Patches used to run with a subdirectory as its working directory This conflicts with the possibility of running multiple patches run simultaneously, so this is no longer the case. Absolute filenames are strongly recommended now. * GPIO pin modes GPIO pin modes were reset when a patch is loaded. This conflicts with running multiple patches, and no longer the case. It is the sole responsibility of objects to restore their configuration when disposed. * USB protocol Cleaned up, incompatible with previous experimental releases. Automatic upgrading from release 1.0.12 and downgrading to 1.0.12 is supported. * Mutable instruments' objects Moved out of firmware, currently broken, need to be re-implemented as dynamic libraries. * Removed "Controller objects" Controller objects were conceived to integrate a patch loading scheme in every other patch. Since multiple patches can load, one "master" patch can load other patches (perhaps responding to midi program changes). Examples are yet to be made.
- Loading branch information