tlk: 6/19 update
[3rdparty/ote_partner/tlk.git] / kernel / task.c
index 5c93553..3f4b0ef 100644 (file)
 #include <platform/platform_p.h>
 #include <kernel/task_load.h>
 
-/* page aligned area for storing task headers */
+/*! page aligned area for storing static task headers before heap is initialized */
 #define TASK_LIST_CARVEOUT_PAGES 1
 
-#define MAX_TASK_COUNT ((TASK_LIST_CARVEOUT_PAGES * PAGE_SIZE) / sizeof(task_t))
+/*! max number of tasks embedded in the TLK task image */
+#define MAX_STATIC_TASK_COUNT ((TASK_LIST_CARVEOUT_PAGES * PAGE_SIZE) / sizeof(task_t))
 
-/* task list and count */
-static u_int task_count;
-static task_t *task_list;
+/* task list and used index */
+static u_int task_next_index;  /* next task index [ 0..N ] */
+static task_t *task_blist;     /* boot time fixed size task list */
+
+/* task_blist is converted to task_list after heap is initialized */
+static struct list_node task_list;
 
 static char *task_image_start;
 static char *task_image_end;
@@ -158,21 +162,21 @@ static status_t task_load_config_options(u_int task_image_addr, task_t *taskp, E
                                }
                                taskp->props.restrict_access = config_blob[++i];
                                break;
-                       case OTE_CONFIG_KEY_INSTALL:
-                               /* tasks which are allowed to install other tasks. */
+                       case OTE_CONFIG_KEY_AUTHORIZE:
+                               /* tasks which are authorized to perform restricted operations */
                                if ((taskp->props.config_entry_cnt - i) <= 1) {
                                        err = ERR_NOT_VALID;
                                        goto exit;
                                }
-                               taskp->props.install_priv = config_blob[++i];
+                               taskp->props.authorizations = config_blob[++i];
                                break;
-                       case OTE_CONFIG_KEY_IMMUTABLE:
-                               /* prevents any manifest data overrides by installer. */
+                       case OTE_CONFIG_KEY_TASK_ISTATE:
+                               /* task initial state attributes */
                                if ((taskp->props.config_entry_cnt - i) <= 1) {
                                        err = ERR_NOT_VALID;
                                        goto exit;
                                }
