/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _SEOS_H_ #define _SEOS_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include "toolchain.h" #include //#define SEGMENT_CRC_SUPPORT #define MAX_TASKS 16 #define MAX_EMBEDDED_EVT_SUBS 6 /* tradeoff, no wrong answer */ #define TASK_IDX_BITS 8 /* should be big enough to hold MAX_TASKS, but still fit in TaskIndex */ typedef uint8_t TaskIndex; struct AppFuncs { /* do not rearrange */ /* lifescycle */ bool (*init)(uint32_t yourTid); //simple init only - no ints on at this time void (*end)(void); //die quickly please /* events */ void (*handle)(uint32_t evtType, const void* evtData); }; /* NOTE: [TASK ID] * TID is designed to be 16-bit; there is no reason for TID to become bigger than that on a system * with typical RAM size of 64kB. However, in NO CASE TID values should overlap with TaggedPtr TAG mask, * which is currently defined as 0x80000000. */ #define TASK_TID_BITS 16 #define TASK_TID_MASK ((1 << TASK_TID_BITS) - 1) #define TASK_TID_INCREMENT (1 << TASK_IDX_BITS) #define TASK_TID_IDX_MASK ((1 << TASK_IDX_BITS) - 1) #define TASK_TID_COUNTER_MASK ((1 << TASK_TID_BITS) - TASK_TID_INCREMENT) #if MAX_TASKS > TASK_TID_IDX_MASK #error MAX_TASKS does not fit in TASK_TID_BITS #endif #define OS_SYSTEM_TID 0 #define OS_VER 0x0000 // FIXME: compatibility: keep key ID 1 until key update is functional //#define ENCR_KEY_GOOGLE_PREPOPULATED 0x041F010000000001 #define ENCR_KEY_GOOGLE_PREPOPULATED 1 // our key ID is 1 #define APP_HDR_MAGIC NANOAPP_FW_MAGIC #define APP_HDR_VER_CUR 0 #define FL_APP_HDR_INTERNAL 0x0001 // to be able to fork behavior at run time for internal apps #define FL_APP_HDR_APPLICATION 0x0002 // image has AppHdr; otherwise is has AppInfo header #define FL_APP_HDR_SECURE 0x0004 // secure content, needs to be zero-filled when discarded #define FL_APP_HDR_VOLATILE 0x0008 // volatile content, segment shall be deleted after operation is complete #define FL_KEY_HDR_DELETE 0x8000 // key-specific flag: if set key id refers to existing key which has to be deleted /* app ids are split into vendor and app parts. vendor parts are assigned by google. App parts are free for each vendor to assign at will */ #define APP_ID_FIRST_USABLE 0x0100000000000000ULL //all app ids lower than this are reserved for google's internal use #define APP_ID_GET_VENDOR(appid) ((appid) >> 24) #define APP_ID_GET_SEQ_ID(appid) ((appid) & 0xFFFFFF) #define APP_ID_MAKE(vendor, app) ((((uint64_t)(vendor)) << 24) | ((app) & APP_SEQ_ID_ANY)) #define KEY_ID_MAKE(vendor, key) ((((uint64_t)(vendor)) << 24) | ((key) & KEY_SEQ_ID_ANY)) #define APP_ID_VENDOR_GOOGLE UINT64_C(0x476F6F676C) // "Googl" #define APP_VENDOR_ANY UINT64_C(0xFFFFFFFFFF) #define APP_SEQ_ID_ANY UINT64_C(0xFFFFFF) #define KEY_SEQ_ID_ANY UINT64_C(0xFFFFFF) #define APP_ID_ANY UINT64_C(0xFFFFFFFFFFFFFFFF) #define APP_INFO_CMD_ADD_KEY 1 #define APP_INFO_CMD_REMOVE_KEY 2 #define APP_INFO_CMD_OS_UPDATE 3 #define SEG_STATE_INVALID UINT32_C(0xFFFFFFFF) #define SEG_SIZE_MAX UINT32_C(0x00FFFFFF) #define SEG_SIZE_INVALID (-1) #define SEG_ST(arg) (((arg) << 4) | (arg)) #define SEG_ID_EMPTY 0xF #define SEG_ID_RESERVED 0x7 // upload in progress #define SEG_ID_VALID 0x3 // CRC-32 valid #define SEG_ID_ERASED 0x0 // segment erased #define SEG_ST_EMPTY SEG_ST(SEG_ID_EMPTY) #define SEG_ST_RESERVED SEG_ST(SEG_ID_RESERVED) #define SEG_ST_VALID SEG_ST(SEG_ID_VALID) #define SEG_ST_ERASED SEG_ST(SEG_ID_ERASED) struct Segment { uint8_t state; // 0xFF: empty; bit7=0: segment present; bit6=0: size valid; bit5=0: CRC-32 valid; bit4=0:segment erased; // bits 3-0 replicate bits7-4; uint8_t size[3]; // actual stored size in flash, initially filled with 0xFF // updated after flash operation is completed (successfully or not) }; struct AppEventFreeData { //goes with EVT_APP_FREE_EVT_DATA uint32_t evtType; void* evtData; }; typedef void (*OsDeferCbkF)(void *); typedef void (*EventFreeF)(void* event); SET_PACKED_STRUCT_MODE_ON struct SeosEedataEncrKeyData { uint64_t keyID; uint8_t key[32]; } ATTRIBUTE_PACKED; SET_PACKED_STRUCT_MODE_OFF /* ==== ABOUT THE "urgent" FLAG ==== * * Do not set "urgent" unless you understand all the repercussions! What repercussions you might ask? * Setting this flag will place your defer request at the front of the queue. This is useful for enqueueing work * from interrupt context that needs to be done "very very soon"(tm). Doing this will delay all other work requests * that have heretofore been peacefully queueing in full faith and with complete belief in fairness of our "FIFO"-ness. * Please be appreciative of this fact and do not abuse this! Example: if you are setting "urgent" flag outside of interrupt * context, you're very very likely wrong. That is not to say that being in interrupt context is a free pass to set this! */ // osMainInit is exposed for testing only, it must never be called for any reason at all by anyone void osMainInit(void); // osMainDequeueLoop is exposed for testing only, it must never be called for any reason at all by anyone void osMainDequeueLoop(void); void osMain(void); bool osEventSubscribe(uint32_t tid, uint32_t evtType); /* async */ bool osEventUnsubscribe(uint32_t tid, uint32_t evtType); /* async */ bool osEnqueuePrivateEvt(uint32_t evtType, void *evtData, EventFreeF evtFreeF, uint32_t toTid); bool osEnqueuePrivateEvtAsApp(uint32_t evtType, void *evtData, uint32_t fromApp, uint32_t toTid); bool osEnqueueEvt(uint32_t evtType, void *evtData, EventFreeF evtFreeF); bool osEnqueueEvtOrFree(uint32_t evtType, void *evtData, EventFreeF evtFreeF); bool osEnqueueEvtAsApp(uint32_t evtType, void *evtData, uint32_t fromApp); bool osDefer(OsDeferCbkF callback, void *cookie, bool urgent); bool osTidById(uint64_t appId, uint32_t *tid); bool osAppInfoById(uint64_t appId, uint32_t *appIdx, uint32_t *appVer, uint32_t *appSize); bool osAppInfoByIndex(uint32_t appIdx, uint64_t *appId, uint32_t *appVer, uint32_t *appSize); uint32_t osGetCurrentTid(); uint32_t osSetCurrentTid(uint32_t); struct AppHdr *osAppSegmentCreate(uint32_t size); bool osAppSegmentClose(struct AppHdr *app, uint32_t segSize, uint32_t segState); bool osAppSegmentSetState(const struct AppHdr *app, uint32_t segState); bool osSegmentSetSize(struct Segment *seg, uint32_t size); bool osAppWipeData(struct AppHdr *app); struct Segment *osGetSegment(const struct AppHdr *app); struct Segment *osSegmentGetEnd(); static inline int32_t osSegmentGetSize(const struct Segment *seg) { return seg ? seg->size[0] | (seg->size[1] << 8) | (seg->size[2] << 16) : SEG_SIZE_INVALID; } static inline uint32_t osSegmentGetState(const struct Segment *seg) { return seg ? seg->state : SEG_STATE_INVALID; } static inline struct AppHdr *osSegmentGetData(const struct Segment *seg) { return (struct AppHdr*)(&seg[1]); } #ifdef SEGMENT_CRC_SUPPORT struct SegmentFooter { uint32_t crc; }; #define FOOTER_SIZE sizeof(struct SegmentFooter) #else #define FOOTER_SIZE 0 #endif static inline uint32_t osSegmentSizeAlignedWithFooter(uint32_t size) { return ((size + 3) & ~3) + FOOTER_SIZE; } static inline const struct Segment *osSegmentSizeGetNext(const struct Segment *seg, uint32_t size) { struct Segment *next = (struct Segment *)(((uint8_t*)seg) + osSegmentSizeAlignedWithFooter(size) + sizeof(*seg) ); return seg ? next : NULL; } static inline const struct Segment *osSegmentGetNext(const struct Segment *seg) { return osSegmentSizeGetNext(seg, osSegmentGetSize(seg)); } static inline uint32_t osAppSegmentGetState(const struct AppHdr *app) { return osSegmentGetState(osGetSegment(app)); } struct SegmentIterator { const struct Segment *shared; const struct Segment *sharedEnd; const struct Segment *seg; }; void osSegmentIteratorInit(struct SegmentIterator *it); static inline bool osSegmentIteratorNext(struct SegmentIterator *it) { const struct Segment *seg = it->shared; const struct Segment *next = seg < it->sharedEnd ? osSegmentGetNext(seg) : it->sharedEnd; it->shared = next; it->seg = seg; return seg < it->sharedEnd; } bool osWriteShared(void *dest, const void *src, uint32_t len); bool osEraseShared(); //event retaining support bool osRetainCurrentEvent(TaggedPtr *evtFreeingInfoP); //called from any apps' event handling to retain current event. Only valid for first app that tries. evtFreeingInfoP filled by call and used to free evt later void osFreeRetainedEvent(uint32_t evtType, void *evtData, TaggedPtr *evtFreeingInfoP); uint32_t osExtAppStopApps(uint64_t appId); uint32_t osExtAppEraseApps(uint64_t appId); uint32_t osExtAppStartApps(uint64_t appId); /* Logging */ enum LogLevel { LOG_ERROR = 'E', LOG_WARN = 'W', LOG_INFO = 'I', LOG_DEBUG = 'D', }; void osLogv(enum LogLevel level, const char *str, va_list vl); void osLog(enum LogLevel level, const char *str, ...) PRINTF_ATTRIBUTE; #ifndef INTERNAL_APP_INIT #define INTERNAL_APP_INIT(_id, _ver, _init, _end, _event) \ SET_INTERNAL_LOCATION(location, ".internal_app_init")static const struct AppHdr \ SET_INTERNAL_LOCATION_ATTRIBUTES(used, section (".internal_app_init")) mAppHdr = { \ .hdr.magic = APP_HDR_MAGIC, \ .hdr.fwVer = APP_HDR_VER_CUR, \ .hdr.fwFlags = FL_APP_HDR_INTERNAL | FL_APP_HDR_APPLICATION, \ .hdr.appId = (_id), \ .hdr.appVer = (_ver), \ .hdr.payInfoType = LAYOUT_APP, \ .vec.init = (uint32_t)(_init), \ .vec.end = (uint32_t)(_end), \ .vec.handle = (uint32_t)(_event) \ } #endif #ifndef APP_INIT #define APP_INIT(_ver, _init, _end, _event) \ extern const struct AppFuncs _mAppFuncs; \ const struct AppFuncs SET_EXTERNAL_APP_ATTRIBUTES(used, section (".app_init"), \ visibility("default")) _mAppFuncs = { \ .init = (_init), \ .end = (_end), \ .handle = (_event) \ }; \ const uint32_t SET_EXTERNAL_APP_VERSION(used, section (".app_version"), \ visibility("default")) _mAppVer = _ver #endif #ifdef __cplusplus } #endif #endif