| /* |
| * 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 <plat/taggedPtr.h> |
| #include <plat/wdt.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <eventQ.h> |
| #include <plat/app.h> |
| #include <eventnums.h> |
| #include <variant/variant.h> |
| #include <crc.h> |
| #include "toolchain.h" |
| |
| #include <nanohub/nanohub.h> |
| |
| #ifndef MAX_TASKS |
| /* Default to 16 tasks, override may come from variant.h */ |
| #define MAX_TASKS 16 |
| #endif |
| |
| #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 1 |
| |
| #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_APP_HDR_CHRE 0x0010 // app is CHRE API compatible |
| #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 KEY_ID_MAKE(vendor, key) ((((uint64_t)(vendor)) << 24) | ((key) & KEY_SEQ_ID_ANY)) |
| #define HW_ID_MAKE(vendor, ver) ((((uint64_t)(vendor)) << 24) | (PLATFORM_ID(ver) & HW_ID_ANY)) |
| #define KEY_SEQ_ID_ANY UINT64_C(0xFFFFFF) |
| #define HW_ID_ANY UINT64_C(0xFFFFFF) |
| #define PLATFORM_ID(ver) ((((PLATFORM_HW_TYPE) & 0xFFFF) << 8) | (ver & 0xFF)) |
| |
| #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; |
| }; |
| |
| struct AppEventStartStop { |
| uint64_t appId; |
| uint32_t version; |
| uint16_t tid; |
| }; |
| |
| 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 osEventsSubscribe(uint32_t numEvts, ...); /* async */ |
| bool osEventsUnsubscribe(uint32_t numEvts, ...); /* async */ |
| |
| bool osEnqueuePrivateEvt(uint32_t evtType, void *evtData, EventFreeF evtFreeF, uint32_t toTid); |
| bool osEnqueuePrivateEvtAsApp(uint32_t evtType, void *evtData, uint32_t toTid); |
| bool osEnqueuePrivateEvtNew(uint16_t evtType, void *evtData, |
| void (*evtFreeCallback)(uint16_t eventType, void *eventData), |
| 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, bool freeData); |
| void osRemovePendingEvents(bool (*match)(uint32_t evtType, const void *evtData, void *context), void *context); |
| |
| bool osDefer(OsDeferCbkF callback, void *cookie, bool urgent); |
| |
| bool osTidById(const 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); |
| bool osExtAppInfoByIndex(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 *osSegmentGetEnd(); |
| uint32_t osSegmentGetFree(); |
| struct Segment *osGetSegment(const struct AppHdr *app); |
| |
| 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]); |
| } |
| |
| struct SegmentFooter |
| { |
| uint32_t crc; |
| }; |
| |
| #define FOOTER_SIZE sizeof(struct SegmentFooter) |
| |
| static inline uint32_t osSegmentGetCrc(const struct Segment *seg) |
| { |
| struct SegmentFooter *footer = (struct SegmentFooter *)(((uint8_t*)seg) + |
| ((osSegmentGetSize(seg) + 3) & ~3) + sizeof(*seg)); |
| return footer ? footer->crc : 0xFFFFFFFF; |
| } |
| |
| 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)); |
| } |
| |
| static inline uint32_t osAppSegmentGetCrc(const struct AppHdr *app) |
| { |
| return osSegmentGetCrc(osGetSegment(app)); |
| } |
| |
| static inline uint32_t osAppSegmentCalcCrcResidue(const struct AppHdr *app) |
| { |
| struct Segment *seg = osGetSegment(app); |
| uint32_t size = osSegmentSizeAlignedWithFooter(osSegmentGetSize(seg)); |
| uint32_t crc; |
| |
| wdtDisableClk(); |
| crc = soft_crc32((uint8_t*)seg, size + sizeof(*seg), ~0); |
| wdtEnableClk(); |
| |
| return crc; |
| } |
| |
| 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 osExtAppStopAppsByAppId(uint64_t appId); |
| uint32_t osExtAppEraseAppsByAppId(uint64_t appId); |
| uint32_t osExtAppStartAppsByAppId(uint64_t appId); |
| |
| bool osAppIsChre(uint16_t tid); |
| uint32_t osAppChreVersion(uint16_t tid); |
| |
| /* Logging */ |
| enum LogLevel { |
| LOG_ERROR = 'E', |
| LOG_WARN = 'W', |
| LOG_INFO = 'I', |
| LOG_DEBUG = 'D', |
| LOG_VERBOSE = 'V', |
| }; |
| |
| void osLogv(char clevel, uint32_t flags, const char *str, va_list vl); |
| void osLog(enum LogLevel level, const char *str, ...) PRINTF_ATTRIBUTE(2, 3); |
| |
| #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 INTERNAL_CHRE_APP_INIT |
| #define INTERNAL_CHRE_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 | FL_APP_HDR_CHRE, \ |
| .hdr.chreApiMajor = 0x01, \ |
| .hdr.chreApiMinor = 0x02, \ |
| .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 |