summaryrefslogtreecommitdiffstats
path: root/cpukit
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit')
-rw-r--r--cpukit/libdl/rtl-elf.c2
-rw-r--r--cpukit/libdl/rtl-obj.c63
-rw-r--r--cpukit/libdl/rtl-obj.h7
-rw-r--r--cpukit/libdl/rtl-rap.c2
4 files changed, 74 insertions, 0 deletions
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 1b7c87448a..b686a4812f 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -944,6 +944,8 @@ rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd)
if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocator, &ehdr))
return false;
+ rtems_rtl_obj_synchronize_cache (obj);
+
rtems_rtl_symbol_obj_erase_local (obj);
if (!rtems_rtl_elf_load_details (obj))
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index 5c89990466..f61d4e53d7 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -558,6 +558,69 @@ rtems_rtl_obj_relocate (rtems_rtl_obj_t* obj,
return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
}
+/**
+ * Cache synchronization after runtime object load (dlopen)
+ */
+typedef struct
+{
+ uint32_t mask;
+ void *start_va;
+ void *end_va;
+} rtems_rtl_obj_sect_sync_ctx_t;
+
+static bool
+rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
+{
+ rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
+ rtems_rtl_obj_sect_sync_ctx_t* sync_ctx = data;
+ uintptr_t old_end;
+ uintptr_t new_start;
+
+ if ( !(sect->flags & sync_ctx->mask) || !sect->size)
+ return true;
+
+ if (sync_ctx->end_va == sync_ctx->start_va) {
+ sync_ctx->start_va = sect->base;
+ } else {
+ old_end = (uintptr_t)sync_ctx->end_va & ~(CPU_CACHE_LINE_BYTES - 1);
+ new_start = (uintptr_t)sect->base & ~(CPU_CACHE_LINE_BYTES - 1);
+ if ( (sect->base < sync_ctx->start_va) ||
+ (new_start - old_end > CPU_CACHE_LINE_BYTES) ) {
+ rtems_cache_instruction_sync_after_code_change(sync_ctx->start_va,
+ sync_ctx->end_va - sync_ctx->start_va + 1);
+ sync_ctx->start_va = sect->base;
+ }
+ }
+
+ sync_ctx->end_va = sect->base + sect->size;
+
+ return true;
+}
+
+void
+rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj)
+{
+ rtems_rtl_obj_sect_sync_ctx_t sync_ctx;
+
+ if (rtems_cache_get_instruction_line_size() == 0)
+ return;
+
+ sync_ctx.mask = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST |
+ RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_BSS |
+ RTEMS_RTL_OBJ_SECT_EXEC;
+
+ sync_ctx.start_va = 0;
+ sync_ctx.end_va = sync_ctx.start_va;
+ rtems_rtl_chain_iterate (&obj->sections,
+ rtems_rtl_obj_sect_sync_handler,
+ &sync_ctx);
+
+ if (sync_ctx.end_va != sync_ctx.start_va) {
+ rtems_cache_instruction_sync_after_code_change(sync_ctx.start_va,
+ sync_ctx.end_va - sync_ctx.start_va);
+ }
+}
+
bool
rtems_rtl_obj_load_symbols (rtems_rtl_obj_t* obj,
int fd,
diff --git a/cpukit/libdl/rtl-obj.h b/cpukit/libdl/rtl-obj.h
index 1202fd5643..80fc60fb05 100644
--- a/cpukit/libdl/rtl-obj.h
+++ b/cpukit/libdl/rtl-obj.h
@@ -494,6 +494,13 @@ bool rtems_rtl_obj_relocate (rtems_rtl_obj_t* obj,
void* data);
/**
+ * Synchronize caches to make code visible to CPU(s)
+ *
+ * @param obj The object file's descriptor.
+ */
+void rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj);
+
+/**
* Relocate an object file's unresolved reference.
*
* @param rec The unresolved relocation record.
diff --git a/cpukit/libdl/rtl-rap.c b/cpukit/libdl/rtl-rap.c
index 439eb20c79..a7fcb9f953 100644
--- a/cpukit/libdl/rtl-rap.c
+++ b/cpukit/libdl/rtl-rap.c
@@ -970,6 +970,8 @@ rtems_rtl_rap_file_load (rtems_rtl_obj_t* obj, int fd)
if (!rtems_rtl_rap_relocate (&rap, obj))
return false;
+ rtems_rtl_obj_synchronize_cache (obj);
+
return true;
}