-                               taskp->props.immutable = config_blob[++i];
+                               taskp->props.initial_state = config_blob[++i];
                                break;
                        default:
                                dprintf(CRITICAL,
@@ -353,6 +357,7 @@ static status_t task_init_stack(task_t *taskp)
        mptr->vaddr = TASK_STACK_ADDR - mptr->size;
        mptr->flags = (TM_UW | TM_UR | TM_PHYS_CONTIG);
        mptr->offset = 0;
+       mptr->map_attrs = NULL;
 
        taskp->stack_map = mptr;
        task_add_mapping(taskp, mptr);
@@ -399,8 +404,10 @@ static status_t task_init_brk(u_int task_image_addr, task_t *taskp, Elf32_Ehdr *
 
                mptr->size  = taskp->props.min_heap_size;
                mptr->u_phys.contig = (addr_t) memalign(PAGE_SIZE, mptr->size);
-               if (mptr->u_phys.contig == NULL)
+               if (mptr->u_phys.contig == NULL) {
+                       free(mptr);
                        return ERR_NO_MEMORY;
+               }
 
                /* mmap expects MAP_ANONYMOUS to be zeros */
                memset((void *)(addr_t)mptr->u_phys.contig, 0, mptr->size);
@@ -413,6 +420,8 @@ static status_t task_init_brk(u_int task_image_addr, task_t *taskp, Elf32_Ehdr *
                mptr->vaddr = taskp->end_brk;
                mptr->flags = (TM_UW | TM_UR | TM_PHYS_CONTIG);
                mptr->offset = 0;
+               mptr->map_attrs = NULL;
+
                task_add_mapping(taskp, mptr);
 
                taskp->end_brk += mptr->size;
@@ -479,6 +488,7 @@ static status_t task_alloc_address_map(task_t *taskp)
                mptr->vaddr = prg_hdr->p_vaddr;
                mptr->flags = (prg_hdr->p_flags & PF_FLAG_MASK) | TM_PHYS_CONTIG;
                mptr->offset = 0;
+               mptr->map_attrs = NULL;
 
                task_add_mapping(taskp, mptr);
 
@@ -587,7 +597,7 @@ static char *task_align_next_task(Elf32_Ehdr *elf_hdr, Elf32_Shdr *pad_hdr)
 }
 
 status_t task_prepare(char *task_addr, u_int task_size, task_t *taskp,
-                     Elf32_Shdr **bss_pad_shdr_p)
+                     Elf32_Shdr **bss_pad_shdr_p, task_type_t task_type)
 {
        status_t    err = NO_ERROR;
        Elf32_Ehdr *ehdr = NULL;
@@ -605,7 +615,10 @@ status_t task_prepare(char *task_addr, u_int task_size, task_t *taskp,
                goto exit;
        }
 
-       dprintf(SPEW, "%s task: start 0x%p size %d (0x%08x)\n",
+       /* For the preloaded tasks: the size includes this task and all
+        * other tasks that follow in the same image.
+        */
+       dprintf(SPEW, "%s task: start %p size %d (0x%08x)\n",
                __func__, task_addr, task_size, task_size);
 
        ehdr = (Elf32_Ehdr *) task_addr;
@@ -700,6 +713,9 @@ status_t task_prepare(char *task_addr, u_int task_size, task_t *taskp,
        }
 
        taskp->elf_hdr = ehdr;
+       taskp->task_size = task_size;
+
+       taskp->task_type  = task_type;
        taskp->task_state = TASK_STATE_INIT;
 
        if (0) {
@@ -714,6 +730,8 @@ status_t task_prepare(char *task_addr, u_int task_size, task_t *taskp,
 /*
  * Carveout memory for task headers.
  * Called before heap_init.
+ *
+ * The task headers are converted to a list after the heap is initialized.
  */
 static void task_mem_init()
 {
@@ -722,10 +740,10 @@ static void task_mem_init()
 
                /* list of tasks (static and loaded) */
                carveout_taskmem -= (TASK_LIST_CARVEOUT_PAGES * PAGE_SIZE);
-               task_list = (task_t *)carveout_taskmem;
+               task_blist = (task_t *)carveout_taskmem;
 
-               task_load_config ((vaddr_t)&_end,
-                                 (vaddr_t *)&carveout_taskmem);
+               task_load_config((vaddr_t)&_end,
+                                (vaddr_t *)&carveout_taskmem);
        }
 
        ASSERT(!(carveout_taskmem & PAGE_MASK));
@@ -744,56 +762,76 @@ static void task_bootloader()
        task_t     *taskp            = NULL;
        status_t    err              = NO_ERROR;
 
-       dprintf(SPEW, "static tasks: start 0x%p size 0x%08x end 0x%p\n",
+       dprintf(SPEW, "static tasks: start %p size 0x%08x end %p\n",
                task_image_start, task_image_size, task_image_end);
 
        task_image_addr = task_image_start;
 
        task_mem_init();
 
-       memset(task_list, 0, TASK_LIST_CARVEOUT_PAGES * PAGE_SIZE);
+       memset(task_blist, 0, TASK_LIST_CARVEOUT_PAGES * PAGE_SIZE);
 
-       taskp = task_list;
+       taskp = task_blist;
 
        while (task_image_size > 0) {
+               u_int i = 0;
                Elf32_Shdr *bss_pad_shdr = NULL;
 
-               ASSERT((task_count + 1) <= MAX_TASK_COUNT);
+               if ((task_next_index + 1) > MAX_STATIC_TASK_COUNT) {
+                       dprintf(CRITICAL, "%s: Too many (%d) tasks in image\n",
+                               __func__, task_next_index+1);
+                       halt();
+               }
 
                err = task_prepare(task_image_addr, task_image_size,
-                                  taskp, &bss_pad_shdr);
+                                  taskp, &bss_pad_shdr, TASK_TYPE_STATIC);
 
                /* statically loaded tasks must run or the system halts */
                if (err != NO_ERROR) {
-                       dprintf(CRITICAL, "%s: task %d preparation failed (%d)\n",
-                               __func__, task_count, err);
-                       halt();
+                       dprintf(CRITICAL, "%s: task#%u preparation failed (%d)\n",
+                              __func__, task_next_index, err);
+                      halt();
                }
 
+               /* Because the size passed to task_prepare above can be larger than the
+                * actual task size in memory (it is larger unless this is the
+                * last task of the image) => fixup the task size here.
+                *
+                * BSS-PAD section is the last accepted PT_LOAD elf section of the secure task,
+                * so task actual memory size can be calculated as below.
+                */
+               taskp->task_size = bss_pad_shdr->sh_offset + bss_pad_shdr->sh_size;
+
                /* static tasks must contain a manifest section */
                if (!taskp->props.manifest_exists) {
-                       dprintf(CRITICAL, "%s: Invalid task image (%d)\n",
-                               __func__, task_count);
+                       dprintf(CRITICAL, "%s: Invalid task#%u in image, no manifest\n",
+                               __func__, task_next_index);
                        halt();
                }
 
                /*
                 * Make sure UUID doesn't already exist.  Note that
                 * this search won't include the task we are processing
-                * here because task_count hasn't been incremented yet.
+                * here because task_next_index hasn't been incremented yet.
+                *
+                * task_find_task_by_uuid() can not yet be used.
                 */
-               if (task_find_task_by_uuid(&taskp->props.uuid) != NULL) {
-                       dprintf(CRITICAL, "%s: task %d duplicate UUID found!\n",
-                               __func__, task_count);
-                       halt();
+               for (i = 0; i < task_next_index; i++) {
+                       task_t *ts = &task_blist[i];
+                       if (!memcmp(&ts->props.uuid, &taskp->props.uuid, sizeof(te_service_id_t))) {
+                               dprintf(CRITICAL, "%s: task#%u duplicate UUID found!\n",
+                                       __func__, task_next_index);
+                               halt();
+                       }
                }
 
-               task_image_addr = task_align_next_task(taskp->elf_hdr,
-                                                      bss_pad_shdr);
+               /*
+                * The next tasks in the image are moved down to the next free
+                * page aligned address after the current task.
+                */
+               task_image_addr = task_align_next_task(taskp->elf_hdr, bss_pad_shdr);
 
-               /* task_state is now TASK_STATE_INIT */
-               taskp->task_index = task_count;
-               task_count++;
+               taskp->task_index = task_next_index++;
                taskp++;
        }
 }
@@ -809,13 +847,14 @@ void task_early_init()
        task_bootloader();
 }
 
-status_t task_init_one_task(task_t *task, u_int task_type)
+status_t task_init_one_task(task_t *task)
 {
        status_t err = NO_ERROR;
        char name[32];
        thread_t *thread;
+       const char *state_str = "(unknown)";
 
-       if (!task || task->task_index > task_count) {
+       if (!task || task->task_index >= task_next_index) {
                err = ERR_INVALID_ARGS;
                goto exit;
        }
@@ -828,6 +867,7 @@ status_t task_init_one_task(task_t *task, u_int task_type)
        }
 
        list_initialize(&task->map_list);
+       list_initialize(&task->thread_node);
 
        err = task_alloc_address_map(task);
        if (err != NO_ERROR) {
@@ -856,8 +896,6 @@ status_t task_init_one_task(task_t *task, u_int task_type)
        }
        name[sizeof(name) - 1] = '\000';
 
-       task->task_type = task_type;
-
        thread = thread_create(name, (thread_start_routine)(task->entry), 0, LOW_PRIORITY, 4096);
        if (thread == NULL) {
                dprintf(CRITICAL, "%s: allocate user thread failed\n",
@@ -866,8 +904,6 @@ status_t task_init_one_task(task_t *task, u_int task_type)
                goto exit;
        }
 
-       list_initialize(&task->thread_node);
-
        if (arch_task_init(thread, task) == false) {
                dprintf(CRITICAL, "%s: arch thread/task init failed\n",
                        __func__);
@@ -875,16 +911,19 @@ status_t task_init_one_task(task_t *task, u_int task_type)
                goto exit;
        }
 
-       task->task_state = TASK_STATE_ACTIVE;
+       if (task->props.initial_state & OTE_MANIFEST_TASK_ISTATE_BLOCKED) {
+               task->task_state = TASK_STATE_BLOCKED;
+               state_str = "blocked";
+       } else {
+               task->task_state = TASK_STATE_ACTIVE;
+               state_str = "active";
+       }
 
        /* start it */
        if (task->entry) {
-               name[0] = '\000';
-               if (task->task_name[0] != '\000') {
-                       snprintf(name, sizeof(name) -1, " (%s)", task->task_name);
-                       name[sizeof(name) - 1] = '\000';
-               }
-               dprintf(INFO, "starting task#%u%s\n", task->task_index, name);
+               dprintf(INFO, "starting %s task#%u%s\n", state_str, task->task_index,
+                       task_get_name_str(task, " (", ")", name, sizeof(name)));
+
                thread_resume(thread);
        }
 
@@ -898,6 +937,8 @@ status_t task_init_one_task(task_t *task, u_int task_type)
 
 /*
  * Start static tasks initialized by task_early_init()
+ *
+ * Convert the boot time task_blist into run-time task_list.
  */
 void task_init()
 {
@@ -905,72 +946,125 @@ void task_init()
        task_t *task;
        u_int i;
 
-       for (i = 0, task = task_list; i < task_count; i++, task++) {
-               err = task_init_one_task(task, TASK_TYPE_STATIC);
+       task_image_start = NULL;
+       task_image_end   = NULL;
+       task_image_size  = 0;
+
+       list_initialize(&task_list);
+
+       /* convert the boot time task_blist into a run-time task_list */
+
+       for (i = 0, task = task_blist; i < task_next_index; i++, task++) {
+               task_t *taskp = malloc(sizeof(task_t));
+               if (!taskp) {
+                       dprintf(CRITICAL, "%s: out of memory -- halting\n", __func__);
+                       halt();
+               }
+               memcpy(taskp, task, sizeof(task_t));
+
+               err = task_init_one_task(taskp);
                if (err != NO_ERROR) {
                        dprintf(CRITICAL, "%s: static task start failed %d -- halting\n",
                                __func__, err);
                        halt();
                }
+
+               list_add_tail(&task_list, &taskp->node);
        }
 
+       /* boot time task header pages are no longer used */
+       memset(task_blist, 0, TASK_LIST_CARVEOUT_PAGES * PAGE_SIZE);
+       task_blist = NULL;
+
+       task_unload_init();
        task_load_init();
 }
 
 task_t *task_find_task_by_uuid(te_service_id_t *uuid)
 {
        task_t *task = NULL;
-       u_int i = 0;
 
        /* find task for this uuid */
        if (uuid) {
-               for (i = 0, task = task_list; i < task_count; i++, task++) {
-                       if (task->task_state == TASK_STATE_ACTIVE ||
-                           task->task_state == TASK_STATE_INIT) {
+               list_for_every_entry(&task_list, task, task_t, node) {
+                       if (task->task_state != TASK_STATE_UNKNOWN) {
                                if (!memcmp(&task->props.uuid, uuid, sizeof(te_service_id_t))) {
-                                       break;
+                                       return task;
                                }
                        }
                }
-               if (i == task_count)
-                       return NULL;
        }
-       return task;
+       return NULL;
 }
 
 task_t *task_find_task_by_index(uint32_t index)
 {
-       if (index >= task_count)
+       task_t *task = NULL;
+
+       if (index >= task_next_index)
                return NULL;
 
-       return &task_list[index];
+       list_for_every_entry(&task_list, task, task_t, node) {
+               if (task->task_state != TASK_STATE_UNKNOWN) {
+                       if (task->task_index == index) {
+                               return task;
+                       }
+               }
+       }
+       return NULL;
+}
+
+const char *task_get_name_str(const task_t *task, const char *prefix, const char *suffix,
+                             char *buf, uint32_t buflen)
+{
+       uint32_t pslen = 0;
+
+       if (prefix)
+               pslen += strlen(prefix);
+       else
+               prefix = "";
+
+       if (suffix)
+               pslen += strlen(suffix);
+       else
+               suffix = "";
+
+       /* OTE_TASK_NAME_MAX_LENGTH includes the NUL character at end of task name */
+       if (!task || !buf || buflen < (OTE_TASK_NAME_MAX_LENGTH + pslen) ||
+           !task->task_name[0])
+               return "";
+
+       snprintf(buf, buflen, "%s%s%s", prefix, task->task_name, suffix);
+       return buf;
 }
 
 void
 task_print_uuid(uint32_t level, const char *prefix, const task_t *taskp)
 {
        if (taskp) {
+               char tp_name[OTE_TASK_NAME_MAX_LENGTH+3];
                const te_service_id_t *uuid = &taskp->props.uuid;
 
-               dprintf(level, "%s%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x\n",
-                        (prefix    ? prefix    : ""),
-                        uuid->time_low,
-                        uuid->time_mid,
-                        uuid->time_hi_and_version,
-                        uuid->clock_seq_and_node[0],   /* clock_seq_hi_and_reserved */
-                        uuid->clock_seq_and_node[1],   /* clock_seq_low */
-                        uuid->clock_seq_and_node[2],
-                        uuid->clock_seq_and_node[3],
-                        uuid->clock_seq_and_node[4],
-                        uuid->clock_seq_and_node[5],
-                        uuid->clock_seq_and_node[6],
-                        uuid->clock_seq_and_node[7]);
+               dprintf(level, "%s%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x%s\n",
+                       (prefix    ? prefix     : ""),
+                       uuid->time_low,
+                       uuid->time_mid,
+                       uuid->time_hi_and_version,
+                       uuid->clock_seq_and_node[0],    /* clock_seq_hi_and_reserved */
+                       uuid->clock_seq_and_node[1],    /* clock_seq_low */
+                       uuid->clock_seq_and_node[2],
+                       uuid->clock_seq_and_node[3],
+                       uuid->clock_seq_and_node[4],
+                       uuid->clock_seq_and_node[5],
+                       uuid->clock_seq_and_node[6],
+                       uuid->clock_seq_and_node[7],
+                       task_get_name_str(taskp, " (", ")", tp_name, sizeof(tp_name)));
        }
 }
 
 /*
  * This is only used by task loading code but placed here because it modifies
- * task_count and the task_list when a new task is loaded.
+ * task_next_index and the task_list when a new task is loaded.
  */
 status_t task_register(task_t **task_p)
 {
@@ -982,58 +1076,66 @@ status_t task_register(task_t **task_p)
                goto exit;
        }
 
+       dtask = malloc(sizeof(task_t));
+       if (!dtask) {
+               err = ERR_NO_MEMORY;
+               dprintf(CRITICAL, "error allocating task header: 0x%x\n", err);
+               goto exit;
+       }
+
+       memcpy(dtask, *task_p, sizeof(task_t));
+
        enter_critical_section();
 
        do {
-               if ((task_count + 1) >= MAX_TASK_COUNT) {
-                       err = ERR_TOO_MANY_TASKS;
-                       break;
-               }
-
                /*
-                * Make sure UUID doesn't already exist.  Note that
-                * this search won't include the task we are processing
-                * here because task_count hasn't been incremented yet.
+                * Make sure UUID doesn't already exist.
                 */
-               if (task_find_task_by_uuid(&(*task_p)->props.uuid) != NULL) {
+               if (task_find_task_by_uuid(&dtask->props.uuid) != NULL) {
                        err = ERR_ALREADY_EXISTS;
                        break;
                }
 
-               /* Committed here */
-               dtask = &task_list[task_count];
+               /* Current task index now reserved for this task */
+               dtask->task_index = task_next_index++;
 
-               /* task list entry reserved for this task */
-               (*task_p)->task_index = task_count++;
+               list_add_tail(&task_list, &dtask->node);
        } while (0);
 
        exit_critical_section();
 
-       if (dtask) {
-               memcpy(dtask, *task_p, sizeof(task_t));
+       if (err != NO_ERROR)
+               goto exit;
 
-               /* clear the input task arg (not to be used anymore) */
-               memset(*task_p, 0, sizeof(task_t));
+       memset(*task_p, 0, sizeof(task_t));
 
-               /* *task_p is now an entry from the task list */
-               *task_p = dtask;
-       }
+       /* swap *task_p to point to the registered object */
+       *task_p = dtask;
 
-exit:
+       if (0) {
+       exit:
+               if (dtask)
+                       free(dtask);
+       }
        return err;
 }
 
-const task_t *task_get_list()
-{
-       return (const task_t *)task_list;
-}
-
 u_int task_get_count()
 {
-       return task_count;
+       return task_next_index;
 }
 
-u_int task_get_max_count()
+u_int task_get_active_count()
 {
-       return MAX_TASK_COUNT;
+       task_t *task = NULL;
+       int count = 0;
+
+       list_for_every_entry(&task_list, task, task_t, node) {
+               if ((task->task_state != TASK_STATE_UNKNOWN) &&
+                   (task->task_state != TASK_STATE_TERMINATED) &&
+                   (task->task_state != TASK_STATE_INIT)) {
+                       count++;
+               }
+       }
+       return count;
 }