tlk: 6/19 update
[3rdparty/ote_partner/tlk.git] / kernel / task_load.c
index 9cbc608..54d8d94 100644 (file)
  */
 #include <debug.h>
 #include <sys/types.h>
-#include <compiler.h>
 #include <assert.h>
 #include <string.h>
 #include <malloc.h>
 #include <err.h>
 #include <errno.h>
 #include <stdlib.h>
-#include <arch.h>
-#include <arch/arm.h>
-#include <arch/arm/mmu.h>
 #include <kernel/task.h>
 #include <kernel/thread.h>
-#include <kernel/elf.h>
-#include <platform.h>
-#include <platform/platform_p.h>
 #include <kernel/task_load.h>
 #include <lib/heap.h>
 
 #include <lib/ote/ote_protocol.h>
 
 #ifndef TASK_HEAP_PERCENTAGE
-
 /*
  * Max 60% of heap can be used for task loading.
  * Define as 0 to disable task loading.
  */
 #define TASK_HEAP_PERCENTAGE 60
-
 #endif /* TASK_HEAP_PERCENTAGE */
 
 #ifndef TASK_HEAP_PAGES_RESERVED
 #define TASK_HEAP_PAGES_MIN    20
 #endif /* TASK_HEAP_PAGES_MIN */
 
