[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