[sw,otbn] Adjust loaders to properly handle OTBN's new bss section.
This change adjusts the OTBN build script to categorize the .bss section
as .bss rather than .rodata for .rv32embed.o files, which means it is no
longer guaranteed that DMEM regions are continuous in memory. The
loaders are then adjusted to handle the two separate sections.
Signed-off-by: Jade Philipoom <jadep@google.com>
diff --git a/hw/ip/otbn/data/otbn.ld.tpl b/hw/ip/otbn/data/otbn.ld.tpl
index cf7853d..cac97f7 100644
--- a/hw/ip/otbn/data/otbn.ld.tpl
+++ b/hw/ip/otbn/data/otbn.ld.tpl
@@ -48,27 +48,29 @@
.data ORIGIN(dmem) : ALIGN(32)
{
- _dmem_start = .;
-
+ _dmem_data_start = .;
*(.data*)
- . = ALIGN(32);
/* Align section end (see note in .text section) */
. = ALIGN(4);
+ _dmem_data_end = .;
} >dmem AT>dmem_load
.bss : ALIGN(32)
{
+ _dmem_bss_start = .;
*(.bss*)
- . = ALIGN(32);
/* Align section end (see note in .text section) */
. = ALIGN(4);
- _dmem_end = .;
+ _dmem_bss_end = .;
} >dmem AT>dmem_load
+ /* This matches the offset *in DMEM* of the .bss section. */
+ _dmem_bss_offset = ADDR(.bss) - ADDR(.data);
+
.scratchpad ORIGIN(dmem_scratch) (NOLOAD) : ALIGN(32)
{
*(.scratch*)
diff --git a/sw/device/lib/runtime/otbn.c b/sw/device/lib/runtime/otbn.c
index 6116b34..177d241 100644
--- a/sw/device/lib/runtime/otbn.c
+++ b/sw/device/lib/runtime/otbn.c
@@ -17,14 +17,29 @@
otbn_result_t otbn_data_ptr_to_dmem_addr(const otbn_t *ctx, otbn_ptr_t ptr,
uint32_t *dmem_addr_otbn) {
uintptr_t ptr_addr = (uintptr_t)ptr;
- uintptr_t app_dmem_start_addr = (uintptr_t)ctx->app.dmem_start;
- uintptr_t app_dmem_end_addr = (uintptr_t)ctx->app.dmem_end;
+ uintptr_t app_dmem_data_start_addr = (uintptr_t)ctx->app.dmem_data_start;
+ uintptr_t app_dmem_data_end_addr = (uintptr_t)ctx->app.dmem_data_end;
+ uintptr_t app_dmem_bss_start_addr = (uintptr_t)ctx->app.dmem_bss_start;
+ uintptr_t app_dmem_bss_end_addr = (uintptr_t)ctx->app.dmem_bss_end;
+ uintptr_t app_dmem_bss_offset = (uintptr_t)ctx->app.dmem_bss_offset;
- if (dmem_addr_otbn == NULL || ptr == NULL || ctx == NULL ||
- ptr_addr < app_dmem_start_addr || ptr_addr > app_dmem_end_addr) {
+ if (dmem_addr_otbn == NULL || ptr == NULL || ctx == NULL) {
return kOtbnBadArg;
}
- *dmem_addr_otbn = ptr_addr - app_dmem_start_addr;
+
+ if (app_dmem_data_start_addr <= ptr_addr &&
+ ptr_addr < app_dmem_data_end_addr) {
+ // Pointer is in the data section, which is at the start of DMEM
+ *dmem_addr_otbn = ptr_addr - app_dmem_data_start_addr;
+ } else if (app_dmem_bss_start_addr <= ptr_addr &&
+ ptr_addr < app_dmem_bss_end_addr) {
+ // Pointer is in the bss section, which is after the data section
+ *dmem_addr_otbn = ptr_addr - app_dmem_bss_start_addr + app_dmem_bss_offset;
+ } else {
+ // Pointer is not in a valid DMEM region
+ return kOtbnBadArg;
+ }
+
return kOtbnOk;
}
@@ -62,16 +77,46 @@
return kOtbnOk;
}
+/**
+ * Checks if the OTBN application's IMEM and DMEM address parameters are valid.
+ *
+ * IMEM and DMEM ranges must not be "backwards" in memory, with the end address
+ * coming before the start address, and the IMEM range must additionally be
+ * non-empty. Finally, separate sections in DMEM must not overlap each other
+ * when converted to DMEM address space.
+ *
+ * @param app the OTBN application to check
+ * @return true if the addresses are valid, otherwise false.
+ */
+bool check_app_address_ranges(const otbn_app_t *app) {
+ // IMEM must have a strictly positive range (cannot be backwards or empty)
+ if (app->imem_end <= app->imem_start) {
+ return false;
+ }
+ // Both DMEM sections must not be backwards
+ if (app->dmem_data_end < app->dmem_data_start ||
+ app->dmem_bss_end < app->dmem_bss_start) {
+ return false;
+ }
+ // The offset of BSS in DMEM address space must be at least as large as the
+ // data section (i.e. the sections do not overlap in DMEM)
+ if (app->dmem_bss_offset < app->dmem_data_end - app->dmem_data_start) {
+ return false;
+ }
+ return true;
+}
+
otbn_result_t otbn_load_app(otbn_t *ctx, const otbn_app_t app) {
- if (app.imem_end <= app.imem_start || app.dmem_end < app.dmem_start) {
+ if (!check_app_address_ranges(&app)) {
return kOtbnBadArg;
}
const size_t imem_size = app.imem_end - app.imem_start;
- const size_t dmem_size = app.dmem_end - app.dmem_start;
+ const size_t data_size = app.dmem_data_end - app.dmem_data_start;
- // Instruction and data memory images must be multiples of 32b words.
- if (imem_size % sizeof(uint32_t) != 0 || dmem_size % sizeof(uint32_t) != 0) {
+ // Memory images and offsets must be multiples of 32b words.
+ if (imem_size % sizeof(uint32_t) != 0 || data_size % sizeof(uint32_t) != 0 ||
+ (size_t)app.dmem_bss_offset % sizeof(uint32_t) != 0) {
return kOtbnBadArg;
}
@@ -83,9 +128,16 @@
return kOtbnError;
}
- if (dmem_size > 0) {
- if (dif_otbn_dmem_write(&ctx->dif, 0, ctx->app.dmem_start, dmem_size) !=
- kDifOk) {
+ // Zero all of DMEM
+ otbn_result_t err = otbn_zero_data_memory(ctx);
+ if (err != kOtbnOk) {
+ return err;
+ }
+
+ // Write initialized data
+ if (data_size > 0) {
+ if (dif_otbn_dmem_write(&ctx->dif, 0, ctx->app.dmem_data_start,
+ data_size) != kDifOk) {
return kOtbnError;
}
}
diff --git a/sw/device/lib/runtime/otbn.h b/sw/device/lib/runtime/otbn.h
index c349cf2..40ea532 100644
--- a/sw/device/lib/runtime/otbn.h
+++ b/sw/device/lib/runtime/otbn.h
@@ -32,13 +32,30 @@
*/
const uint8_t *imem_end;
/**
- * Start of OTBN data memory.
+ * Start of initialized OTBN data memory.
+ *
+ * Data in this section is copied into DMEM when the app is loaded.
*/
- const uint8_t *dmem_start;
+ const uint8_t *dmem_data_start;
/**
- * End of OTBN data memory.
+ * End of initialized OTBN data memory.
*/
- const uint8_t *dmem_end;
+ const uint8_t *dmem_data_end;
+ /**
+ * Start of uninitialized OTBN data memory.
+ *
+ * Data in this section is initialized to zeroes in DMEM when the app is
+ * loaded.
+ */
+ const uint8_t *dmem_bss_start;
+ /**
+ * End of uninitialized OTBN data memory.
+ */
+ const uint8_t *dmem_bss_end;
+ /**
+ * Offset of the BSS section within DMEM.
+ */
+ uint32_t dmem_bss_offset;
} otbn_app_t;
/**
@@ -113,11 +130,14 @@
* @param app_name Name of the application to load, which is typically the
* name of the main (assembly) source file.
*/
-#define OTBN_DECLARE_APP_SYMBOLS(app_name) \
- extern const uint8_t _otbn_app_##app_name##__imem_start[]; \
- extern const uint8_t _otbn_app_##app_name##__imem_end[]; \
- extern const uint8_t _otbn_app_##app_name##__dmem_start[]; \
- extern const uint8_t _otbn_app_##app_name##__dmem_end[]
+#define OTBN_DECLARE_APP_SYMBOLS(app_name) \
+ extern const uint8_t _otbn_app_##app_name##__imem_start[]; \
+ extern const uint8_t _otbn_app_##app_name##__imem_end[]; \
+ extern const uint8_t _otbn_app_##app_name##__dmem_data_start[]; \
+ extern const uint8_t _otbn_app_##app_name##__dmem_data_end[]; \
+ extern const uint8_t _otbn_app_##app_name##__dmem_bss_start[]; \
+ extern const uint8_t _otbn_app_##app_name##__dmem_bss_end[]; \
+ extern const uint8_t _otbn_app_##app_name##__dmem_bss_offset[];
/**
* Initializes the OTBN application information structure.
@@ -129,12 +149,15 @@
* @param app_name Name of the application to load.
* @see OTBN_DECLARE_APP_SYMBOLS()
*/
-#define OTBN_APP_T_INIT(app_name) \
- ((otbn_app_t){ \
- .imem_start = _otbn_app_##app_name##__imem_start, \
- .imem_end = _otbn_app_##app_name##__imem_end, \
- .dmem_start = _otbn_app_##app_name##__dmem_start, \
- .dmem_end = _otbn_app_##app_name##__dmem_end, \
+#define OTBN_APP_T_INIT(app_name) \
+ ((otbn_app_t){ \
+ .imem_start = _otbn_app_##app_name##__imem_start, \
+ .imem_end = _otbn_app_##app_name##__imem_end, \
+ .dmem_data_start = _otbn_app_##app_name##__dmem_data_start, \
+ .dmem_data_end = _otbn_app_##app_name##__dmem_data_end, \
+ .dmem_bss_start = _otbn_app_##app_name##__dmem_bss_start, \
+ .dmem_bss_end = _otbn_app_##app_name##__dmem_bss_end, \
+ .dmem_bss_offset = (uint32_t)_otbn_app_##app_name##__dmem_bss_offset, \
})
/**
diff --git a/sw/device/silicon_creator/lib/otbn_util.c b/sw/device/silicon_creator/lib/otbn_util.c
index 228f7b9..630d78a 100644
--- a/sw/device/silicon_creator/lib/otbn_util.c
+++ b/sw/device/silicon_creator/lib/otbn_util.c
@@ -24,10 +24,25 @@
otbn_error_t otbn_data_ptr_to_dmem_addr(const otbn_t *ctx, otbn_ptr_t ptr,
uint32_t *dmem_addr_otbn) {
- if (ptr < ctx->app.dmem_start || ptr > ctx->app.dmem_end) {
+ uintptr_t ptr_addr = (uintptr_t)ptr;
+ uintptr_t app_dmem_data_start_addr = (uintptr_t)ctx->app.dmem_data_start;
+ uintptr_t app_dmem_data_end_addr = (uintptr_t)ctx->app.dmem_data_end;
+ uintptr_t app_dmem_bss_start_addr = (uintptr_t)ctx->app.dmem_bss_start;
+ uintptr_t app_dmem_bss_end_addr = (uintptr_t)ctx->app.dmem_bss_end;
+ uintptr_t app_dmem_bss_offset = (uintptr_t)ctx->app.dmem_bss_offset;
+
+ if (app_dmem_data_start_addr <= ptr_addr &&
+ ptr_addr < app_dmem_data_end_addr) {
+ // Pointer is in the `data` section, which is at the start of DMEM
+ *dmem_addr_otbn = ptr_addr - app_dmem_data_start_addr;
+ } else if (app_dmem_bss_start_addr <= ptr_addr &&
+ ptr_addr < app_dmem_bss_end_addr) {
+ // Pointer is in the `bss` section, which is after the data section in DMEM
+ *dmem_addr_otbn = ptr_addr - app_dmem_bss_start_addr + app_dmem_bss_offset;
+ } else {
+ // Pointer is not in a valid DMEM region
return kOtbnErrorInvalidArgument;
}
- *dmem_addr_otbn = (uintptr_t)ptr - (uintptr_t)ctx->app.dmem_start;
return kOtbnErrorOk;
}
@@ -44,21 +59,52 @@
return kOtbnErrorOk;
}
+/**
+ * Checks if the OTBN application's IMEM and DMEM address parameters are valid.
+ *
+ * IMEM and DMEM ranges must not be "backwards" in memory, with the end address
+ * coming before the start address, and the IMEM range must additionally be
+ * non-empty. Finally, separate sections in DMEM must not overlap each other
+ * when converted to DMEM address space.
+ *
+ * @param app the OTBN application to check
+ * @return true if the addresses are valid, otherwise false.
+ */
+bool check_app_address_ranges(const otbn_app_t *app) {
+ // IMEM must have a strictly positive range (cannot be backwards or empty)
+ if (app->imem_end <= app->imem_start) {
+ return false;
+ }
+ // Both DMEM sections must not be backwards
+ if (app->dmem_data_end < app->dmem_data_start ||
+ app->dmem_bss_end < app->dmem_bss_start) {
+ return false;
+ }
+ // The offset of BSS in DMEM address space must be at least as large as the
+ // data section (i.e. the sections do not overlap in DMEM)
+ if (app->dmem_bss_offset <
+ (uintptr_t)app->dmem_data_end - (uintptr_t)app->dmem_data_start) {
+ return false;
+ }
+ return true;
+}
+
otbn_error_t otbn_load_app(otbn_t *ctx, const otbn_app_t app) {
- if (app.imem_end <= app.imem_start || app.dmem_end < app.dmem_start) {
+ if (!check_app_address_ranges(&app)) {
return kOtbnErrorInvalidArgument;
}
const size_t imem_num_words = app.imem_end - app.imem_start;
- const size_t dmem_num_words = app.dmem_end - app.dmem_start;
+ const size_t data_num_words = app.dmem_data_end - app.dmem_data_start;
ctx->app_is_loaded = false;
OTBN_RETURN_IF_ERROR(otbn_imem_write(0, app.imem_start, imem_num_words));
otbn_zero_dmem();
- if (dmem_num_words > 0) {
- OTBN_RETURN_IF_ERROR(otbn_dmem_write(0, app.dmem_start, dmem_num_words));
+ if (data_num_words > 0) {
+ OTBN_RETURN_IF_ERROR(
+ otbn_dmem_write(0, app.dmem_data_start, data_num_words));
}
ctx->app = app;
diff --git a/sw/device/silicon_creator/lib/otbn_util.h b/sw/device/silicon_creator/lib/otbn_util.h
index c03124f..249d997 100644
--- a/sw/device/silicon_creator/lib/otbn_util.h
+++ b/sw/device/silicon_creator/lib/otbn_util.h
@@ -45,15 +45,37 @@
*/
const uint32_t *imem_end;
/**
- * Start of OTBN data memory.
- */
- const uint32_t *dmem_start;
- /**
- * The first word after OTBN data memory.
+ * Start of initialized OTBN data.
*
- * This address satifies `dmem_len = dmem_end - dmem_start`.
+ * Data in between dmem_data_start and dmem_data_end will be copied to OTBN
+ * at app load time.
*/
- const uint32_t *dmem_end;
+ const uint32_t *dmem_data_start;
+ /**
+ * The first word after initialized OTBN data.
+ *
+ * Should satisfy `dmem_data_start <= dmem_data_end`.
+ */
+ const uint32_t *dmem_data_end;
+ /**
+ * Start of uninitialized OTBN data memory.
+ *
+ * Data in between dmem_bss_start and dmem_bss_end will not be copied to
+ * OTBN; it will be initialized to zeroes at app load time.
+ */
+ const uint32_t *dmem_bss_start;
+ /**
+ * The first word after uninitialized OTBN data memory.
+ *
+ * Should satisfy `dmem_bss_start <= dmem_bss_end`.
+ */
+ const uint32_t *dmem_bss_end;
+ /**
+ * DMEM address at which the BSS section begins.
+ *
+ * Should satisfy `dmem_data_end - dmem_data_start <= dmem_bss_offset`.
+ */
+ uint32_t dmem_bss_offset;
} otbn_app_t;
/**
@@ -103,11 +125,14 @@
* @param app_name Name of the application to load, which is typically the
* name of the main (assembly) source file.
*/
-#define OTBN_DECLARE_APP_SYMBOLS(app_name) \
- extern const uint32_t _otbn_app_##app_name##__imem_start[]; \
- extern const uint32_t _otbn_app_##app_name##__imem_end[]; \
- extern const uint32_t _otbn_app_##app_name##__dmem_start[]; \
- extern const uint32_t _otbn_app_##app_name##__dmem_end[]
+#define OTBN_DECLARE_APP_SYMBOLS(app_name) \
+ extern const uint32_t _otbn_app_##app_name##__imem_start[]; \
+ extern const uint32_t _otbn_app_##app_name##__imem_end[]; \
+ extern const uint32_t _otbn_app_##app_name##__dmem_data_start[]; \
+ extern const uint32_t _otbn_app_##app_name##__dmem_data_end[]; \
+ extern const uint32_t _otbn_app_##app_name##__dmem_bss_start[]; \
+ extern const uint32_t _otbn_app_##app_name##__dmem_bss_end[]; \
+ extern const uint32_t _otbn_app_##app_name##__dmem_bss_offset[];
/**
* Initializes the OTBN application information structure.
@@ -119,12 +144,15 @@
* @param app_name Name of the application to load.
* @see OTBN_DECLARE_APP_SYMBOLS()
*/
-#define OTBN_APP_T_INIT(app_name) \
- ((otbn_app_t){ \
- .imem_start = _otbn_app_##app_name##__imem_start, \
- .imem_end = _otbn_app_##app_name##__imem_end, \
- .dmem_start = _otbn_app_##app_name##__dmem_start, \
- .dmem_end = _otbn_app_##app_name##__dmem_end, \
+#define OTBN_APP_T_INIT(app_name) \
+ ((otbn_app_t){ \
+ .imem_start = _otbn_app_##app_name##__imem_start, \
+ .imem_end = _otbn_app_##app_name##__imem_end, \
+ .dmem_data_start = _otbn_app_##app_name##__dmem_data_start, \
+ .dmem_data_end = _otbn_app_##app_name##__dmem_data_end, \
+ .dmem_bss_start = _otbn_app_##app_name##__dmem_bss_start, \
+ .dmem_bss_end = _otbn_app_##app_name##__dmem_bss_end, \
+ .dmem_bss_offset = (uint32_t)_otbn_app_##app_name##__dmem_bss_offset, \
})
/**
diff --git a/util/otbn_build.py b/util/otbn_build.py
index f534969..68957bb 100755
--- a/util/otbn_build.py
+++ b/util/otbn_build.py
@@ -200,9 +200,12 @@
sym_pfx = '_otbn_app_{}_'.format(app_name)
out_embedded_obj = out_dir / (app_name + '.rv32embed.o')
args = (['-O', 'elf32-littleriscv',
- '--prefix-sections=.rodata.otbn',
- '--set-section-flags=*=alloc,readonly',
- '--set-section-flags=.data=load',
+ '--set-section-flags=*=alloc,load,readonly',
+ '--set-section-flags=.bss=alloc,readonly',
+ '--rename-section=.text=.rodata.otbn.text',
+ '--rename-section=.start=.rodata.otbn.start',
+ '--rename-section=.data=.rodata.otbn.data',
+ '--rename-section=.bss=.bss.otbn.bss',
'--remove-section=.scratchpad',
'--prefix-symbols', sym_pfx] +
[out_elf,