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