Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
# ======================================================================
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 15 additions & 4 deletions docs/rom-embedding.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -128,11 +136,14 @@ 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

# Check for user_data symbols
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.
2 changes: 1 addition & 1 deletion lib/dmheap
2 changes: 1 addition & 1 deletion lib/dmlog
12 changes: 12 additions & 0 deletions linker/common.ld
Original file line number Diff line number Diff line change
Expand Up @@ -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__);
Expand Down
4 changes: 2 additions & 2 deletions modules/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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..."
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion modules/modules.dmd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#
# File with list of modules to load
#
dmffs@1.1
dmffs
58 changes: 58 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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();

Expand Down