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