You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
14 KiB
365 lines
14 KiB
/*
|
|
* 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
|