[Cbe-oss-dev] [PATCH 09/23 v2]MARS/base: workload module elf loader
Yuji Mano
yuji.mano at am.sony.com
Tue Mar 17 12:19:40 EST 2009
This patch accomplishes several changes.
* It moves the workload_module structure definition into internal headers so it
is no longer public.
* The workload module structure is now redefined and 64 bytes.
* The workload context structure is now 256 bytes.
* The mars_workload_queue_add_begin() API function now takes the module_elf and
module_name parameters and internally sets the workload module structure
inside the workload context.
* Updates the kernel so text and data segments are loaded/reloaded as necessary.
Signed-off-by: Yuji Mano <yuji.mano at am.sony.com>
---
v2:
- Need to mars_ea_get() before unmapping elfs in remove_workload_module() so
workload module is copied into the work area from EA.
base/include/common/mars/workload_types.h | 37 +-----
base/include/host/mars/workload_queue.h | 8 +
base/src/common/workload_internal_types.h | 15 ++
base/src/host/lib/workload_queue.c | 160 +++++++++++++++++++++++++++++-
base/src/mpu/kernel/kernel.c | 48 +++++----
5 files changed, 217 insertions(+), 51 deletions(-)
--- a/base/include/common/mars/workload_types.h
+++ b/base/include/common/mars/workload_types.h
@@ -55,15 +55,21 @@
/**
* \ingroup group_mars_workload_module
+ * \brief Maximum length of workload module name
+ */
+#define MARS_WORKLOAD_MODULE_NAME_LEN_MAX 23
+
+/**
+ * \ingroup group_mars_workload_module
* \brief Size of workload module structure
*/
-#define MARS_WORKLOAD_MODULE_SIZE 20
+#define MARS_WORKLOAD_MODULE_SIZE 64
/**
* \ingroup group_mars_workload_queue
* \brief Size of workload context structure
*/
-#define MARS_WORKLOAD_CONTEXT_SIZE 128
+#define MARS_WORKLOAD_CONTEXT_SIZE 256
/**
* \ingroup group_mars_workload_queue
@@ -72,29 +78,6 @@
#define MARS_WORKLOAD_CONTEXT_ALIGN 128
/**
- * \ingroup group_mars_workload_module
- * \brief MARS workload module structure
- *
- * This structure stores information about the workload module executable that
- * needs to be loaded and executed in order to handle processing of a workload
- * context.
- *
- * The workload model implementation is responsible for populating this
- * structure inside the workload context before adding the workload context to
- * the workload queue.
- */
-struct mars_workload_module {
- /** ea of exec */
- uint64_t exec_ea;
- /** size of text and data of exec */
- uint32_t exec_size;
- /** size of bss in memory of exec */
- uint32_t bss_size;
- /** entry address of exec */
- uint32_t entry;
-} __attribute__((packed));
-
-/**
* \ingroup group_mars_workload_context
* \brief MARS workload context structure
*
@@ -106,8 +89,8 @@ struct mars_workload_module {
* model implementation as needed.
*/
struct mars_workload_context {
- /** workload module information */
- struct mars_workload_module module;
+ /** workload module reserved area */
+ uint8_t workload_module[MARS_WORKLOAD_MODULE_SIZE];
/** workload model specific data */
uint8_t context[MARS_WORKLOAD_CONTEXT_SIZE - MARS_WORKLOAD_MODULE_SIZE];
} __attribute__((aligned(MARS_WORKLOAD_CONTEXT_ALIGN)));
--- a/base/include/host/mars/workload_queue.h
+++ b/base/include/host/mars/workload_queue.h
@@ -77,15 +77,19 @@ int mars_workload_queue_exit(struct mars
* \param[in] mars - address of pointer to MARS context
* \param[out] id - pointer to return workload id
* \param[out] workload_ea - address of pointer to workload context ea
+ * \param[in] module_elf - pointer to workload module elf image
+ * \param[in] module_name - name of module
* \return
* MARS_SUCCESS - workload adding started
* \n MARS_ERROR_NULL - null pointer specified
- * \n MARS_ERROR_PARAMS - invalid mars context specified
+ * \n MARS_ERROR_PARAMS - invalid mars context or module specified
* \n MARS_ERROR_LIMIT - workload queue is full
*/
int mars_workload_queue_add_begin(struct mars_context *mars,
uint16_t *id,
- uint64_t *workload_ea);
+ uint64_t *workload_ea,
+ const void *module_elf,
+ const char *module_name);
/**
* \ingroup group_mars_workload_queue
--- a/base/src/common/workload_internal_types.h
+++ b/base/src/common/workload_internal_types.h
@@ -138,6 +138,8 @@
#define MARS_HOST_SIGNAL_EXIT 0x0 /* host exit flag */
+#define MARS_WORKLOAD_MODULE_ALIGN 16
+
/* 128 byte workload queue header structure */
struct mars_workload_queue_header {
uint32_t lock;
@@ -162,4 +164,17 @@ struct mars_workload_queue {
struct mars_workload_context context[MARS_WORKLOAD_MAX];
} __attribute__((aligned(MARS_WORKLOAD_QUEUE_ALIGN)));
+/* mars workload module structure */
+struct mars_workload_module {
+ uint64_t text_ea;
+ uint64_t data_ea;
+ uint32_t text_vaddr;
+ uint32_t data_vaddr;
+ uint32_t text_size;
+ uint32_t data_size;
+ uint32_t bss_size;
+ uint32_t entry;
+ uint8_t name[MARS_WORKLOAD_MODULE_NAME_LEN_MAX + 1];
+} __attribute__((aligned(MARS_WORKLOAD_MODULE_ALIGN)));
+
#endif
--- a/base/src/host/lib/workload_queue.c
+++ b/base/src/host/lib/workload_queue.c
@@ -35,6 +35,7 @@
* LIBRARY OR THE USE OR OTHER DEALINGS IN THE LIBRARY.
*/
+#include <elf.h>
#include <string.h>
#include "config.h"
@@ -372,10 +373,147 @@ static int alloc_block(uint64_t block_ea
return ret;
}
+static int add_workload_module(uint64_t workload_ea,
+ const void *workload_module_elf,
+ const char *workload_module_name)
+{
+ int ret, i;
+ int text_found = 0;
+ int data_found = 0;
+ Elf32_Ehdr *ehdr;
+ Elf32_Phdr *phdr;
+ struct mars_workload_module *workload_module;
+
+ /* get work area for workload module */
+ workload_module = mars_ea_work_area_get(workload_ea,
+ MARS_WORKLOAD_MODULE_ALIGN,
+ MARS_WORKLOAD_MODULE_SIZE);
+
+ memset(workload_module, 0, MARS_WORKLOAD_MODULE_SIZE);
+
+ /* process elf header information */
+ ehdr = (Elf32_Ehdr *)workload_module_elf;
+ phdr = (Elf32_Phdr *)((void *)ehdr + ehdr->e_phoff);
+
+ /* elf is not executable */
+ if (ehdr->e_type != ET_EXEC)
+ return MARS_ERROR_FORMAT;
+
+ /* iterate through program header segments */
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ /* readonly text segment */
+ if (phdr->p_type == PT_LOAD &&
+ phdr->p_flags == PF_R + PF_X &&
+ phdr->p_align == 0x80) {
+ /* make sure base addr is what we expect */
+ if (text_found ||
+ phdr->p_vaddr != MARS_WORKLOAD_MODULE_BASE_ADDR ||
+ phdr->p_memsz != phdr->p_filesz) {
+ ret = MARS_ERROR_FORMAT;
+ goto error;
+ }
+
+ /* initialize the workload module text info */
+ workload_module->text_ea = mars_ea_map((void *)ehdr +
+ phdr->p_offset,
+ phdr->p_filesz);
+ if (!workload_module->text_ea) {
+ ret = MARS_ERROR_MEMORY;
+ goto error;
+ }
+
+ workload_module->text_vaddr = phdr->p_vaddr;
+ workload_module->text_size = phdr->p_filesz;
+
+ /* make sure we only find 1 text segment */
+ text_found = 1;
+ /* read-write data segment */
+ } else if (phdr->p_type == PT_LOAD &&
+ phdr->p_flags == PF_R + PF_W &&
+ phdr->p_align == 0x80) {
+ if (data_found) {
+ ret = MARS_ERROR_FORMAT;
+ goto error;
+ }
+
+ workload_module->data_ea = mars_ea_map((void *)ehdr +
+ phdr->p_offset,
+ phdr->p_filesz);
+ if (!workload_module->data_ea) {
+ ret = MARS_ERROR_MEMORY;
+ goto error;
+ }
+
+ workload_module->data_vaddr = phdr->p_vaddr;
+ workload_module->data_size = phdr->p_filesz;
+ workload_module->bss_size = phdr->p_memsz -
+ phdr->p_filesz;
+
+ /* make sure we only find 1 data segment */
+ data_found = 1;
+ }
+
+ /* increment program header */
+ phdr = (void *)phdr + ehdr->e_phentsize;
+ }
+
+ /* make sure text and data segment is found */
+ if (!text_found || !data_found) {
+ ret = MARS_ERROR_FORMAT;
+ goto error;
+ }
+
+ /* set the entry point of execution */
+ workload_module->entry = ehdr->e_entry;
+
+ if (workload_module_name)
+ strcpy((char *)workload_module->name, workload_module_name);
+ else
+ memset((char *)workload_module->name, 0,
+ MARS_WORKLOAD_MODULE_NAME_LEN_MAX + 1);
+
+ /* update workload module on EA */
+ mars_ea_put(workload_ea, workload_module, MARS_WORKLOAD_MODULE_SIZE);
+ mars_ea_sync();
+
+ return MARS_SUCCESS;
+
+error:
+ if (text_found)
+ mars_ea_unmap(workload_module->text_ea,
+ workload_module->text_size);
+ if (data_found)
+ mars_ea_unmap(workload_module->data_ea,
+ workload_module->data_size);
+
+ return ret;
+}
+
+static void remove_workload_module(struct mars_context *mars, uint16_t id)
+{
+ struct mars_workload_module *workload_module;
+
+ /* prepare work area for workload module */
+ workload_module = mars_ea_work_area_get(
+ get_workload_ea(mars->workload_queue_ea, id),
+ MARS_WORKLOAD_MODULE_ALIGN,
+ MARS_WORKLOAD_MODULE_SIZE);
+
+ /* get workload module from ea */
+ mars_ea_get(mars->workload_queue_ea, workload_module,
+ MARS_WORKLOAD_MODULE_SIZE);
+
+ mars_ea_unmap(workload_module->text_ea, workload_module->text_size);
+ mars_ea_unmap(workload_module->data_ea, workload_module->data_size);
+}
+
int mars_workload_queue_add_begin(struct mars_context *mars,
uint16_t *id,
- uint64_t *workload_ea)
+ uint64_t *workload_ea,
+ const void *workload_module_elf,
+ const char *workload_module_name)
{
+ int ret;
int block;
int index = 0;
uint64_t queue_ea;
@@ -387,6 +525,11 @@ int mars_workload_queue_add_begin(struct
return MARS_ERROR_PARAMS;
if (!id)
return MARS_ERROR_NULL;
+ if (!workload_module_elf)
+ return MARS_ERROR_NULL;
+ if (workload_module_name &&
+ strlen(workload_module_name) > MARS_WORKLOAD_MODULE_NAME_LEN_MAX)
+ return MARS_ERROR_PARAMS;
queue_ea = mars->workload_queue_ea;
@@ -406,6 +549,17 @@ int mars_workload_queue_add_begin(struct
/* calculate and return workload id */
*id = block * MARS_WORKLOAD_PER_BLOCK + index;
+ /* add the workload module in workload context */
+ ret = add_workload_module(get_workload_ea(queue_ea, *id),
+ workload_module_elf, workload_module_name);
+ if (ret != MARS_SUCCESS) {
+ change_state(mars, *id, NULL,
+ MARS_WORKLOAD_STATE_ADDING,
+ MARS_WORKLOAD_STATE_NONE,
+ NULL);
+ return ret;
+ }
+
/* if requested set workload context pointer to return */
if (workload_ea)
*workload_ea = get_workload_ea(queue_ea, *id);
@@ -428,7 +582,7 @@ int mars_workload_queue_add_cancel(struc
return change_state(mars, id, NULL,
MARS_WORKLOAD_STATE_ADDING,
MARS_WORKLOAD_STATE_NONE,
- NULL);
+ remove_workload_module);
}
int mars_workload_queue_remove_begin(struct mars_context *mars,
@@ -447,7 +601,7 @@ int mars_workload_queue_remove_end(struc
return change_state(mars, id, NULL,
MARS_WORKLOAD_STATE_REMOVING,
MARS_WORKLOAD_STATE_NONE,
- NULL);
+ remove_workload_module);
}
int mars_workload_queue_remove_cancel(struct mars_context *mars,
--- a/base/src/mpu/kernel/kernel.c
+++ b/base/src/mpu/kernel/kernel.c
@@ -67,7 +67,8 @@ static uint8_t workload_cached;
static struct mars_workload_context schedule_workload;
static uint16_t schedule_workload_id;
-/* workload module cached */
+/* workload module */
+static struct mars_workload_module *workload_module;
static struct mars_workload_module cached_workload_module;
/* workload module entry */
@@ -734,6 +735,7 @@ static int workload_reserve(void)
/* set global workload info based on workload block and index */
workload_id = MARS_WORKLOAD_PER_BLOCK * block + index;
workload_ea = get_workload_ea(workload_id);
+ workload_module = (struct mars_workload_module *)&workload;
/* get the workload context code from workload queue */
dma_get(&workload, workload_ea, sizeof(struct mars_workload_context),
@@ -779,35 +781,43 @@ static void __attribute__((noinline)) wo
__kernel_stack = sp;
/* call module entry function */
- ((module_entry)workload.module.entry)(&kernel_syscalls);
+ ((module_entry)workload_module->entry)(&kernel_syscalls);
}
static void workload_module_load(void)
{
__vector unsigned char *bss_ptr, *bss_end;
- /* 0 the bss section */
- bss_ptr = (__vector unsigned char *)(MARS_WORKLOAD_MODULE_BASE_ADDR +
- workload.module.exec_size);
+ /* only reload the readonly text segment if different from cached */
+ if (kernel_memcmp(&cached_workload_module, workload_module,
+ sizeof(struct mars_workload_module))) {
+ /* store the current cached workload module ea */
+ kernel_memcpy(&cached_workload_module, workload_module,
+ sizeof(struct mars_workload_module));
+
+ /* load the text into mpu storage from host storage */
+ dma_get((void *)workload_module->text_vaddr,
+ workload_module->text_ea,
+ workload_module->text_size,
+ MARS_KERNEL_DMA_TAG);
+ }
+
+ /* load the read-write data segment */
+ dma_get((void *)workload_module->data_vaddr,
+ workload_module->data_ea,
+ workload_module->data_size,
+ MARS_KERNEL_DMA_TAG);
+
+ /* 0 the bss segment */
+ bss_ptr = (__vector unsigned char *)(workload_module->data_vaddr +
+ workload_module->data_size);
bss_end = (__vector unsigned char *)((void *)bss_ptr +
- workload.module.bss_size);
+ workload_module->bss_size);
while (bss_ptr < bss_end)
*bss_ptr++ = spu_splats((unsigned char)0);
- /* only reload the workload module if different from cached */
- if (kernel_memcmp(&cached_workload_module, &workload.module,
- sizeof(struct mars_workload_module))) {
- /* load the exec code into mpu storage from host storage */
- dma_get((void *)MARS_WORKLOAD_MODULE_BASE_ADDR,
- workload.module.exec_ea, workload.module.exec_size,
- MARS_KERNEL_DMA_TAG);
- dma_wait(MARS_KERNEL_DMA_TAG);
-
- /* store the current cached workload module ea */
- kernel_memcpy(&cached_workload_module, &workload.module,
- sizeof(struct mars_workload_module));
- }
+ dma_wait(MARS_KERNEL_DMA_TAG);
/* sync before executing loaded code */
spu_sync();
More information about the cbe-oss-dev
mailing list