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