diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d748df..4f005ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,24 @@ else() message(STATUS "No user data file provided (USER_DATA_FILE not set or file doesn't exist)") endif() +# Embed modules.dmp if it exists after build +# Note: modules.dmp is created during build, not configuration, so we check for it at build time +set(MODULES_DMP_FILE "${CMAKE_BINARY_DIR}/modules.dmp") +set(MODULES_DMP_OBJECT "${CMAKE_BINARY_DIR}/__modules_dmp.o") + +# Create a custom command that will conditionally embed modules.dmp +add_custom_command( + OUTPUT "${MODULES_DMP_OBJECT}" + COMMAND ${CMAKE_COMMAND} -E echo "Checking for modules.dmp..." + COMMAND bash -c "if [ -f ${MODULES_DMP_FILE} ]; then echo 'Embedding modules.dmp'; ${CMAKE_OBJCOPY} --input-target=binary --output-target=elf32-littlearm --binary-architecture=arm --rename-section .data=.embedded.modules_dmp,alloc,load,readonly,data,contents ${MODULES_DMP_FILE} ${MODULES_DMP_OBJECT}; else echo 'No modules.dmp found, creating empty object'; ${CMAKE_OBJCOPY} --input-target=binary --output-target=elf32-littlearm --binary-architecture=arm --rename-section .data=.embedded.modules_dmp,alloc,load,readonly,data,contents /dev/null ${MODULES_DMP_OBJECT}; fi" + DEPENDS prepare_modules_dmp + COMMENT "Conditionally embedding modules.dmp if it exists" + VERBATIM +) + +list(APPEND EMBEDDED_OBJECTS "${MODULES_DMP_OBJECT}") +message(STATUS "modules.dmp will be conditionally embedded if created during build") + # ====================================================================== # dmod-boot application # ====================================================================== diff --git a/README.md b/README.md index 6c8f126..805e96a 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,9 @@ cmake --build build - `USER_DATA_FILE` (optional) - Path to a user data file that will be embedded in ROM, with its address and size available via environment variables `USER_DATA_ADDR` and `USER_DATA_SIZE` - `DMBOOT_EMULATION` (optional) - Enable Renode simulation mode instead of hardware mode +**Automatic Build-Time Embedding:** +- `modules.dmp` - Automatically created and embedded during build if modules are specified in `modules/modules.dmd`. This file is loaded before `startup.dmp` at boot time. If no modules are defined, the file won't exist, which is not an error. + All parameters are optional. If not specified, the build will proceed with default settings. ## CMake Targets diff --git a/docs/rom-embedding.md b/docs/rom-embedding.md index 955914c..f6798fb 100644 --- a/docs/rom-embedding.md +++ b/docs/rom-embedding.md @@ -16,12 +16,20 @@ DMOD Boot supports embedding binary files into ROM at build time. This allows yo - Size available as `USER_DATA_SIZE` environment variable - Can contain configuration, assets, or any custom data +3. **`modules.dmp`** (automatic, build-time generated) - A DMOD package file containing modules from the `modules/` directory + - Automatically created during the build process if modules are specified in `modules/modules.dmd` + - Loaded before `startup.dmp` during boot + - If no modules are defined, the file won't exist, which is not an error + - Can contain library modules to be enabled or application modules to be run + ## How It Works When DMOD Boot starts: -1. It checks if a `startup.dmp` package is embedded in ROM -2. If present, the package is automatically loaded using `Dmod_Load()` and its main module (if specified) is executed -3. User data (if embedded) has its location made available through environment variables for your modules to access +1. It checks if a `modules.dmp` package is embedded in ROM +2. If present, the package is automatically loaded using `Dmod_Load()` and enabled (for library modules) or run (for application modules) +3. It checks if a `startup.dmp` package is embedded in ROM +4. If present, the package is automatically loaded using `Dmod_Load()` and its main module (if specified) is executed +5. User data (if embedded) has its location made available through environment variables for your modules to access ## Building with Embedded Files @@ -128,6 +136,9 @@ if (dmenv_geti(env, "USER_DATA_ADDR", &user_data_addr)) { After building, you can verify that files were properly embedded by checking the map file: ```bash +# Check for modules.dmp symbols +grep "__modules_dmp" build/dmboot.map + # Check for startup.dmp symbols grep "__startup_dmp" build/dmboot.map @@ -135,4 +146,4 @@ grep "__startup_dmp" build/dmboot.map grep "__user_data" build/dmboot.map ``` -Both should show the start, end, and size symbols with their addresses. +All should show the start, end, and size symbols with their addresses. Note that `modules.dmp` symbols will always be present, but may show zero size if no modules were defined. diff --git a/lib/dmheap b/lib/dmheap index 61b78b4..b052298 160000 --- a/lib/dmheap +++ b/lib/dmheap @@ -1 +1 @@ -Subproject commit 61b78b4abd117b30374f55e8fa4d231caa55d100 +Subproject commit b052298dfa6ec1cf032d26840c18f3c693c6df66 diff --git a/lib/dmlog b/lib/dmlog index 3cf83ee..17281e2 160000 --- a/lib/dmlog +++ b/lib/dmlog @@ -1 +1 @@ -Subproject commit 3cf83ee8de1c5e64250ca4d5ec42ff2c4c9f09f9 +Subproject commit 17281e2ca690b54865922468b6857430235784eb diff --git a/lib/dmod b/lib/dmod index 811a16f..2ee3e0b 160000 --- a/lib/dmod +++ b/lib/dmod @@ -1 +1 @@ -Subproject commit 811a16fc8ac000e2af17ad404e2456afa06b89e8 +Subproject commit 2ee3e0b6e9723747f78a44dbd716e032db8e8390 diff --git a/linker/common.ld b/linker/common.ld index 71e5ac6..3fdfea8 100644 --- a/linker/common.ld +++ b/linker/common.ld @@ -101,6 +101,18 @@ SECTIONS PROVIDE(__user_data_size = __user_data_end - __user_data_start); } > rom AT > rom + . = ALIGN(16); + .embedded.modules_dmp : + { + __modules_dmp_start = .; + PROVIDE(__modules_dmp_start = .); + KEEP(*(.embedded.modules_dmp)) + __modules_dmp_end = .; + PROVIDE(__modules_dmp_end = .); + __modules_dmp_size = __modules_dmp_end - __modules_dmp_start; + PROVIDE(__modules_dmp_size = __modules_dmp_end - __modules_dmp_start); + } > rom AT > rom + . = ALIGN(4); __exidx_start__ = .; PROVIDE(__exidx_start__ = __exidx_start__); diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 2d80fbd..fabba55 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -14,7 +14,7 @@ if(EXISTS "${DMBOOT_MODULES_DMD}") OUTPUT "${DMBOOT_MODULES_MARKER_FILE}" COMMAND ${CMAKE_COMMAND} -E make_directory "${DMBOOT_MODULES_OUT_DIR}" COMMAND ${CMAKE_COMMAND} -E echo "Downloading modules to ${DMBOOT_MODULES_OUT_DIR}..." - COMMAND ${DMF_GET} -d "${DMBOOT_MODULES_DMD}" -o "${DMBOOT_MODULES_OUT_DIR}" -t "${DMOD_TOOLS_NAME}" --type dmfc + COMMAND ${DMF_GET} -d "${DMBOOT_MODULES_DMD}" -o "${DMBOOT_MODULES_OUT_DIR}" -t "${DMOD_TOOLS_NAME}" --type dmf COMMAND ${CMAKE_COMMAND} -E touch "${DMBOOT_MODULES_MARKER_FILE}" DEPENDS "${DMBOOT_MODULES_DMD}" COMMENT "Downloading modules specified in ${DMBOOT_MODULES_DMD} from DMD..." @@ -44,7 +44,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E echo "Checking if modules directory contains files..." COMMAND ${CMAKE_COMMAND} -E echo "Contents of ${DMBOOT_MODULES_OUT_DIR}:" COMMAND ls -la ${DMBOOT_MODULES_OUT_DIR} || ${CMAKE_COMMAND} -E echo "Directory is empty or does not exist" - COMMAND bash -c "if ls ${DMBOOT_MODULES_OUT_DIR}/*.dmfc 1> /dev/null 2>&1; then ${TODMP} modules ${DMBOOT_MODULES_OUT_DIR} ${DMBOOT_MODULES_DMP}; ls ${DMBOOT_MODULES_OUT_DIR}/*.dmfc; else echo 'No .dmfc files found'; fi" + COMMAND bash -c "if ls ${DMBOOT_MODULES_OUT_DIR}/*.dmf 1> /dev/null 2>&1; then ${TODMP} modules ${DMBOOT_MODULES_OUT_DIR} ${DMBOOT_MODULES_DMP}; ls ${DMBOOT_MODULES_OUT_DIR}/*.dmf; else echo 'No .dmf files found'; fi" DEPENDS download_modules COMMENT "Creating modules dmp file from modules (if any exist)..." VERBATIM diff --git a/modules/modules.dmd b/modules/modules.dmd index 8cdbc65..b781f1d 100644 --- a/modules/modules.dmd +++ b/modules/modules.dmd @@ -1,4 +1,4 @@ # # File with list of modules to load # -dmffs@1.1 \ No newline at end of file +dmffs \ No newline at end of file diff --git a/src/main.c b/src/main.c index 3757f5c..d1c28c7 100644 --- a/src/main.c +++ b/src/main.c @@ -17,6 +17,9 @@ extern void* __startup_dmp_size; extern void* __user_data_start; extern void* __user_data_end; extern void* __user_data_size; +extern void* __modules_dmp_start; +extern void* __modules_dmp_end; +extern void* __modules_dmp_size; void delay(int cycles) { @@ -186,6 +189,57 @@ static bool prepare_argv_for_run(const char* input, char*** argv_out, int* argc_ return true; } +static void load_embedded_modules_dmp(void) +{ + void* modules_dmp_start = &__modules_dmp_start; + void* modules_dmp_end = &__modules_dmp_end; + size_t modules_dmp_size = (size_t)((uintptr_t)modules_dmp_end - (uintptr_t)modules_dmp_start); + if(modules_dmp_size > 0) + { + DMOD_LOG_INFO("Loading modules.dmp from ROM: addr=0x%X, size=%u bytes\n", + (uintptr_t)modules_dmp_start, (unsigned int)modules_dmp_size); + + Dmod_Context_t* modules_ctx = Dmod_Load(modules_dmp_start, modules_dmp_size); + if(modules_ctx != NULL) + { + DMOD_LOG_INFO("Modules package loaded successfully\n"); + + // Check module type and handle accordingly + Dmod_ModuleType_t moduleType = Dmod_GetModuleType( modules_ctx ); + if( moduleType == Dmod_ModuleType_Library ) + { + if( !Dmod_Enable( modules_ctx, false, NULL ) ) + { + DMOD_LOG_ERROR("Failed to enable modules library\n"); + } + } + else if( moduleType == Dmod_ModuleType_Application ) + { + DMOD_LOG_INFO("Modules module is an application module\n"); + char argv0[] = "modules.dmp"; + char* argv[] = { argv0 }; + int argc = 1; + if( Dmod_Run(modules_ctx, argc, argv) != 0 ) + { + DMOD_LOG_ERROR("Failed to run modules application\n"); + } + } + else + { + DMOD_LOG_ERROR("Modules module has unknown module type: %d\n", moduleType); + } + } + else + { + DMOD_LOG_ERROR("Failed to load modules.dmp package\n"); + } + } + else + { + DMOD_LOG_INFO("No modules.dmp embedded in ROM\n"); + } +} + static void setup_embedded_user_data(dmenv_ctx_t dmenv_ctx) { void* user_data_start = &__user_data_start; @@ -208,6 +262,7 @@ static void setup_embedded_user_data(dmenv_ctx_t dmenv_ctx) int main(int argc, char** argv) { + Dmod_SetLogLevel(Dmod_LogLevel_Verbose); void* logs_start = &__logs_start__; void* logs_end = &__logs_end__; dmlog_index_t logs_size = (dmlog_index_t)((uintptr_t)logs_end - (uintptr_t)logs_start); @@ -261,6 +316,9 @@ int main(int argc, char** argv) // Set user_data environment variables if embedded in ROM setup_embedded_user_data(dmenv_ctx); + // Load modules.dmp if embedded in ROM + load_embedded_modules_dmp(); + // Load startup.dmp if embedded in ROM load_embedded_startup_dmp();