Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <inttypes.h>
     18 #include <stdarg.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 
     22 #include <plat/eeData.h>
     23 #include <plat/plat.h>
     24 #include <plat/wdt.h>
     25 
     26 #include <apInt.h>
     27 #include <atomic.h>
     28 #include <bl.h>
     29 #include <cpu.h>
     30 #include <crc.h>
     31 #include <eventQ.h>
     32 #include <heap.h>
     33 #include <hostIntf.h>
     34 #include <mpu.h>
     35 #include <nanohubPacket.h>
     36 #include <osApi.h>
     37 #include <platform.h>
     38 #include <printf.h>
     39 #include <sensors.h>
     40 #include <seos.h>
     41 #include <seos_priv.h>
     42 #include <slab.h>
     43 #include <syscall.h>
     44 #include <timer.h>
     45 #include <util.h>
     46 
     47 #include <nanohub/nanohub.h>
     48 
     49 #include <chreApi.h>
     50 
     51 struct TaskPool {
     52     struct Task data[MAX_TASKS];
     53 };
     54 
     55 static struct TaskPool mTaskPool;
     56 static struct EvtQueue *mEvtsInternal;
     57 static struct SlabAllocator* mMiscInternalThingsSlab;
     58 static struct TaskList mFreeTasks;
     59 static struct TaskList mTasks;
     60 static struct Task *mCurrentTask;
     61 static struct Task *mSystemTask;
     62 static TaggedPtr *mCurEvtEventFreeingInfo = NULL; //used as flag for retaining. NULL when none or already retained
     63 
     64 static inline void list_init(struct TaskList *l)
     65 {
     66     l->prev = l->next = NO_NODE;
     67 }
     68 
     69 struct Task *osGetCurrentTask()
     70 {
     71     return mCurrentTask;
     72 }
     73 
     74 struct Task *osSetCurrentTask(struct Task *task)
     75 {
     76     struct Task *old = mCurrentTask;
     77     while (true) {
     78         old = mCurrentTask;
     79         if (atomicCmpXchgPtr((uintptr_t*)&mCurrentTask, (uintptr_t)old, (uintptr_t)task)) {
     80             break;
     81         }
     82     }
     83     return old;
     84 }
     85 
     86 // beyond this point, noone shall access mCurrentTask directly
     87 
     88 static inline bool osTaskTestFlags(struct Task *task, uint32_t mask)
     89 {
     90     return (atomicReadByte(&task->flags) & mask) != 0;
     91 }
     92 
     93 bool osAppIsChre(uint16_t tid)
     94 {
     95     struct Task *task = osTaskFindByTid(tid);
     96 
     97     return task && osTaskIsChre(task);
     98 }
     99 
    100 static inline uint32_t osTaskClrSetFlags(struct Task *task, uint32_t clrMask, uint32_t setMask)
    101 {
    102     while (true) {
    103         uint8_t flags = atomicReadByte(&task->flags);
    104         uint8_t newFlags = (flags & ~clrMask) | setMask;
    105         if (atomicCmpXchgByte(&task->flags, flags, newFlags))
    106             return newFlags;
    107     }
    108 }
    109 
    110 static inline uint32_t osTaskAddIoCount(struct Task *task, int32_t delta)
    111 {
    112     uint8_t count = atomicAddByte(&task->ioCount, delta);
    113 
    114     count += delta; // old value is returned, so we add it again
    115 
    116     return count;
    117 }
    118 
    119 static inline uint32_t osTaskGetIoCount(struct Task *task)
    120 {
    121     return atomicReadByte(&task->ioCount);
    122 }
    123 
    124 uint8_t osTaskIndex(struct Task *task)
    125 {
    126     // we don't need signed diff here: this way we simplify boundary check
    127     size_t idx = task - &mTaskPool.data[0];
    128     return idx >= MAX_TASKS || &mTaskPool.data[idx] != task ? NO_NODE : idx;
    129 }
    130 
    131 static inline struct Task *osTaskByIdx(size_t idx)
    132 {
    133     return idx >= MAX_TASKS ? NULL : &mTaskPool.data[idx];
    134 }
    135 
    136 uint32_t osGetCurrentTid()
    137 {
    138     struct Task *task = osGetCurrentTask();
    139     if (task == NULL) {
    140         return UINT32_MAX;
    141     }
    142     return task->tid;
    143 }
    144 
    145 uint32_t osSetCurrentTid(uint32_t tid)
    146 {
    147     struct Task *task = osTaskByIdx(TID_TO_TASK_IDX(tid));
    148 
    149     if (task && task->tid == tid) {
    150         struct Task *preempted = osSetCurrentTask(task);
    151         return preempted->tid;
    152     }
    153 
    154     return osGetCurrentTid();
    155 }
    156 
    157 static inline struct Task *osTaskListPeekHead(struct TaskList *listHead)
    158 {
    159     TaskIndex idx = listHead->next;
    160     return idx == NO_NODE ? NULL : &mTaskPool.data[idx];
    161 }
    162 
    163 #ifdef DEBUG
    164 static void dumpListItems(const char *p, struct TaskList *listHead)
    165 {
    166     int i = 0;
    167     struct Task *task;
    168 
    169     osLog(LOG_ERROR, "List: %s (%p) [%u;%u]\n",
    170           p,
    171           listHead,
    172           listHead ? listHead->prev : NO_NODE,
    173           listHead ? listHead->next : NO_NODE
    174     );
    175     if (!listHead)
    176         return;
    177 
    178     for_each_task(listHead, task) {
    179         osLog(LOG_ERROR, "  item %d: task=%p TID=%04X [%u;%u;%u]\n",
    180               i,
    181               task,
    182               task->tid,
    183               task->list.prev,
    184               osTaskIndex(task),
    185               task->list.next
    186         );
    187         ++i;
    188     }
    189 }
    190 
    191 static void dumpTaskList(const char *f, struct Task *task, struct TaskList *listHead)
    192 {
    193     osLog(LOG_ERROR, "%s: pool: %p; task=%p [%u;%u;%u]; listHead=%p [%u;%u]\n",
    194           f,
    195           &mTaskPool,
    196           task,
    197           task ? task->list.prev : NO_NODE,
    198           osTaskIndex(task),
    199           task ? task->list.next : NO_NODE,
    200           listHead,
    201           listHead ? listHead->prev : NO_NODE,
    202           listHead ? listHead->next : NO_NODE
    203     );
    204     dumpListItems("Tasks", &mTasks);
    205     dumpListItems("Free Tasks", &mFreeTasks);
    206 }
    207 #else
    208 #define dumpTaskList(a,b,c)
    209 #endif
    210 
    211 static inline void osTaskListRemoveTask(struct TaskList *listHead, struct Task *task)
    212 {
    213     if (task && listHead) {
    214         struct TaskList *cur = &task->list;
    215         TaskIndex left_idx = cur->prev;
    216         TaskIndex right_idx = cur->next;
    217         struct TaskList *left =  left_idx == NO_NODE ? listHead : &mTaskPool.data[left_idx].list;
    218         struct TaskList *right = right_idx == NO_NODE ? listHead : &mTaskPool.data[right_idx].list;
    219         cur->prev = cur->next = NO_NODE;
    220         left->next = right_idx;
    221         right->prev = left_idx;
    222     } else {
    223         dumpTaskList(__func__, task, listHead);
    224     }
    225 }
    226 
    227 static inline void osTaskListAddTail(struct TaskList *listHead, struct Task *task)
    228 {
    229     if (task && listHead) {
    230         struct TaskList *cur = &task->list;
    231         TaskIndex last_idx = listHead->prev;
    232         TaskIndex new_idx = osTaskIndex(task);
    233         struct TaskList *last = last_idx == NO_NODE ? listHead : &mTaskPool.data[last_idx].list;
    234         cur->prev = last_idx;
    235         cur->next = NO_NODE;
    236         last->next = new_idx;
    237         listHead->prev = new_idx;
    238     } else {
    239         dumpTaskList(__func__, task, listHead);
    240     }
    241 }
    242 
    243 static struct Task *osAllocTask()
    244 {
    245     struct Task *task = osTaskListPeekHead(&mFreeTasks);
    246 
    247     if (task) {
    248         osTaskListRemoveTask(&mFreeTasks, task);
    249         uint16_t tid = task->tid;
    250         memset(task, 0, sizeof(*task));
    251         task->tid = tid;
    252     }
    253 
    254     return task;
    255 }
    256 
    257 static void osFreeTask(struct Task *task)
    258 {
    259     if (task) {
    260         task->flags = 0;
    261         task->ioCount = 0;
    262         osTaskListAddTail(&mFreeTasks, task);
    263     }
    264 }
    265 
    266 static void osRemoveTask(struct Task *task)
    267 {
    268     osTaskListRemoveTask(&mTasks, task);
    269 }
    270 
    271 static void osAddTask(struct Task *task)
    272 {
    273     osTaskListAddTail(&mTasks, task);
    274 }
    275 
    276 struct Task* osTaskFindByTid(uint32_t tid)
    277 {
    278     TaskIndex idx = TID_TO_TASK_IDX(tid);
    279 
    280     return idx < MAX_TASKS ? &mTaskPool.data[idx] : NULL;
    281 }
    282 
    283 static inline bool osTaskInit(struct Task *task)
    284 {
    285     struct Task *preempted = osSetCurrentTask(task);
    286     bool done = cpuAppInit(task->app, &task->platInfo, task->tid);
    287     osSetCurrentTask(preempted);
    288     return done;
    289 }
    290 
    291 static void osTaskRelease(struct Task *task)
    292 {
    293     uint16_t tid = task->tid;
    294 
    295     osSetCurrentTask(mSystemTask);
    296 
    297     platFreeResources(tid); // HW resources cleanup (IRQ, DMA etc)
    298     sensorFreeAll(tid);
    299     timTimerCancelAll(tid);
    300     heapFreeAll(tid);
    301 }
    302 
    303 static inline void osTaskEnd(struct Task *task)
    304 {
    305     struct Task *preempted = osSetCurrentTask(task);
    306 
    307     cpuAppEnd(task->app, &task->platInfo);
    308 
    309     // task was supposed to release it's resources,
    310     // but we do our cleanup anyway
    311     osTaskRelease(task);
    312     // NOTE: we don't need to unsubscribe from events
    313     osSetCurrentTask(preempted);
    314 }
    315 
    316 static inline void osTaskHandle(struct Task *task, uint16_t evtType, uint16_t fromTid, const void* evtData)
    317 {
    318     struct Task *preempted = osSetCurrentTask(task);
    319     cpuAppHandle(task->app, &task->platInfo,
    320                  EVENT_WITH_ORIGIN(evtType, osTaskIsChre(task) ? fromTid : 0),
    321                  evtData);
    322     osSetCurrentTask(preempted);
    323 }
    324 
    325 void osTaskInvokeMessageFreeCallback(struct Task *task, void (*freeCallback)(void *, size_t), void *message, uint32_t messageSize)
    326 {
    327     if (!task || !freeCallback)
    328         return;
    329     cpuAppInvoke(task->app, &task->platInfo, (void (*)(uintptr_t,uintptr_t))freeCallback, (uintptr_t)message, (uintptr_t)messageSize);
    330 }
    331 
    332 void osTaskInvokeEventFreeCallback(struct Task *task, void (*freeCallback)(uint16_t, void *), uint16_t event, void *data)
    333 {
    334     if (!task || !freeCallback)
    335         return;
    336     cpuAppInvoke(task->app, &task->platInfo,
    337                  (void (*)(uintptr_t,uintptr_t))freeCallback,
    338                  (uintptr_t)event, (uintptr_t)data);
    339 }
    340 
    341 static void osPrivateEvtFreeF(void *event)
    342 {
    343     union SeosInternalSlabData *act = event;
    344     uint16_t fromTid = act->privateEvt.fromTid;
    345     struct Task *srcTask = osTaskFindByTid(fromTid);
    346     TaggedPtr evtFreeInfo = act->privateEvt.evtFreeInfo;
    347     uint32_t evtType = act->privateEvt.evtType;
    348     void *evtData = act->privateEvt.evtData;
    349 
    350     slabAllocatorFree(mMiscInternalThingsSlab, event);
    351 
    352     if (!srcTask) {
    353         osLog(LOG_ERROR, "ERROR: Failed to find task to free event: evtType=%08" PRIX32 "\n", evtType);
    354         return;
    355     }
    356 
    357     if (taggedPtrIsPtr(evtFreeInfo) && taggedPtrToPtr(evtFreeInfo)) {
    358         if (osTaskIsChre(srcTask) && (evtType >> 16) == EVT_PRIVATE_CLASS_CHRE) {
    359             osChreFreeEvent(fromTid,
    360                             (void (*)(uint16_t, void *))taggedPtrToPtr(evtFreeInfo),
    361                             evtType & EVT_MASK, evtData);
    362         } else {
    363             // this is for internal non-CHRE tasks, and CHRE tasks
    364             // System may schedule non-CHRE events on behalf of CHRE app;
    365             // this is the place we release them
    366             struct Task *preempted = osSetCurrentTask(srcTask);
    367             ((EventFreeF)taggedPtrToPtr(evtFreeInfo))(evtData);
    368             osSetCurrentTask(preempted);
    369         }
    370     } else if (taggedPtrIsUint(evtFreeInfo)) {
    371         // this is for external non-CHRE tasks
    372         struct AppEventFreeData fd = {.evtType = evtType, .evtData = evtData};
    373         osTaskHandle(srcTask, EVT_APP_FREE_EVT_DATA, OS_SYSTEM_TID, &fd);
    374     }
    375 
    376     osTaskAddIoCount(srcTask, -1);
    377 }
    378 
    379 static void handleEventFreeing(uint32_t evtType, void *evtData, TaggedPtr evtFreeData) // watch out, this is synchronous
    380 {
    381     struct Task *srcTask = osTaskFindByTid(EVENT_GET_ORIGIN(evtType));
    382 
    383     if (!srcTask) {
    384         osLog(LOG_ERROR, "ERROR: Failed to find task to free event: evtType=%08" PRIX32 "\n", evtType);
    385         return;
    386     }
    387 
    388     // release non-CHRE event; we can't determine if this is CHRE or non-CHRE event, but
    389     // this method is only called to release non-CHRE events, so we make use of that fact
    390 
    391     if (taggedPtrIsPtr(evtFreeData) && taggedPtrToPtr(evtFreeData)) {
    392         // this is for internal non-CHRE tasks, and CHRE tasks
    393         // System may schedule non-CHRE events on behalf of CHRE app;
    394         // this is the place we release them
    395         struct Task *preempted = osSetCurrentTask(srcTask);
    396         ((EventFreeF)taggedPtrToPtr(evtFreeData))(evtData);
    397         osSetCurrentTask(preempted);
    398     } else if (taggedPtrIsUint(evtFreeData)) {
    399         // this is for external non-CHRE tasks
    400         struct AppEventFreeData fd = {.evtType = EVENT_GET_EVENT(evtType), .evtData = evtData};
    401         osTaskHandle(srcTask, EVT_APP_FREE_EVT_DATA, OS_SYSTEM_TID, &fd);
    402     }
    403 
    404     osTaskAddIoCount(srcTask, -1);
    405 }
    406 
    407 static void osInit(void)
    408 {
    409     heapInit();
    410     platInitialize();
    411 
    412     osLog(LOG_INFO, "SEOS Initializing\n");
    413     cpuInitLate();
    414 
    415     /* create the queues */
    416     if (!(mEvtsInternal = evtQueueAlloc(512, handleEventFreeing))) {
    417         osLog(LOG_INFO, "events failed to init\n");
    418         return;
    419     }
    420 
    421     mMiscInternalThingsSlab = slabAllocatorNew(sizeof(union SeosInternalSlabData), alignof(union SeosInternalSlabData), 64 /* for now? */);
    422     if (!mMiscInternalThingsSlab) {
    423         osLog(LOG_INFO, "deferred actions list failed to init\n");
    424         return;
    425     }
    426 }
    427 
    428 static struct Task* osTaskFindByAppID(uint64_t appID)
    429 {
    430     struct Task *task;
    431 
    432     for_each_task(&mTasks, task) {
    433         if (task->app && task->app->hdr.appId == appID)
    434             return task;
    435     }
    436 
    437     return NULL;
    438 }
    439 
    440 void osSegmentIteratorInit(struct SegmentIterator *it)
    441 {
    442     uint32_t sz;
    443     uint8_t *start = platGetSharedAreaInfo(&sz);
    444 
    445     it->shared    = (const struct Segment *)(start);
    446     it->sharedEnd = (const struct Segment *)(start + sz);
    447     it->seg       = NULL;
    448 }
    449 
    450 bool osAppSegmentSetState(const struct AppHdr *app, uint32_t segState)
    451 {
    452     bool done;
    453     struct Segment *seg = osGetSegment(app);
    454     uint8_t state = segState;
    455 
    456     if (!seg)
    457         return false;
    458 
    459     mpuAllowRamExecution(true);
    460     mpuAllowRomWrite(true);
    461     done = BL.blProgramShared(&seg->state, &state, sizeof(state), BL_FLASH_KEY1, BL_FLASH_KEY2);
    462     mpuAllowRomWrite(false);
    463     mpuAllowRamExecution(false);
    464 
    465     return done;
    466 }
    467 
    468 bool osSegmentSetSize(struct Segment *seg, uint32_t size)
    469 {
    470     bool ret = true;
    471 
    472     if (!seg)
    473         return false;
    474 
    475     if (size > SEG_SIZE_MAX) {
    476         seg->state = SEG_ST_ERASED;
    477         size = SEG_SIZE_MAX;
    478         ret = false;
    479     }
    480     seg->size[0] = size;
    481     seg->size[1] = size >> 8;
    482     seg->size[2] = size >> 16;
    483 
    484     return ret;
    485 }
    486 
    487 struct Segment *osSegmentGetEnd()
    488 {
    489     uint32_t size;
    490     uint8_t *start = platGetSharedAreaInfo(&size);
    491     return (struct Segment *)(start + size);
    492 }
    493 
    494 struct Segment *osGetSegment(const struct AppHdr *app)
    495 {
    496     uint32_t size;
    497     uint8_t *start = platGetSharedAreaInfo(&size);
    498 
    499     return (struct Segment *)((uint8_t*)app &&
    500                               (uint8_t*)app >= start &&
    501                               (uint8_t*)app < (start + size) ?
    502                               (uint8_t*)app - sizeof(struct Segment) : NULL);
    503 }
    504 
    505 bool osEraseShared()
    506 {
    507     wdtDisableClk();
    508     mpuAllowRamExecution(true);
    509     mpuAllowRomWrite(true);
    510     (void)BL.blEraseShared(BL_FLASH_KEY1, BL_FLASH_KEY2);
    511     mpuAllowRomWrite(false);
    512     mpuAllowRamExecution(false);
    513     wdtEnableClk();
    514     return true;
    515 }
    516 
    517 bool osWriteShared(void *dest, const void *src, uint32_t len)
    518 {
    519     bool ret;
    520 
    521     mpuAllowRamExecution(true);
    522     mpuAllowRomWrite(true);
    523     ret = BL.blProgramShared(dest, src, len, BL_FLASH_KEY1, BL_FLASH_KEY2);
    524     mpuAllowRomWrite(false);
    525     mpuAllowRamExecution(false);
    526 
    527     if (!ret)
    528         osLog(LOG_ERROR, "osWriteShared: blProgramShared return false\n");
    529 
    530     return ret;
    531 }
    532 
    533 struct AppHdr *osAppSegmentCreate(uint32_t size)
    534 {
    535     struct SegmentIterator it;
    536     const struct Segment *storageSeg = NULL;
    537     struct AppHdr *app;
    538 
    539     osSegmentIteratorInit(&it);
    540     while (osSegmentIteratorNext(&it)) {
    541         if (osSegmentGetState(it.seg) == SEG_ST_EMPTY) {
    542             storageSeg = it.seg;
    543             break;
    544         }
    545     }
    546     if (!storageSeg || osSegmentSizeGetNext(storageSeg, size) > it.sharedEnd)
    547         return NULL;
    548 
    549     app = osSegmentGetData(storageSeg);
    550     osAppSegmentSetState(app, SEG_ST_RESERVED);
    551 
    552     return app;
    553 }
    554 
    555 bool osAppSegmentClose(struct AppHdr *app, uint32_t segDataSize, uint32_t segState)
    556 {
    557     struct Segment seg;
    558 
    559     // this is enough for holding padding to uint32_t and the footer
    560     uint8_t footer[sizeof(uint32_t) + FOOTER_SIZE];
    561     int footerLen;
    562     bool ret;
    563     uint32_t totalSize;
    564     uint8_t *start = platGetSharedAreaInfo(&totalSize);
    565     uint8_t *end = start + totalSize;
    566     int32_t fullSize = segDataSize + sizeof(seg); // without footer or padding
    567     struct Segment *storageSeg = osGetSegment(app);
    568 
    569     // sanity check
    570     if (segDataSize >= SEG_SIZE_MAX)
    571         return false;
    572 
    573     // physical limits check
    574     if (osSegmentSizeAlignedWithFooter(segDataSize) + sizeof(struct Segment) > totalSize)
    575         return false;
    576 
    577     // available space check: we could truncate size, instead of disallowing it,
    578     // but we know that we performed validation on the size before, in *Create call,
    579     // and it was fine, so this must be a programming error, and so we fail.
    580     // on a side note: size may grow or shrink compared to original estimate.
    581     // typically it shrinks, since we skip some header info and padding, as well
    582     // as signature blocks, but it is possible that at some point we may produce
    583     // more data for some reason. At that time the logic here may need to change
    584     if (osSegmentSizeGetNext(storageSeg, segDataSize) > (struct Segment*)end)
    585         return false;
    586 
    587     seg.state = segState;
    588     osSegmentSetSize(&seg, segDataSize);
    589 
    590     ret = osWriteShared((uint8_t*)storageSeg, (uint8_t*)&seg, sizeof(seg));
    591 
    592     footerLen = (-fullSize) & 3;
    593     memset(footer, 0x00, footerLen);
    594 
    595 #ifdef SEGMENT_CRC_SUPPORT
    596     struct SegmentFooter segFooter {
    597         .crc = ~crc32(storageSeg, fullSize, ~0),
    598     };
    599     memcpy(&footer[footerLen], &segFooter, sizeof(segFooter));
    600     footerLen += sizeof(segFooter);
    601 #endif
    602 
    603     if (ret && footerLen)
    604         ret = osWriteShared((uint8_t*)storageSeg + fullSize, footer, footerLen);
    605 
    606     return ret;
    607 }
    608 
    609 bool osAppWipeData(struct AppHdr *app)
    610 {
    611     struct Segment *seg = osGetSegment(app);
    612     int32_t size = osSegmentGetSize(seg);
    613     uint8_t *p = (uint8_t*)app;
    614     uint32_t state = osSegmentGetState(seg);
    615     uint8_t buf[256];
    616     bool done = true;
    617 
    618     if (!seg || size == SEG_SIZE_INVALID || state == SEG_ST_EMPTY) {
    619         osLog(LOG_ERROR, "%s: can't erase segment: app=%p; seg=%p"
    620                          "; size=%" PRIu32
    621                          "; state=%" PRIu32
    622                          "\n",
    623                          __func__, app, seg, size, state);
    624         return false;
    625     }
    626 
    627     size = osSegmentSizeAlignedWithFooter(size);
    628 
    629     memset(buf, 0, sizeof(buf));
    630     while (size > 0) {
    631         uint32_t flashSz = size > sizeof(buf) ? sizeof(buf) : size;
    632         // keep trying to zero-out stuff even in case of intermittent failures.
    633         // flash write may occasionally fail on some byte, but it is not good enough
    634         // reason to not rewrite other bytes
    635         bool res = osWriteShared(p, buf, flashSz);
    636         done = done && res;
    637         size -= flashSz;
    638         p += flashSz;
    639     }
    640 
    641     return done;
    642 }
    643 
    644 static inline bool osAppIsValid(const struct AppHdr *app)
    645 {
    646     return app->hdr.magic == APP_HDR_MAGIC &&
    647            app->hdr.fwVer == APP_HDR_VER_CUR &&
    648            (app->hdr.fwFlags & FL_APP_HDR_APPLICATION) != 0 &&
    649            app->hdr.payInfoType == LAYOUT_APP;
    650 }
    651 
    652 static bool osExtAppIsValid(const struct AppHdr *app, uint32_t len)
    653 {
    654     //TODO: when CRC support is ready, add CRC check here
    655     return  osAppIsValid(app) &&
    656             len >= sizeof(*app) &&
    657             osAppSegmentGetState(app) == SEG_ST_VALID &&
    658             !(app->hdr.fwFlags & FL_APP_HDR_INTERNAL);
    659 }
    660 
    661 static bool osIntAppIsValid(const struct AppHdr *app)
    662 {
    663     return  osAppIsValid(app) &&
    664             osAppSegmentGetState(app) == SEG_STATE_INVALID &&
    665             (app->hdr.fwFlags & FL_APP_HDR_INTERNAL) != 0;
    666 }
    667 
    668 static inline bool osExtAppErase(const struct AppHdr *app)
    669 {
    670     return osAppSegmentSetState(app, SEG_ST_ERASED);
    671 }
    672 
    673 static struct Task *osLoadApp(const struct AppHdr *app) {
    674     struct Task *task;
    675 
    676     task = osAllocTask();
    677     if (!task) {
    678         osLog(LOG_WARN, "External app id %016" PRIX64 " @ %p cannot be used as too many apps already exist.\n", app->hdr.appId, app);
    679         return NULL;
    680     }
    681     task->app = app;
    682     bool done = (app->hdr.fwFlags & FL_APP_HDR_INTERNAL) ?
    683                 cpuInternalAppLoad(task->app, &task->platInfo) :
    684                 cpuAppLoad(task->app, &task->platInfo);
    685 
    686     if (!done) {
    687         osLog(LOG_WARN, "App @ %p ID %016" PRIX64 " failed to load\n", app, app->hdr.appId);
    688         osFreeTask(task);
    689         task = NULL;
    690     }
    691 
    692     return task;
    693 }
    694 
    695 static void osUnloadApp(struct Task *task)
    696 {
    697     // this is called on task that has stopped running, or had never run
    698     cpuAppUnload(task->app, &task->platInfo);
    699     osFreeTask(task);
    700 }
    701 
    702 static bool osStartApp(const struct AppHdr *app)
    703 {
    704     bool done = false;
    705     struct Task *task;
    706 
    707     if ((task = osLoadApp(app)) != NULL) {
    708         task->subbedEvtListSz = MAX_EMBEDDED_EVT_SUBS;
    709         task->subbedEvents = task->subbedEventsInt;
    710         osTaskMakeNewTid(task);
    711 
    712         // print external NanoApp info to facilitate NanoApp debugging
    713         if (!(task->app->hdr.fwFlags & FL_APP_HDR_INTERNAL))
    714             osLog(LOG_INFO, "loaded app ID 0x%llx at flash base 0x%08x ram base 0x%08x; TID %04X\n",
    715                   task->app->hdr.appId, (uintptr_t) task->app, (uintptr_t) task->platInfo.data, task->tid);
    716 
    717         done = osTaskInit(task);
    718 
    719         if (!done) {
    720             osLog(LOG_WARN, "App @ %p ID %016" PRIX64 " failed to init\n", task->app, task->app->hdr.appId);
    721             osUnloadApp(task);
    722         } else {
    723             osAddTask(task);
    724         }
    725     }
    726 
    727     return done;
    728 }
    729 
    730 static bool osStopTask(struct Task *task)
    731 {
    732     if (!task)
    733         return false;
    734 
    735     osRemoveTask(task);
    736 
    737     if (osTaskGetIoCount(task))
    738     {
    739         osTaskHandle(task, EVT_APP_STOP, OS_SYSTEM_TID, NULL);
    740         osEnqueueEvt(EVT_APP_END, task, NULL);
    741     } else {
    742         osTaskEnd(task); // calls app END() and Release()
    743         osUnloadApp(task);
    744     }
    745 
    746     osTaskClrSetFlags(task, 0, FL_TASK_STOPPED);
    747     return true;
    748 }
    749 
    750 void osTaskAbort(struct Task *task)
    751 {
    752     if (!task)
    753         return;
    754 
    755     osRemoveTask(task); // remove from active task list
    756     // do not call app END()
    757     osTaskRelease(task); // release all system resources
    758     osUnloadApp(task); // destroy platform app object in RAM
    759 }
    760 
    761 static bool osExtAppFind(struct SegmentIterator *it, uint64_t appId)
    762 {
    763     uint64_t vendor = APP_ID_GET_VENDOR(appId);
    764     uint64_t seqId = APP_ID_GET_SEQ_ID(appId);
    765     uint64_t curAppId;
    766     const struct AppHdr *app;
    767     const struct Segment *seg;
    768 
    769     while (osSegmentIteratorNext(it)) {
    770         seg = it->seg;
    771         if (!seg)
    772             break;
    773         if (seg->state == SEG_ST_EMPTY)
    774             break;
    775         if (seg->state != SEG_ST_VALID)
    776             continue;
    777         app = osSegmentGetData(seg);
    778         curAppId = app->hdr.appId;
    779 
    780         if ((vendor == APP_VENDOR_ANY || vendor == APP_ID_GET_VENDOR(curAppId)) &&
    781             (seqId == APP_SEQ_ID_ANY || seqId == APP_ID_GET_SEQ_ID(curAppId)))
    782             return true;
    783     }
    784 
    785     return false;
    786 }
    787 
    788 static uint32_t osExtAppStopEraseApps(uint64_t appId, bool doErase)
    789 {
    790     const struct AppHdr *app;
    791     int32_t len;
    792     struct SegmentIterator it;
    793     uint32_t stopCount = 0;
    794     uint32_t eraseCount = 0;
    795     uint32_t appCount = 0;
    796     uint32_t taskCount = 0;
    797     struct MgmtStatus stat = { .value = 0 };
    798     struct Task *task;
    799 
    800     osSegmentIteratorInit(&it);
    801     while (osExtAppFind(&it, appId)) {
    802         app = osSegmentGetData(it.seg);
    803         len = osSegmentGetSize(it.seg);
    804         if (!osExtAppIsValid(app, len))
    805             continue;
    806         appCount++;
    807         /* it is safe to erase a running app;
    808          * erase merely sets a flag in the header,
    809          * and app keeps running until it is stopped */
    810         if (doErase && osExtAppErase(app))
    811             eraseCount++;
    812         task = osTaskFindByAppID(app->hdr.appId);
    813         if (task) {
    814             taskCount++;
    815             if (osStopTask(task))
    816                stopCount++;
    817         }
    818     }
    819     SET_COUNTER(stat.app,   appCount);
    820     SET_COUNTER(stat.task,  taskCount);
    821     SET_COUNTER(stat.op,    stopCount);
    822     SET_COUNTER(stat.erase, eraseCount);
    823 
    824     return stat.value;
    825 }
    826 
    827 uint32_t osExtAppStopApps(uint64_t appId)
    828 {
    829     return osExtAppStopEraseApps(appId, false);
    830 }
    831 
    832 uint32_t osExtAppEraseApps(uint64_t appId)
    833 {
    834     return osExtAppStopEraseApps(appId, true);
    835 }
    836 
    837 static void osScanExternal()
    838 {
    839     struct SegmentIterator it;
    840     osSegmentIteratorInit(&it);
    841     while (osSegmentIteratorNext(&it)) {
    842         switch (osSegmentGetState(it.seg)) {
    843         case SEG_ST_EMPTY:
    844             // everything looks good
    845             osLog(LOG_INFO, "External area is good\n");
    846             return;
    847         case SEG_ST_ERASED:
    848         case SEG_ST_VALID:
    849             // this is valid stuff, ignore
    850             break;
    851         case SEG_ST_RESERVED:
    852         default:
    853             // something is wrong: erase everything
    854             osLog(LOG_ERROR, "External area is damaged. Erasing\n");
    855             osEraseShared();
    856             return;
    857         }
    858     }
    859 }
    860 
    861 uint32_t osExtAppStartApps(uint64_t appId)
    862 {
    863     const struct AppHdr *app;
    864     int32_t len;
    865     struct SegmentIterator it;
    866     struct SegmentIterator checkIt;
    867     uint32_t startCount = 0;
    868     uint32_t eraseCount = 0;
    869     uint32_t appCount = 0;
    870     uint32_t taskCount = 0;
    871     struct MgmtStatus stat = { .value = 0 };
    872 
    873     osScanExternal();
    874 
    875     osSegmentIteratorInit(&it);
    876     while (osExtAppFind(&it, appId)) {
    877         app = osSegmentGetData(it.seg);
    878         len = osSegmentGetSize(it.seg);
    879 
    880         // skip erased or malformed apps
    881         if (!osExtAppIsValid(app, len))
    882             continue;
    883 
    884         appCount++;
    885         checkIt = it;
    886         // find the most recent copy
    887         while (osExtAppFind(&checkIt, app->hdr.appId)) {
    888             if (osExtAppErase(app)) // erase the old one, so we skip it next time
    889                 eraseCount++;
    890             app = osSegmentGetData(checkIt.seg);
    891         }
    892 
    893         if (osTaskFindByAppID(app->hdr.appId)) {
    894             // this either the most recent external app with the same ID,
    895             // or internal app with the same id; in both cases we do nothing
    896             taskCount++;
    897             continue;
    898         }
    899 
    900         if (osStartApp(app))
    901             startCount++;
    902     }
    903     SET_COUNTER(stat.app,   appCount);
    904     SET_COUNTER(stat.task,  taskCount);
    905     SET_COUNTER(stat.op,    startCount);
    906     SET_COUNTER(stat.erase, eraseCount);
    907 
    908     return stat.value;
    909 }
    910 
    911 static void osStartTasks(void)
    912 {
    913     const struct AppHdr *app;
    914     uint32_t i, nApps;
    915     struct Task* task;
    916     uint32_t status = 0;
    917     uint32_t taskCnt = 0;
    918 
    919     osLog(LOG_DEBUG, "Initializing task pool...\n");
    920     list_init(&mTasks);
    921     list_init(&mFreeTasks);
    922     for (i = 0; i < MAX_TASKS; ++i) {
    923         task = &mTaskPool.data[i];
    924         list_init(&task->list);
    925         osFreeTask(task);
    926     }
    927 
    928     mSystemTask = osAllocTask(); // this is a dummy task; holder of TID 0; all system code will run with TID 0
    929     osSetCurrentTask(mSystemTask);
    930     osLog(LOG_DEBUG, "System task is: %p\n", mSystemTask);
    931 
    932     /* first enum all internal apps, making sure to check for dupes */
    933     osLog(LOG_DEBUG, "Starting internal apps...\n");
    934     for (i = 0, app = platGetInternalAppList(&nApps); i < nApps; i++, app++) {
    935         if (!osIntAppIsValid(app)) {
    936             osLog(LOG_WARN, "Invalid internal app @ %p ID %016" PRIX64
    937                             "header version: %" PRIu16
    938                             "\n",
    939                             app, app->hdr.appId, app->hdr.fwVer);
    940             continue;
    941         }
    942 
    943         if (!(app->hdr.fwFlags & FL_APP_HDR_INTERNAL)) {
    944             osLog(LOG_WARN, "Internal app is not marked: [%p]: flags: 0x%04" PRIX16
    945                             "; ID: %016" PRIX64
    946                             "; ignored\n",
    947                             app, app->hdr.fwFlags, app->hdr.appId);
    948             continue;
    949         }
    950         if ((task = osTaskFindByAppID(app->hdr.appId))) {
    951             osLog(LOG_WARN, "Internal app ID %016" PRIX64
    952                             "@ %p attempting to update internal app @ %p; app @%p ignored.\n",
    953                             app->hdr.appId, app, task->app, app);
    954             continue;
    955         }
    956         if (osStartApp(app))
    957             taskCnt++;
    958     }
    959 
    960     osLog(LOG_DEBUG, "Starting external apps...\n");
    961     status = osExtAppStartApps(APP_ID_ANY);
    962     osLog(LOG_DEBUG, "Started %" PRIu32 " internal apps; EXT status: %08" PRIX32 "\n", taskCnt, status);
    963 }
    964 
    965 static void osInternalEvtHandle(uint32_t evtType, void *evtData)
    966 {
    967     union SeosInternalSlabData *da = (union SeosInternalSlabData*)evtData;
    968     struct Task *task;
    969     uint32_t i, j;
    970     uint16_t tid = EVENT_GET_ORIGIN(evtType);
    971     uint16_t evt = EVENT_GET_EVENT(evtType);
    972     struct Task *srcTask = osTaskFindByTid(tid);
    973     struct Task *preempted = osSetCurrentTask(srcTask);
    974 
    975     switch (evt) {
    976     case EVT_SUBSCRIBE_TO_EVT:
    977     case EVT_UNSUBSCRIBE_TO_EVT:
    978         /* get task */
    979         task = osTaskFindByTid(da->evtSub.tid);
    980         if (!task)
    981             break;
    982 
    983         for (j = 0; j < da->evtSub.numEvts; j++) {
    984             /* find if subscribed to this evt */
    985             for (i = 0; i < task->subbedEvtCount && task->subbedEvents[i] != da->evtSub.evts[j]; i++);
    986 
    987             /* if unsub & found -> unsub */
    988             if (evt == EVT_UNSUBSCRIBE_TO_EVT && i != task->subbedEvtCount)
    989                 task->subbedEvents[i] = task->subbedEvents[--task->subbedEvtCount];
    990             /* if sub & not found -> sub */
    991             else if (evt == EVT_SUBSCRIBE_TO_EVT && i == task->subbedEvtCount) {
    992                 if (task->subbedEvtListSz == task->subbedEvtCount) { /* enlarge the list */
    993                     uint32_t newSz = (task->subbedEvtListSz * 3 + 1) / 2;
    994                     uint32_t *newList = heapAlloc(sizeof(uint32_t[newSz])); /* grow by 50% */
    995                     if (newList) {
    996                         memcpy(newList, task->subbedEvents, sizeof(uint32_t[task->subbedEvtListSz]));
    997                         if (task->subbedEvents != task->subbedEventsInt)
    998                             heapFree(task->subbedEvents);
    999                         task->subbedEvents = newList;
   1000                         task->subbedEvtListSz = newSz;
   1001                     }
   1002                 }
   1003                 if (task->subbedEvtListSz > task->subbedEvtCount) { /* have space ? */
   1004                     task->subbedEvents[task->subbedEvtCount++] = da->evtSub.evts[j];
   1005                 }
   1006             }
   1007         }
   1008         break;
   1009 
   1010     case EVT_APP_END:
   1011         task = evtData;
   1012         osTaskEnd(task);
   1013         osUnloadApp(task);
   1014         break;
   1015 
   1016     case EVT_DEFERRED_CALLBACK:
   1017         da->deferred.callback(da->deferred.cookie);
   1018         break;
   1019 
   1020     case EVT_PRIVATE_EVT:
   1021         task = osTaskFindByTid(da->privateEvt.toTid);
   1022         evtType = da->privateEvt.evtType & EVT_MASK;
   1023         evtData = da->privateEvt.evtData;
   1024         if (task) {
   1025             //private events cannot be retained
   1026             TaggedPtr *tmp = mCurEvtEventFreeingInfo;
   1027             mCurEvtEventFreeingInfo = NULL;
   1028             osTaskHandle(task, evtType, da->privateEvt.fromTid, da->privateEvt.evtData);
   1029             mCurEvtEventFreeingInfo = tmp;
   1030         }
   1031         break;
   1032     }
   1033     osSetCurrentTask(preempted);
   1034 }
   1035 
   1036 void abort(void)
   1037 {
   1038     /* this is necessary for va_* funcs... */
   1039     osLog(LOG_ERROR, "Abort called");
   1040     while(1);
   1041 }
   1042 
   1043 bool osRetainCurrentEvent(TaggedPtr *evtFreeingInfoP)
   1044 {
   1045     if (!mCurEvtEventFreeingInfo)
   1046         return false;
   1047 
   1048     *evtFreeingInfoP = *mCurEvtEventFreeingInfo;
   1049     mCurEvtEventFreeingInfo = NULL;
   1050     return true;
   1051 }
   1052 
   1053 void osFreeRetainedEvent(uint32_t evtType, void *evtData, TaggedPtr *evtFreeingInfoP)
   1054 {
   1055     //TODO: figure the way to calculate src tid here to pass to handleEventFreeing
   1056     handleEventFreeing(evtType, evtData, *evtFreeingInfoP);
   1057 }
   1058 
   1059 void osMainInit(void)
   1060 {
   1061     cpuInit();
   1062     cpuIntsOff();
   1063     osInit();
   1064     timInit();
   1065     sensorsInit();
   1066     syscallInit();
   1067     osApiExport(mMiscInternalThingsSlab);
   1068     osChreApiExport();
   1069     apIntInit();
   1070     cpuIntsOn();
   1071     wdtInit();
   1072     osStartTasks();
   1073 
   1074     //broadcast app start to all already-loaded apps
   1075     (void)osEnqueueEvt(EVT_APP_START, NULL, NULL);
   1076 }
   1077 
   1078 void osMainDequeueLoop(void)
   1079 {
   1080     TaggedPtr evtFreeingInfo;
   1081     uint32_t evtType, j;
   1082     void *evtData;
   1083     struct Task *task;
   1084     uint16_t tid, evt;
   1085 
   1086     /* get an event */
   1087     if (!evtQueueDequeue(mEvtsInternal, &evtType, &evtData, &evtFreeingInfo, true))
   1088         return;
   1089 
   1090     /* by default we free them when we're done with them */
   1091     mCurEvtEventFreeingInfo = &evtFreeingInfo;
   1092     tid = EVENT_GET_ORIGIN(evtType);
   1093     evt = EVENT_GET_EVENT(evtType);
   1094 
   1095     if (evt < EVT_NO_FIRST_USER_EVENT) {
   1096         /* handle deferred actions and other reserved events here */
   1097         osInternalEvtHandle(evtType, evtData);
   1098     } else {
   1099         /* send this event to all tasks who want it */
   1100         for_each_task(&mTasks, task) {
   1101             for (j = 0; j < task->subbedEvtCount; j++) {
   1102                 if (task->subbedEvents[j] == evt) {
   1103                     osTaskHandle(task, evt, tid, evtData);
   1104                     break;
   1105                 }
   1106             }
   1107         }
   1108     }
   1109 
   1110     /* free it */
   1111     if (mCurEvtEventFreeingInfo)
   1112         handleEventFreeing(evtType, evtData, evtFreeingInfo);
   1113 
   1114     /* avoid some possible errors */
   1115     mCurEvtEventFreeingInfo = NULL;
   1116 }
   1117 
   1118 void __attribute__((noreturn)) osMain(void)
   1119 {
   1120     osMainInit();
   1121 
   1122     while (true)
   1123     {
   1124         osMainDequeueLoop();
   1125         platPeriodic();
   1126     }
   1127 }
   1128 
   1129 static void osDeferredActionFreeF(void* event)
   1130 {
   1131     slabAllocatorFree(mMiscInternalThingsSlab, event);
   1132 }
   1133 
   1134 static bool osEventsSubscribeUnsubscribeV(bool sub, uint32_t numEvts, va_list ap)
   1135 {
   1136     union SeosInternalSlabData *act = slabAllocatorAlloc(mMiscInternalThingsSlab);
   1137     int i;
   1138 
   1139     if (!act || numEvts > MAX_EVT_SUB_CNT)
   1140         return false;
   1141 
   1142     act->evtSub.tid = osGetCurrentTid();
   1143     act->evtSub.numEvts = numEvts;
   1144     for (i = 0; i < numEvts; i++)
   1145         act->evtSub.evts[i] = va_arg(ap, uint32_t);
   1146 
   1147     return osEnqueueEvtOrFree(sub ? EVT_SUBSCRIBE_TO_EVT : EVT_UNSUBSCRIBE_TO_EVT, act, osDeferredActionFreeF);
   1148 }
   1149 
   1150 static bool osEventsSubscribeUnsubscribe(bool sub, uint32_t numEvts, ...)
   1151 {
   1152     bool ret;
   1153     va_list ap;
   1154 
   1155     va_start(ap, numEvts);
   1156     ret = osEventsSubscribeUnsubscribeV(sub, numEvts, ap);
   1157     va_end(ap);
   1158 
   1159     return ret;
   1160 }
   1161 
   1162 bool osEventSubscribe(uint32_t tid, uint32_t evtType)
   1163 {
   1164     (void)tid;
   1165     return osEventsSubscribeUnsubscribe(true, 1, evtType);
   1166 }
   1167 
   1168 bool osEventUnsubscribe(uint32_t tid, uint32_t evtType)
   1169 {
   1170     (void)tid;
   1171     return osEventsSubscribeUnsubscribe(false, 1, evtType);
   1172 }
   1173 
   1174 bool osEventsSubscribe(uint32_t numEvts, ...)
   1175 {
   1176     bool ret;
   1177     va_list ap;
   1178 
   1179     va_start(ap, numEvts);
   1180     ret = osEventsSubscribeUnsubscribeV(true, numEvts, ap);
   1181     va_end(ap);
   1182 
   1183     return ret;
   1184 }
   1185 
   1186 bool osEventsUnsubscribe(uint32_t numEvts, ...)
   1187 {
   1188     bool ret;
   1189     va_list ap;
   1190 
   1191     va_start(ap, numEvts);
   1192     ret = osEventsSubscribeUnsubscribeV(false, numEvts, ap);
   1193     va_end(ap);
   1194 
   1195     return ret;
   1196 }
   1197 
   1198 static bool osEnqueueEvtCommon(uint32_t evt, void *evtData, TaggedPtr evtFreeInfo, bool urgent)
   1199 {
   1200     struct Task *task = osGetCurrentTask();
   1201     uint32_t evtType = EVENT_WITH_ORIGIN(evt, osGetCurrentTid());
   1202 
   1203     osTaskAddIoCount(task, 1);
   1204 
   1205     if (osTaskTestFlags(task, FL_TASK_STOPPED)) {
   1206         handleEventFreeing(evtType, evtData, evtFreeInfo);
   1207         return true;
   1208     }
   1209 
   1210     if (!evtQueueEnqueue(mEvtsInternal, evtType, evtData, evtFreeInfo, urgent)) {
   1211         osTaskAddIoCount(task, -1);
   1212         return false;
   1213     }
   1214 
   1215     return true;
   1216 }
   1217 
   1218 void osRemovePendingEvents(bool (*match)(uint32_t evtType, const void *evtData, void *context), void *context)
   1219 {
   1220     evtQueueRemoveAllMatching(mEvtsInternal, match, context);
   1221 }
   1222 
   1223 bool osEnqueueEvt(uint32_t evtType, void *evtData, EventFreeF evtFreeF)
   1224 {
   1225     return osEnqueueEvtCommon(evtType, evtData, taggedPtrMakeFromPtr(evtFreeF), false);
   1226 }
   1227 
   1228 bool osEnqueueEvtOrFree(uint32_t evtType, void *evtData, EventFreeF evtFreeF)
   1229 {
   1230     bool success = osEnqueueEvt(evtType, evtData, evtFreeF);
   1231 
   1232     if (!success && evtFreeF)
   1233         evtFreeF(evtData);
   1234 
   1235     return success;
   1236 }
   1237 
   1238 bool osEnqueueEvtAsApp(uint32_t evtType, void *evtData, bool freeData)
   1239 {
   1240     // compatibility with existing external apps
   1241     if (evtType & EVENT_TYPE_BIT_DISCARDABLE_COMPAT)
   1242         evtType |= EVENT_TYPE_BIT_DISCARDABLE;
   1243 
   1244     return osEnqueueEvtCommon(evtType, evtData, freeData ? taggedPtrMakeFromUint(osGetCurrentTid()) : taggedPtrMakeFromPtr(NULL), false);
   1245 }
   1246 
   1247 bool osDefer(OsDeferCbkF callback, void *cookie, bool urgent)
   1248 {
   1249     union SeosInternalSlabData *act = slabAllocatorAlloc(mMiscInternalThingsSlab);
   1250     if (!act)
   1251             return false;
   1252 
   1253     act->deferred.callback = callback;
   1254     act->deferred.cookie = cookie;
   1255 
   1256     if (osEnqueueEvtCommon(EVT_DEFERRED_CALLBACK, act, taggedPtrMakeFromPtr(osDeferredActionFreeF), urgent))
   1257         return true;
   1258 
   1259     slabAllocatorFree(mMiscInternalThingsSlab, act);
   1260     return false;
   1261 }
   1262 
   1263 static bool osEnqueuePrivateEvtEx(uint32_t evtType, void *evtData, TaggedPtr evtFreeInfo, uint32_t toTid)
   1264 {
   1265     union SeosInternalSlabData *act = slabAllocatorAlloc(mMiscInternalThingsSlab);
   1266     bool result;
   1267 
   1268     if (!act) {
   1269         osLog(LOG_ERROR, "[seos] ERROR: osEnqueuePrivateEvtEx: call to slabAllocatorAlloc() failed\n");
   1270         return false;
   1271     }
   1272     struct Task *task = osGetCurrentTask();
   1273     osTaskAddIoCount(task, 1);
   1274 
   1275     act->privateEvt.evtType = evtType;
   1276     act->privateEvt.evtData = evtData;
   1277     act->privateEvt.evtFreeInfo = evtFreeInfo;
   1278     act->privateEvt.fromTid = task->tid;
   1279     act->privateEvt.toTid = toTid;
   1280 
   1281     osSetCurrentTask(mSystemTask);
   1282     result = osEnqueueEvtOrFree(EVT_PRIVATE_EVT, act, osPrivateEvtFreeF);
   1283     osSetCurrentTask(task);
   1284     return result;
   1285 }
   1286 
   1287 // only called to send events for CHRE apps
   1288 bool osEnqueuePrivateEvtNew(uint16_t evtType, void *evtData,
   1289                                    void (*evtFreeCallback)(uint16_t evtType, void *evtData),
   1290                                    uint32_t toTid)
   1291 {
   1292     if (!osEnqueuePrivateEvtEx(evtType | (EVT_PRIVATE_CLASS_CHRE << 16), evtData,
   1293                                taggedPtrMakeFromPtr(evtFreeCallback), toTid)) {
   1294         osChreFreeEvent(osGetCurrentTid(), evtFreeCallback, evtType, evtData);
   1295         return false;
   1296     }
   1297     return true;
   1298 }
   1299 
   1300 bool osEnqueuePrivateEvt(uint32_t evtType, void *evtData, EventFreeF evtFreeF, uint32_t toTid)
   1301 {
   1302     return osEnqueuePrivateEvtEx(evtType & EVT_MASK, evtData, taggedPtrMakeFromPtr(evtFreeF), toTid);
   1303 }
   1304 
   1305 bool osEnqueuePrivateEvtAsApp(uint32_t evtType, void *evtData, uint32_t toTid)
   1306 {
   1307     return osEnqueuePrivateEvtEx(evtType & EVT_MASK, evtData, taggedPtrMakeFromUint(osGetCurrentTid()), toTid);
   1308 }
   1309 
   1310 bool osTidById(uint64_t *appId, uint32_t *tid)
   1311 {
   1312     struct Task *task;
   1313 
   1314     for_each_task(&mTasks, task) {
   1315         if (task->app && !memcmp(&task->app->hdr.appId, appId, sizeof(*appId))) {
   1316             *tid = task->tid;
   1317             return true;
   1318         }
   1319     }
   1320 
   1321     return false;
   1322 }
   1323 
   1324 bool osAppInfoById(uint64_t appId, uint32_t *appIdx, uint32_t *appVer, uint32_t *appSize)
   1325 {
   1326     uint32_t i = 0;
   1327     struct Task *task;
   1328 
   1329     for_each_task(&mTasks, task) {
   1330         const struct AppHdr *app = task->app;
   1331         if (app && app->hdr.appId == appId) {
   1332             *appIdx = i;
   1333             *appVer = app->hdr.appVer;
   1334             *appSize = app->sect.rel_end;
   1335             return true;
   1336         }
   1337         i++;
   1338     }
   1339 
   1340     return false;
   1341 }
   1342 
   1343 bool osAppInfoByIndex(uint32_t appIdx, uint64_t *appId, uint32_t *appVer, uint32_t *appSize)
   1344 {
   1345     struct Task *task;
   1346     int i = 0;
   1347 
   1348     for_each_task(&mTasks, task) {
   1349         if (i != appIdx) {
   1350             ++i;
   1351         } else {
   1352             const struct AppHdr *app = task->app;
   1353             *appId = app->hdr.appId;
   1354             *appVer = app->hdr.appVer;
   1355             *appSize = app->sect.rel_end;
   1356             return true;
   1357         }
   1358     }
   1359 
   1360     return false;
   1361 }
   1362 
   1363 void osLogv(char clevel, const char *str, va_list vl)
   1364 {
   1365     void *userData = platLogAllocUserData();
   1366 
   1367     platLogPutcharF(userData, clevel);
   1368     cvprintf(platLogPutcharF, userData, str, vl);
   1369 
   1370     platLogFlush(userData);
   1371 }
   1372 
   1373 void osLog(enum LogLevel level, const char *str, ...)
   1374 {
   1375     va_list vl;
   1376 
   1377     va_start(vl, str);
   1378     osLogv((char)level, str, vl);
   1379     va_end(vl);
   1380 }
   1381 
   1382 
   1383 
   1384 
   1385 //Google's public key for Google's apps' signing
   1386 const uint8_t __attribute__ ((section (".pubkeys"))) _RSA_KEY_GOOGLE[] = {
   1387     0xd9, 0xcd, 0x83, 0xae, 0xb5, 0x9e, 0xe4, 0x63, 0xf1, 0x4c, 0x26, 0x6a, 0x1c, 0xeb, 0x4c, 0x12,
   1388     0x5b, 0xa6, 0x71, 0x7f, 0xa2, 0x4e, 0x7b, 0xa2, 0xee, 0x02, 0x86, 0xfc, 0x0d, 0x31, 0x26, 0x74,
   1389     0x1e, 0x9c, 0x41, 0x43, 0xba, 0x16, 0xe9, 0x23, 0x4d, 0xfc, 0xc4, 0xca, 0xcc, 0xd5, 0x27, 0x2f,
   1390     0x16, 0x4c, 0xe2, 0x85, 0x39, 0xb3, 0x0b, 0xcb, 0x73, 0xb6, 0x56, 0xc2, 0x98, 0x83, 0xf6, 0xfa,
   1391     0x7a, 0x6e, 0xa0, 0x9a, 0xcc, 0x83, 0x97, 0x9d, 0xde, 0x89, 0xb2, 0xa3, 0x05, 0x46, 0x0c, 0x12,
   1392     0xae, 0x01, 0xf8, 0x0c, 0xf5, 0x39, 0x32, 0xe5, 0x94, 0xb9, 0xa0, 0x8f, 0x19, 0xe4, 0x39, 0x54,
   1393     0xad, 0xdb, 0x81, 0x60, 0x74, 0x63, 0xd5, 0x80, 0x3b, 0xd2, 0x88, 0xf4, 0xcb, 0x6b, 0x47, 0x28,
   1394     0x80, 0xb0, 0xd1, 0x89, 0x6d, 0xd9, 0x62, 0x88, 0x81, 0xd6, 0xc0, 0x13, 0x88, 0x91, 0xfb, 0x7d,
   1395     0xa3, 0x7f, 0xa5, 0x40, 0x12, 0xfb, 0x77, 0x77, 0x4c, 0x98, 0xe4, 0xd3, 0x62, 0x39, 0xcc, 0x63,
   1396     0x34, 0x76, 0xb9, 0x12, 0x67, 0xfe, 0x83, 0x23, 0x5d, 0x40, 0x6b, 0x77, 0x93, 0xd6, 0xc0, 0x86,
   1397     0x6c, 0x03, 0x14, 0xdf, 0x78, 0x2d, 0xe0, 0x9b, 0x5e, 0x05, 0xf0, 0x93, 0xbd, 0x03, 0x1d, 0x17,
   1398     0x56, 0x88, 0x58, 0x25, 0xa6, 0xae, 0x63, 0xd2, 0x01, 0x43, 0xbb, 0x7e, 0x7a, 0xa5, 0x62, 0xdf,
   1399     0x8a, 0x31, 0xbd, 0x24, 0x1b, 0x1b, 0xeb, 0xfe, 0xdf, 0xd1, 0x31, 0x61, 0x4a, 0xfa, 0xdd, 0x6e,
   1400     0x62, 0x0c, 0xa9, 0xcd, 0x08, 0x0c, 0xa1, 0x1b, 0xe7, 0xf2, 0xed, 0x36, 0x22, 0xd0, 0x5d, 0x80,
   1401     0x78, 0xeb, 0x6f, 0x5a, 0x58, 0x18, 0xb5, 0xaf, 0x82, 0x77, 0x4c, 0x95, 0xce, 0xc6, 0x4d, 0xda,
   1402     0xca, 0xef, 0x68, 0xa6, 0x6d, 0x71, 0x4d, 0xf1, 0x14, 0xaf, 0x68, 0x25, 0xb8, 0xf3, 0xff, 0xbe,
   1403 };
   1404 
   1405 
   1406 #ifdef DEBUG
   1407 
   1408 //debug key whose privatekey is checked in as misc/debug.privkey
   1409 const uint8_t __attribute__ ((section (".pubkeys"))) _RSA_KEY_GOOGLE_DEBUG[] = {
   1410     0x2d, 0xff, 0xa6, 0xb5, 0x65, 0x87, 0xbe, 0x61, 0xd1, 0xe1, 0x67, 0x10, 0xa1, 0x9b, 0xc6, 0xca,
   1411     0xc8, 0xb1, 0xf0, 0xaa, 0x88, 0x60, 0x9f, 0xa1, 0x00, 0xa1, 0x41, 0x9a, 0xd8, 0xb4, 0xd1, 0x74,
   1412     0x9f, 0x23, 0x28, 0x0d, 0xc2, 0xc4, 0x37, 0x15, 0xb1, 0x4a, 0x80, 0xca, 0xab, 0xb9, 0xba, 0x09,
   1413     0x7d, 0xf8, 0x44, 0xd6, 0xa2, 0x72, 0x28, 0x12, 0x91, 0xf6, 0xa5, 0xea, 0xbd, 0xf8, 0x81, 0x6b,
   1414     0xd2, 0x3c, 0x50, 0xa2, 0xc6, 0x19, 0x54, 0x48, 0x45, 0x8d, 0x92, 0xac, 0x01, 0xda, 0x14, 0x32,
   1415     0xdb, 0x05, 0x82, 0x06, 0x30, 0x25, 0x09, 0x7f, 0x5a, 0xbb, 0x86, 0x64, 0x70, 0x98, 0x64, 0x1e,
   1416     0xe6, 0xca, 0x1d, 0xc1, 0xcb, 0xb6, 0x23, 0xd2, 0x62, 0x00, 0x46, 0x97, 0xd5, 0xcc, 0xe6, 0x36,
   1417     0x72, 0xec, 0x2e, 0x43, 0x1f, 0x0a, 0xaf, 0xf2, 0x51, 0xe1, 0xcd, 0xd2, 0x98, 0x5d, 0x7b, 0x64,
   1418     0xeb, 0xd1, 0x35, 0x4d, 0x59, 0x13, 0x82, 0x6c, 0xbd, 0xc4, 0xa2, 0xfc, 0xad, 0x64, 0x73, 0xe2,
   1419     0x71, 0xb5, 0xf4, 0x45, 0x53, 0x6b, 0xc3, 0x56, 0xb9, 0x8b, 0x3d, 0xeb, 0x00, 0x48, 0x6e, 0x29,
   1420     0xb1, 0xb4, 0x8e, 0x2e, 0x43, 0x39, 0xef, 0x45, 0xa0, 0xb8, 0x8b, 0x5f, 0x80, 0xb5, 0x0c, 0xc3,
   1421     0x03, 0xe3, 0xda, 0x51, 0xdc, 0xec, 0x80, 0x2c, 0x0c, 0xdc, 0xe2, 0x71, 0x0a, 0x14, 0x4f, 0x2c,
   1422     0x22, 0x2b, 0x0e, 0xd1, 0x8b, 0x8f, 0x93, 0xd2, 0xf3, 0xec, 0x3a, 0x5a, 0x1c, 0xba, 0x80, 0x54,
   1423     0x23, 0x7f, 0xb0, 0x54, 0x8b, 0xe3, 0x98, 0x22, 0xbb, 0x4b, 0xd0, 0x29, 0x5f, 0xce, 0xf2, 0xaa,
   1424     0x99, 0x89, 0xf2, 0xb7, 0x5d, 0x8d, 0xb2, 0x72, 0x0b, 0x52, 0x02, 0xb8, 0xa4, 0x37, 0xa0, 0x3b,
   1425     0xfe, 0x0a, 0xbc, 0xb3, 0xb3, 0xed, 0x8f, 0x8c, 0x42, 0x59, 0xbe, 0x4e, 0x31, 0xed, 0x11, 0x9b,
   1426 };
   1427 
   1428 #endif
   1429