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