-/* pending task states (before task is fully loaded) */
+/* Pending task-load states (before task is fully loaded)
+ *
+ * The tp_state_t defines the internal states of the state machine used
+ * for the multi-step task loading operation. Once completed or on error
+ * the associated task_pending_t node will be deleted and the task be
+ * either installed or rejected.
+ */
 typedef enum {
-       TASK_PSTATE_UNDEFINED,
-       TASK_PSTATE_INVALID,
-       TASK_PSTATE_MEMBUF,
-       TASK_PSTATE_TA_MAPPED,
-       TASK_PSTATE_TA_UNMAPPED,
-       TASK_PSTATE_PREPARED,
-       TASK_PSTATE_READY
+       TASK_PSTATE_UNDEFINED,   /* uninitialized */
+       TASK_PSTATE_INVALID,     /* allocated, undefined */
+       TASK_PSTATE_MEMBUF,      /* memory allocated for task */
+       TASK_PSTATE_TA_MAPPED,   /* shared buffer mapped for copying task image */
+       TASK_PSTATE_TA_UNMAPPED, /* shared buffer unmapped; task image copied */
+       TASK_PSTATE_PREPARED,    /* task parsed */
+       TASK_PSTATE_READY        /* task started (pending node deallocated) */
 } tp_state_t;
 
 /*
- * Loaded tasks pending activation.
- * Activated tasks are removed from this list.
+ * Each task loading operation will get a pending node associated with it.
+ * The node exists only during the load process.
+ *
+ * Completed/rejected task installs are removed from this list and the pending node
+ * gets deleted.
  */
 typedef struct {
        uint32_t        tp_handle;
@@ -115,6 +115,8 @@ static u_int task_heap_percentage = TASK_HEAP_PERCENTAGE;
 static vaddr_t original_heap_start;
 static vaddr_t original_heap_end;
 
+static uint32_t task_load_counter;
+
 void task_load_config(vaddr_t vaddr_begin, vaddr_t *vaddr_end_p)
 {
        u_int heap_pages = 0;
@@ -174,7 +176,7 @@ void task_load_init()
 
 u_int task_allowed_to_load_tasks(task_t *taskp)
 {
-       return (taskp && (taskp->props.install_priv & OTE_INSTALL_AUTHORIZED));
+       return (taskp && (taskp->props.authorizations & OTE_AUTHORIZE_INSTALL));
 }
 
 static void task_add_new_pending(task_pending_t *tp, vaddr_t addr, uint32_t size,
@@ -348,12 +350,12 @@ status_t task_request_app_load_memory(u_int byte_size, uint32_t *handle_p)
        }
        memset((void *)load_addr, 0, npages * PAGE_SIZE);
 
-       tp = malloc(sizeof (task_pending_t));
+       tp = malloc(sizeof(task_pending_t));
        if (!tp) {
                err = ERR_NO_MEMORY;
                goto exit;
        }
-       memset(tp, 0, sizeof (task_pending_t));
+       memset(tp, 0, sizeof(task_pending_t));
 
        /* check for an upper limit for heap allocation for task loading */
        enter_critical_section();
@@ -397,6 +399,25 @@ status_t task_request_app_load_memory(u_int byte_size, uint32_t *handle_p)
        return err;
 }
 
+void task_dealloc_memory(vaddr_t vaddr, u_int task_byte_size)
+{
+       u_int npages = 0;
+
+       ASSERT(vaddr);
+       ASSERT(task_byte_size > 0);
+       ASSERT(original_heap_start <= vaddr && vaddr <= original_heap_end);
+
+       npages = ROUNDUP(task_byte_size, PAGE_SIZE) / PAGE_SIZE;
+
+       ASSERT(task_pages_heap_used >= npages);
+
+       heap_free((void *)vaddr);
+
+       enter_critical_section();
+       task_pages_heap_used -= npages;
+       exit_critical_section();
+}
+
 static status_t task_dealloc_app_load_memory_tp(task_pending_t *tp)
 {
        status_t err = NO_ERROR;
@@ -418,19 +439,9 @@ static status_t task_dealloc_app_load_memory_tp(task_pending_t *tp)
                goto exit;
        }
 
-       npages = ROUNDUP(byte_size, PAGE_SIZE) / PAGE_SIZE;
-
-       ASSERT (task_pages_heap_used >= npages);
-
-       heap_free ((void *)vaddr);
-
-       enter_critical_section();
-
-       if (task_pages_heap_used >= npages)
-               task_pages_heap_used -= npages;
-
-       exit_critical_section();
+       task_dealloc_memory(vaddr, byte_size);
 
+       npages = ROUNDUP(byte_size, PAGE_SIZE) / PAGE_SIZE;
        if (used_pages < npages)
                dprintf(INFO, "TASK MEM (handle 0x%x) dealloc INCONSISTENCY => task addr 0x%x (%d pages) [tasks pages used %d]\n",
                        tp->tp_handle, (uint32_t)vaddr, npages, used_pages);
@@ -485,12 +496,12 @@ static status_t task_property_override(task_t *taskp, task_restrictions_t *tr)
        status_t err = NO_ERROR;
        uint32_t size;
 
-       if (!tr) {
+       if (!taskp || !tr) {
                err = ERR_TASK_GENERIC;
                goto exit;
        }
 
-       if ((taskp->props.immutable & OTE_MANIFEST_IMMUTABLE) == 0) {
+       if ((taskp->props.initial_state & OTE_MANIFEST_TASK_ISTATE_IMMUTABLE) == 0) {
                if (tr->min_stack_size > 0) {
                        size = ROUNDUP(tr->min_stack_size, PAGE_SIZE);
                        taskp->props.min_stack_size = size;
@@ -561,9 +572,9 @@ static status_t task_unmap_app_mem_from_ta(task_t *taskp, uint32_t handle)
        }
 
        arch_task_unmap_memory(taskp, mptr);
-       dprintf (SPEW,
-                "Unmapped task map memory <0%08lx, %d bytes> from the calling task\n",
-                tp->tp_task_ta_addr, tp->tp_task_size);
+       dprintf(SPEW,
+               "Unmapped task map memory <0%08lx, %d bytes> from the calling task\n",
+               tp->tp_task_ta_addr, tp->tp_task_size);
 
        task_push_pending(tp, TASK_PSTATE_TA_UNMAPPED);
 
@@ -594,19 +605,19 @@ static void task_get_config(task_info_t *ti, task_t *taskp)
 
                TASK_COPY_PROPERTY(ti,taskp,manifest_exists);
                TASK_COPY_PROPERTY(ti,taskp,multi_instance);
-               TASK_COPY_PROPERTY(ti,taskp,immutable);
                TASK_COPY_PROPERTY(ti,taskp,min_stack_size);
                TASK_COPY_PROPERTY(ti,taskp,min_heap_size);
                TASK_COPY_PROPERTY(ti,taskp,map_io_mem_cnt);
                TASK_COPY_PROPERTY(ti,taskp,restrict_access);
-               TASK_COPY_PROPERTY(ti,taskp,install_priv);
+               TASK_COPY_PROPERTY(ti,taskp,authorizations);
+               TASK_COPY_PROPERTY(ti,taskp,initial_state);
 
 #undef TASK_COPY_PROPERTY
 
                memcpy(ti->task_name, taskp->task_name,
                       sizeof(taskp->task_name));
 
-               ti->task_name[sizeof (ti->task_name) - 1] = '\000';
+               ti->task_name[sizeof(ti->task_name) - 1] = '\000';
 
                memcpy(ti->task_private_data, taskp->task_private_data,
                       sizeof(taskp->task_private_data));
@@ -637,7 +648,7 @@ static status_t task_parse_app(uint32_t handle, task_info_t *ti)
 
        /* prepare task based on static app data in buffer */
        err = task_prepare((char *)tp->tp_task_tlk_addr, tp->tp_task_size,
-                          &tp->tp_task, NULL);
+                          &tp->tp_task, NULL, TASK_TYPE_LOADED);
        if (err != NO_ERROR) {
                dprintf(CRITICAL, "%s: loaded task preparation failed (%d)\n",
                        __func__, err);
@@ -666,8 +677,6 @@ static status_t task_parse_app(uint32_t handle, task_info_t *ti)
 }
 
 /* @brief Start loaded application with manifest restrictions at step#3/3.
- *
- * If manifest is immutable restriction values are ignored.
  */
 static status_t task_run_app(uint32_t handle, uint32_t reject_task, task_restrictions_t *tr)
 {
@@ -720,7 +729,7 @@ static status_t task_run_app(uint32_t handle, uint32_t reject_task, task_restric
                 */
                err = task_property_override(taskp, tr);
                if (err != NO_ERROR) {
-                       dprintf(CRITICAL, "%s: task install 0x%x blocked by override error %d\n",
+                       dprintf(CRITICAL, "%s: task install 0x%x rejected by override error %d\n",
                                __func__, handle, err);
                        goto exit;
                }
@@ -736,9 +745,11 @@ static status_t task_run_app(uint32_t handle, uint32_t reject_task, task_restric
                }
 
                /*
-                * Atomically commit task (and assign the index) to the known task list
+                * Atomically commit task (and assign the index) to the known task_list
                 * unless there is an error. TASKP value swapped to track the registered
                 * task header (old object is cleared in the call).
+                *
+                * tp->tp_task is cleared by task_register.
                 */
                err = task_register(&taskp);
 
@@ -750,37 +761,35 @@ static status_t task_run_app(uint32_t handle, uint32_t reject_task, task_restric
 
                task_registered++;
 
-               {
-                       const task_t *task_list = task_get_list();
-
-                       /* taskp now points to an entry in the carve out task list */
-                       ASSERT(task_list);
-                       ASSERT(taskp == &task_list[taskp->task_index]);
-               }
-
                /*
-                * Init task and start it (flagged as post-loaded)
-                *
-                * XXX NOTE:
-                * Failing here leaks memory as task terminating/releasing
-                * resources at this point is not supported (yet).
-                *
-                * Resources may be allocated for stack, heap, address map,
-                * thread, etc...
+                * Init task and start it
                 */
-               err = task_init_one_task(taskp, TASK_TYPE_LOADED);
+               err = task_init_one_task(taskp);
                if (err != NO_ERROR) {
-                       dprintf(CRITICAL, "%s: loaded task %d init failed (%d)\n",
-                               __func__, task_get_count(), err);
+                       status_t err2 = NO_ERROR;
+                       uint32_t tindex = taskp->task_index;
+
+                       dprintf(CRITICAL, "Loaded task#%u init failed (0x%x), unloading...\n",
+                               tindex, err);
+
+                       err2 = task_unload(&taskp);
+                       if (err2 != NO_ERROR) {
+                               dprintf(CRITICAL, "Unloading the failed task#%u failed: (0x%x)\n",
+                                       tindex, err2);
+                       }
                        goto exit;
                }
 
-               /*
-                * Already removed from pending task list and now junked
-                * because task is now active
-                */
+               task_load_counter++;
        }
 
+       /*
+        * Already removed from pending task list and now junked
+        * because task is now active.
+        *
+        * Just for completeness, advance the state machine before killing object.
+        */
+       tp->tp_state = TASK_PSTATE_READY;
        free(tp);
        tp = NULL;
 
@@ -818,33 +827,42 @@ void task_set_name(task_t *task, const char *name)
 extern int _end;
 extern int _heap_end;
 
-/* debug: print info of heap sizes and task load space to console */
-void task_system_info()
+/* debug: print system info to console.
+ *
+ * For R&D only, should disable from production builds.
+ */
+void task_system_info(te_system_info_args_t *args)
 {
+       if (args->si_type == 41) {
+               dprintf(INFO, "Kernel thread dump:\n");
+               dump_all_threads();
+       } else {
+
 #define HEAP_LEN ((u_int)_heap_end - (u_int)&_end)
 
-       dprintf(INFO, "HEAP start (orig): 0x%x\n", (u_int)original_heap_start);
-       dprintf(INFO, "HEAP end   (orig): 0x%x\n", (u_int)original_heap_end);
+               dprintf(INFO, "HEAP start (orig): 0x%x\n", (u_int)original_heap_start);
+               dprintf(INFO, "HEAP end   (orig): 0x%x\n", (u_int)original_heap_end);
 
-       dprintf(INFO, "HEAP start (end of binary == &_end) %p\n", &_end);
-       dprintf(INFO, "HEAP end (end_of_memory == _heap_end) %p\n",
-               (void *)_heap_end);
-       dprintf(INFO, "HEAP size (_heap_end-&_end)=%u (0x%x) bytes\n",
-               HEAP_LEN, HEAP_LEN);
+               dprintf(INFO, "HEAP start (end of binary == &_end) %p\n", &_end);
+               dprintf(INFO, "HEAP end (end_of_memory == _heap_end) %p\n",
+                       (void *)_heap_end);
+               dprintf(INFO, "HEAP size (_heap_end-&_end)=%u (0x%x) bytes\n",
+                       HEAP_LEN, HEAP_LEN);
 
-       dprintf(INFO, "TASK_INFO: Max task count: %d\n",
-               task_get_max_count());
+               dprintf(INFO, "Number of active tasks: %d\n",
+                       task_get_active_count());
 
-       dprintf(INFO, "TASK_INFO: number of tasks: %d\n",
-               task_get_count());
+               dprintf(INFO, "sizeof(task_t): %d bytes\n", sizeof(task_t));
 
-       dprintf(INFO, "TASK_INFO: sizeof(task_t): %d\n", sizeof(task_t));
+               dprintf(INFO, "Heap pages used for tasks: %d\n", task_pages_heap_used);
 
-       dprintf(INFO, "HEAP pages used for tasks: %d\n", task_pages_heap_used);
+               dprintf(INFO, "Heap pages for tasks: left %d (out of %d)\n",
+                       task_pages_heap_max - task_pages_heap_used,
+                       task_pages_heap_max);
 
-       dprintf(INFO, "HEAP pages for tasks: left %d (out of %d)\n",
-               task_pages_heap_max - task_pages_heap_used,
-               task_pages_heap_max);
+               dprintf(INFO, "Tasks loaded since boot: %u\n", task_load_counter);
+               dprintf(INFO, "Tasks unloaded since boot: %u\n", task_get_unload_counter());
+       }
 }
 #endif /* DEBUG */
 
@@ -862,7 +880,7 @@ static int tlk_handle_app_memory_request(te_app_load_memory_request_args_t *args
        dprintf(SPEW, "%s: mem request app size %d bytes\n",
                __func__, args->app_size);
 
-       task_print_uuid(INFO, "Map task memory request by UUID ", taskp);
+       task_print_uuid(INFO, "Map task memory request by ", taskp);
 
        /*
         * Simple manifest based permission allowing a task to install
@@ -928,8 +946,8 @@ static void map_task_info_to_te(te_task_info_t *to, task_info_t *from)
                TASK_COPY_PROPERTY(to,from,min_heap_size);
                TASK_COPY_PROPERTY(to,from,map_io_mem_cnt);
                TASK_COPY_PROPERTY(to,from,restrict_access);
-               TASK_COPY_PROPERTY(to,from,install_priv);
-               TASK_COPY_PROPERTY(to,from,immutable);
+               TASK_COPY_PROPERTY(to,from,authorizations);
+               TASK_COPY_PROPERTY(to,from,initial_state);
 
 #undef TASK_COPY_PROPERTY
 
@@ -971,7 +989,7 @@ static int tlk_handle_app_prepare(te_app_prepare_args_t *args)
        /*
         * Parse application
         */
-       memset(&ti, 0, sizeof (ti));
+       memset(&ti, 0, sizeof(ti));
        err = task_parse_app(args->app_handle, &ti);
        if (err != NO_ERROR) {
                dprintf(INFO, "Could parse loaded application (%d)\n", err);
@@ -983,6 +1001,109 @@ static int tlk_handle_app_prepare(te_app_prepare_args_t *args)
        return 0;
 }
 
+static int get_manifest_mapping(task_t *task, te_memory_mapping_t *map)
+{
+       u_int i = 0;
+       u_int found     = 0;
+       u_int map_index = 0;
+
+       if (! task || ! map)
+               return -EINVAL;
+
+       for (i = 0; i < task->props.config_entry_cnt; i++) {
+               if (task->props.config_blob[i] == OTE_CONFIG_KEY_MAP_MEM) {
+                       if (map_index == map->map_index) {
+
+                               /* found the specified mapping by index */
+                               map->map_id     = task->props.config_blob[++i];
+                               map->map_offset = task->props.config_blob[++i];
+                               map->map_size   = task->props.config_blob[++i];
+
+                               found++;
+                               break;
+                       } else {
+                               /* wrong mapping, skip the 3 fields */
+                               i += 3;
+                       }
+
+                       map_index++;
+               } else {
+                       /* all other config options take 1 data value */
+                       i++;
+               }
+       }
+
+       if (!found)
+               return -ESRCH;
+
+       return 0;
+}
+
+/*
+ * Add an API to fetch the manifest mappings from a pending task using its handle
+ * (i.e. when task is being loaded).
+ *
+ * This is an installer only API to enable decisions if the task
+ * needs to be rejected due to unauthorized memory mappings. The caller must
+ * reject the task on error, this routine does not do it.
+ */
+static int tlk_get_pending_mapping(te_get_pending_map_args_t *args)
+{
+       int rval = 0;
+       task_t *taskp = current_thread->arch.task;
+       task_pending_t *tp = NULL;
+
+       if (!args)
+               return -EINVAL;
+
+       if (!task_allowed_to_load_tasks(taskp)) {
+               task_print_uuid(CRITICAL, "Client tried to perform "
+                               "an operation for which they are "
+                               "not permitted ", taskp);
+               rval = -EACCES;
+               goto exit;
+       }
+
+       tp = task_find_pending(args->pm_handle);
+       if (!tp) {
+               dprintf(SPEW, "%s: task handle unknown 0x%x\n",
+                       __func__, args->pm_handle);
+               rval = -ENOENT;
+               goto exit;
+       }
+
+       /* Do not reject task when fetching a non-existent mapping.
+        * Just return a not found error but allow install to proceed or
+        * installer to reject the task.
+        */
+       if (tp->tp_state != TASK_PSTATE_PREPARED) {
+               dprintf(INFO, "%s: task handle 0x%x in wrong state: %d\n",
+                       __func__, args->pm_handle, tp->tp_state);
+               rval = -EINVAL;
+       } else if (tp->tp_task.props.map_io_mem_cnt < (args->pm_map.map_index + 1)) {
+               dprintf(INFO, "Task manifest does not contain %d memory mappings",
+                       args->pm_map.map_index + 1);
+               rval = -ESRCH;
+       } else {
+               if (get_manifest_mapping(&tp->tp_task, &args->pm_map)) {
+                       dprintf(INFO, "Task manifest does not contain mapping at index %d",
+                               args->pm_map.map_index);
+                       rval = -ESRCH;
+               }
+       }
+
+       task_push_pending(tp, tp->tp_state);
+
+exit:
+       return rval;
+}
+
+/*
+ * Copy selected non-security related fields that the installer wants
+ * to enforce to the task when it starts. Zero field values are not-used.
+ *
+ * This is just a type mapping, properties are set later in task_property_override.
+ */
 static void map_task_app_restrictions(task_restrictions_t *to,
                                      te_task_restrictions_t *from)
 {
@@ -991,12 +1112,6 @@ static void map_task_app_restrictions(task_restrictions_t *to,
 
        if (from && to) {
 
-               /*
-                * Copy selected non-security related fields
-                * that the installer wants to enforce to the task
-                * when it starts. Zero field values indicate "not-used"
-                * and are ignored.
-                */
                to->min_stack_size = from->min_stack_size;
                to->min_heap_size = from->min_heap_size;
 
@@ -1051,6 +1166,7 @@ static int tlk_list_apps(te_app_list_args_t *args)
 {
        task_t *taskp   = current_thread->arch.task;
        task_t *task    = NULL;
+       task_info_t ti;
 
        if (!args)
                return -EINVAL;
@@ -1062,23 +1178,29 @@ static int tlk_list_apps(te_app_list_args_t *args)
                return -EACCES;
        }
 
-       memset(&args->app_uuid, 0, sizeof(te_service_id_t));
-       memset(&args->app_name[0], 0, sizeof (args->app_name));
+       args->app_type = TASK_TYPE_UNKNOWN;
+       args->app_state = TASK_STATE_UNKNOWN;
+       memset(&args->app_info, 0, sizeof(args->app_info));
 
-       /*
-        * Otherwise copy the UUID of the specified task to the
-        * IOCTL argument.
-        */
-       task = task_find_task_by_index(args->app_index);
-       if (!task)
+       /* task at this or any larger index does not exist */
+       if (args->app_index > task_get_count())
                return -ENOENT;
 
-       memcpy(&args->app_uuid, &task->props.uuid,
-              sizeof(te_service_id_t));
+       task = task_find_task_by_index(args->app_index);
+       if (!task) {
+               /* task at index does not exist */
+               return -ESRCH;
+       }
 
-       if (task->task_name[0])
-               memcpy(&args->app_name[0], &task->task_name[0],
-                      sizeof(task->task_name));
+       /*
+        * Otherwise set up the UUID and other info of the specified task to the
+        * IOCTL result.
+        */
+       args->app_type = task->task_type;
+       args->app_state = task->task_state;
+
+       task_get_config(&ti, task);
+       map_task_info_to_te(&args->app_info, &ti);
 
        return 0;
 }
@@ -1105,6 +1227,10 @@ static int tlk_task_get_info(te_get_task_info_t *args)
 
        switch (args->gti_request_type) {
        case OTE_GET_TASK_INFO_REQUEST_INDEX:
+               /* task at this or any larger index does not exist */
+               if (args->gtiu_index > task_get_count())
+                       return -ENOENT;
+
                task = task_find_task_by_index(args->gtiu_index);
                break;
        case OTE_GET_TASK_INFO_REQUEST_UUID:
@@ -1121,13 +1247,210 @@ static int tlk_task_get_info(te_get_task_info_t *args)
        if (!task)
                return -ENOENT;
 
-       memset(&ti, 0, sizeof (ti));
+       memset(&ti, 0, sizeof(ti));
        task_get_config(&ti, task);
+
+       args->gti_state = task->task_state;
        map_task_info_to_te(&args->gti_info, &ti);
 
        return 0;
 }
 
+static int tlk_task_get_mapping(te_get_task_mapping_t *args)
+{
+       task_t *taskp   = current_thread->arch.task;
+       task_t *task    = NULL;
+
+       if (!args)
+               return -EINVAL;
+
+       /* Any task is authorized to fetch it's own mapping information (SELF).
+        * Installers are authorized to fetch it from any task.
+        */
+       if (!task_allowed_to_load_tasks(taskp) &&
+           (args->gmt_request_type != OTE_GET_TASK_INFO_REQUEST_SELF)) {
+               task_print_uuid(CRITICAL, "Client tried to perform "
+                               "an operation for which they are "
+                               "not permitted ", taskp);
+               return -EACCES;
+       }
+
+       switch (args->gmt_request_type) {
+       case OTE_GET_TASK_INFO_REQUEST_INDEX:
+               /* task at this or any larger index does not exist */
+               if (args->gmtu_index > task_get_count())
+                       return -ENOENT;
+
+               task = task_find_task_by_index(args->gmtu_index);
+               break;
+       case OTE_GET_TASK_INFO_REQUEST_UUID:
+               task = task_find_task_by_uuid(&args->gmtu_uuid);
+               break;
+       case OTE_GET_TASK_INFO_REQUEST_SELF:
+               task = taskp;
+               break;
+       default:
+               task = NULL;
+               break;
+       }
+
+       if (!task)
+               return -ENOENT;
+
+       return get_manifest_mapping(task, &args->gmt_map);
+}
+
+static int tlk_task_unload(te_app_unload_args_t *args)
+{
+       status_t err  = NO_ERROR;
+       task_t *taskp = current_thread->arch.task;
+       task_t *target_task = NULL;
+
+       if (!args)
+               return -EINVAL;
+
+       if (!task_allowed_to_load_tasks(taskp)) {
+               task_print_uuid(CRITICAL, "Client tried to perform "
+                               "an operation for which they are "
+                               "not permitted ", taskp);
+               return -EACCES;
+       }
+
+       switch (args->tid_type) {
+       case OTE_APP_ID_INDEX:
+               /* task at this or any larger index does not exist */
+               if (args->tid_index > task_get_count())
+                       return -ENOENT;
+
+               target_task = task_find_task_by_index(args->tid_index);
+               break;
+       case OTE_APP_ID_UUID:
+               target_task = task_find_task_by_uuid(&args->tid_uuid);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!target_task)
+               return -ESRCH;
+
+       task_print_uuid(INFO, "Request to unload task ", target_task);
+
+       err = task_unload(&target_task);
+       if (err != NO_ERROR) {
+               switch (err) {
+               case ERR_NOT_FOUND:   return -ENOENT;
+               case ERR_NOT_ALLOWED: return -EACCES;
+               default: return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Block an active task so it does not accept new sessions.
+ *
+ * Note that after blocking the last task which has installer privileges
+ * you can no longer unblock any blocked tasks in the system.
+ */
+static int tlk_task_block(te_app_block_args_t *args)
+{
+       task_t *taskp = current_thread->arch.task;
+       task_t *target_task  = NULL;
+
+       if (!args)
+               return -EINVAL;
+
+       if (!task_allowed_to_load_tasks(taskp)) {
+               task_print_uuid(CRITICAL, "Client tried to perform "
+                               "an operation for which they are "
+                               "not permitted ", taskp);
+               return -EACCES;
+       }
+
+       switch (args->tid_type) {
+       case OTE_APP_ID_INDEX:
+               /* task at this or any larger index does not exist */
+               if (args->tid_index > task_get_count())
+                       return -ENOENT;
+
+               target_task = task_find_task_by_index(args->tid_index);
+               break;
+       case OTE_APP_ID_UUID:
+               target_task = task_find_task_by_uuid(&args->tid_uuid);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!target_task)
+               return -ESRCH;
+
+       switch(target_task->task_state) {
+       case TASK_STATE_BLOCKED:
+       case TASK_STATE_ACTIVE:
+               target_task->task_state = TASK_STATE_BLOCKED;
+               task_print_uuid(INFO, "Blocked task ", target_task);
+               break;
+       default:
+               dprintf(INFO, "Request to block task#%d in state %d -- rejected\n",
+                       target_task->task_index,
+                       target_task->task_state);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tlk_task_unblock(te_app_block_args_t *args)
+{
+       task_t *taskp = current_thread->arch.task;
+       task_t *target_task  = NULL;
+
+       if (!args)
+               return -EINVAL;
+
+       if (!task_allowed_to_load_tasks(taskp)) {
+               task_print_uuid(CRITICAL, "Client tried to perform "
+                               "an operation for which they are "
+                               "not permitted ", taskp);
+               return -EACCES;
+       }
+
+       switch (args->tid_type) {
+       case OTE_APP_ID_INDEX:
+               /* task at this or any larger index does not exist */
+               if (args->tid_index > task_get_count())
+                       return -ENOENT;
+
+               target_task = task_find_task_by_index(args->tid_index);
+               break;
+       case OTE_APP_ID_UUID:
+               target_task = task_find_task_by_uuid(&args->tid_uuid);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!target_task)
+               return -ESRCH;
+
+       switch(target_task->task_state) {
+       case TASK_STATE_BLOCKED:
+               target_task->task_state = TASK_STATE_ACTIVE;
+               task_print_uuid(INFO, "Unblocked task ", target_task);
+               break;
+       default:
+               dprintf(INFO, "Request to unblock task#%d in state %d -- rejected\n",
+                       target_task->task_index,
+                       target_task->task_state);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /*
  * Called by syscall OTE_IOCTL_TASK_REQUEST ioctl handler
  */
@@ -1149,6 +1472,10 @@ int task_request_handler(te_task_request_args_t *args)
                retval = tlk_handle_app_prepare(&args->ia_prepare);
                break;
 
+       case OTE_TASK_OP_PENDING_MAPPING:
+               retval = tlk_get_pending_mapping(&args->ia_pending_mapping);
+               break;
+
        case OTE_TASK_OP_START:
                retval = tlk_handle_app_start(&args->ia_start);
                break;
@@ -1161,12 +1488,29 @@ int task_request_handler(te_task_request_args_t *args)
                retval = tlk_task_get_info(&args->ia_get_task_info);
                break;
 
+       case OTE_TASK_OP_GET_MAPPING:
+               /* much like pending mapping above, but for existing tasks */
+               retval = tlk_task_get_mapping(&args->ia_get_task_mapping);
+               break;
+
 #ifdef DEBUG
        case OTE_TASK_OP_SYSTEM_INFO:
-               task_system_info();
+               task_system_info(&args->ia_system_info);
                break;
 #endif
 
+       case OTE_TASK_OP_UNLOAD:
+               retval = tlk_task_unload(&args->ia_app_unload);
+               break;
+
+       case OTE_TASK_OP_BLOCK:
+               retval = tlk_task_block(&args->ia_app_block);
+               break;
+
+       case OTE_TASK_OP_UNBLOCK:
+               retval = tlk_task_unblock(&args->ia_app_block);
+               break;
+
        default:
                retval = -EINVAL;
                break;