1552 lines
46 KiB
C
1552 lines
46 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <plat/eeData.h>
|
|
#include <plat/plat.h>
|
|
#include <plat/wdt.h>
|
|
|
|
#include <apInt.h>
|
|
#include <atomic.h>
|
|
#include <bl.h>
|
|
#include <cpu.h>
|
|
#include <crc.h>
|
|
#include <eventQ.h>
|
|
#include <heap.h>
|
|
#include <hostIntf.h>
|
|
#include <mpu.h>
|
|
#include <nanohubPacket.h>
|
|
#include <osApi.h>
|
|
#include <platform.h>
|
|
#include <printf.h>
|
|
#include <sensors.h>
|
|
#include <seos.h>
|
|
#include <seos_priv.h>
|
|
#include <slab.h>
|
|
#include <syscall.h>
|
|
#include <timer.h>
|
|
#include <util.h>
|
|
|
|
#include <nanohub/nanohub.h>
|
|
|
|
#include <chreApi.h>
|
|
|
|
struct TaskPool {
|
|
struct Task data[MAX_TASKS];
|
|
};
|
|
|
|
static struct TaskPool mTaskPool;
|
|
static struct EvtQueue *mEvtsInternal;
|
|
static struct SlabAllocator* mMiscInternalThingsSlab;
|
|
static struct TaskList mFreeTasks;
|
|
static struct TaskList mTasks;
|
|
static struct Task *mCurrentTask;
|
|
static struct Task *mSystemTask;
|
|
static TaggedPtr *mCurEvtEventFreeingInfo = NULL; //used as flag for retaining. NULL when none or already retained
|
|
|
|
static inline void list_init(struct TaskList *l)
|
|
{
|
|
l->prev = l->next = NO_NODE;
|
|
}
|
|
|
|
struct Task *osGetCurrentTask()
|
|
{
|
|
return mCurrentTask;
|
|
}
|
|
|
|
struct Task *osSetCurrentTask(struct Task *task)
|
|
{
|
|
struct Task *old = mCurrentTask;
|
|
while (true) {
|
|
old = mCurrentTask;
|
|
if (atomicCmpXchgPtr((uintptr_t*)&mCurrentTask, (uintptr_t)old, (uintptr_t)task)) {
|
|
break;
|
|
}
|
|
}
|
|
return old;
|
|
}
|
|
|
|
// beyond this point, noone shall access mCurrentTask directly
|
|
|
|
static inline bool osTaskTestFlags(struct Task *task, uint32_t mask)
|
|
{
|
|
return (atomicReadByte(&task->flags) & mask) != 0;
|
|
}
|
|
|
|
bool osAppIsChre(uint16_t tid)
|
|
{
|
|
struct Task *task = osTaskFindByTid(tid);
|
|
|
|
return task && osTaskIsChre(task);
|
|
}
|
|
|
|
uint32_t osAppChreVersion(uint16_t tid)
|
|
{
|
|
struct Task *task = osTaskFindByTid(tid);
|
|
|
|
if (task)
|
|
return osTaskChreVersion(task);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static inline uint32_t osTaskClrSetFlags(struct Task *task, uint32_t clrMask, uint32_t setMask)
|
|
{
|
|
while (true) {
|
|
uint8_t flags = atomicReadByte(&task->flags);
|
|
uint8_t newFlags = (flags & ~clrMask) | setMask;
|
|
if (atomicCmpXchgByte(&task->flags, flags, newFlags))
|
|
return newFlags;
|
|
}
|
|
}
|
|
|
|
static inline uint32_t osTaskAddIoCount(struct Task *task, int32_t delta)
|
|
{
|
|
uint8_t count = atomicAddByte(&task->ioCount, delta);
|
|
|
|
count += delta; // old value is returned, so we add it again
|
|
|
|
return count;
|
|
}
|
|
|
|
static inline uint32_t osTaskGetIoCount(struct Task *task)
|
|
{
|
|
return atomicReadByte(&task->ioCount);
|
|
}
|
|
|
|
uint8_t osTaskIndex(struct Task *task)
|
|
{
|
|
// we don't need signed diff here: this way we simplify boundary check
|
|
size_t idx = task - &mTaskPool.data[0];
|
|
return idx >= MAX_TASKS || &mTaskPool.data[idx] != task ? NO_NODE : idx;
|
|
}
|
|
|
|
static inline struct Task *osTaskByIdx(size_t idx)
|
|
{
|
|
return idx >= MAX_TASKS ? NULL : &mTaskPool.data[idx];
|
|
}
|
|
|
|
uint32_t osGetCurrentTid()
|
|
{
|
|
struct Task *task = osGetCurrentTask();
|
|
if (task == NULL) {
|
|
return UINT32_MAX;
|
|
}
|
|
return task->tid;
|
|
}
|
|
|
|
uint32_t osSetCurrentTid(uint32_t tid)
|
|
{
|
|
struct Task *task = osTaskByIdx(TID_TO_TASK_IDX(tid));
|
|
|
|
if (task && task->tid == tid) {
|
|
struct Task *preempted = osSetCurrentTask(task);
|
|
return preempted->tid;
|
|
}
|
|
|
|
return osGetCurrentTid();
|
|
}
|
|
|
|
static inline struct Task *osTaskListPeekHead(struct TaskList *listHead)
|
|
{
|
|
TaskIndex idx = listHead->next;
|
|
return idx == NO_NODE ? NULL : &mTaskPool.data[idx];
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static void dumpListItems(const char *p, struct TaskList *listHead)
|
|
{
|
|
int i = 0;
|
|
struct Task *task;
|
|
|
|
osLog(LOG_ERROR, "List: %s (%p) [%u;%u]\n",
|
|
p,
|
|
listHead,
|
|
listHead ? listHead->prev : NO_NODE,
|
|
listHead ? listHead->next : NO_NODE
|
|
);
|
|
if (!listHead)
|
|
return;
|
|
|
|
for_each_task(listHead, task) {
|
|
osLog(LOG_ERROR, " item %d: task=%p TID=%04X [%u;%u;%u]\n",
|
|
i,
|
|
task,
|
|
task->tid,
|
|
task->list.prev,
|
|
osTaskIndex(task),
|
|
task->list.next
|
|
);
|
|
++i;
|
|
}
|
|
}
|
|
|
|
static void dumpTaskList(const char *f, struct Task *task, struct TaskList *listHead)
|
|
{
|
|
osLog(LOG_ERROR, "%s: pool: %p; task=%p [%u;%u;%u]; listHead=%p [%u;%u]\n",
|
|
f,
|
|
&mTaskPool,
|
|
task,
|
|
task ? task->list.prev : NO_NODE,
|
|
osTaskIndex(task),
|
|
task ? task->list.next : NO_NODE,
|
|
listHead,
|
|
listHead ? listHead->prev : NO_NODE,
|
|
listHead ? listHead->next : NO_NODE
|
|
);
|
|
dumpListItems("Tasks", &mTasks);
|
|
dumpListItems("Free Tasks", &mFreeTasks);
|
|
}
|
|
#else
|
|
#define dumpTaskList(a,b,c)
|
|
#endif
|
|
|
|
static inline void osTaskListRemoveTask(struct TaskList *listHead, struct Task *task)
|
|
{
|
|
if (task && listHead) {
|
|
struct TaskList *cur = &task->list;
|
|
TaskIndex left_idx = cur->prev;
|
|
TaskIndex right_idx = cur->next;
|
|
struct TaskList *left = left_idx == NO_NODE ? listHead : &mTaskPool.data[left_idx].list;
|
|
struct TaskList *right = right_idx == NO_NODE ? listHead : &mTaskPool.data[right_idx].list;
|
|
cur->prev = cur->next = NO_NODE;
|
|
left->next = right_idx;
|
|
right->prev = left_idx;
|
|
} else {
|
|
dumpTaskList(__func__, task, listHead);
|
|
}
|
|
}
|
|
|
|
static inline void osTaskListAddTail(struct TaskList *listHead, struct Task *task)
|
|
{
|
|
if (task && listHead) {
|
|
struct TaskList *cur = &task->list;
|
|
TaskIndex last_idx = listHead->prev;
|
|
TaskIndex new_idx = osTaskIndex(task);
|
|
struct TaskList *last = last_idx == NO_NODE ? listHead : &mTaskPool.data[last_idx].list;
|
|
cur->prev = last_idx;
|
|
cur->next = NO_NODE;
|
|
last->next = new_idx;
|
|
listHead->prev = new_idx;
|
|
} else {
|
|
dumpTaskList(__func__, task, listHead);
|
|
}
|
|
}
|
|
|
|
static struct Task *osAllocTask()
|
|
{
|
|
struct Task *task = osTaskListPeekHead(&mFreeTasks);
|
|
|
|
if (task) {
|
|
osTaskListRemoveTask(&mFreeTasks, task);
|
|
uint16_t tid = task->tid;
|
|
memset(task, 0, sizeof(*task));
|
|
task->tid = tid;
|
|
}
|
|
|
|
return task;
|
|
}
|
|
|
|
static void osFreeTask(struct Task *task)
|
|
{
|
|
if (task) {
|
|
task->flags = 0;
|
|
task->ioCount = 0;
|
|
osTaskListAddTail(&mFreeTasks, task);
|
|
}
|
|
}
|
|
|
|
static void osRemoveTask(struct Task *task)
|
|
{
|
|
osTaskListRemoveTask(&mTasks, task);
|
|
}
|
|
|
|
static void osAddTask(struct Task *task)
|
|
{
|
|
osTaskListAddTail(&mTasks, task);
|
|
}
|
|
|
|
struct Task* osTaskFindByTid(uint32_t tid)
|
|
{
|
|
TaskIndex idx = TID_TO_TASK_IDX(tid);
|
|
|
|
return idx < MAX_TASKS ? &mTaskPool.data[idx] : NULL;
|
|
}
|
|
|
|
static inline bool osTaskInit(struct Task *task)
|
|
{
|
|
struct Task *preempted = osSetCurrentTask(task);
|
|
bool done = cpuAppInit(task->app, &task->platInfo, task->tid);
|
|
osSetCurrentTask(preempted);
|
|
return done;
|
|
}
|
|
|
|
static void osTaskRelease(struct Task *task)
|
|
{
|
|
uint32_t taskTid = task->tid;
|
|
uint32_t platErr, sensorErr;
|
|
int timErr, heapErr;
|
|
uint64_t appId;
|
|
|
|
if (task->app)
|
|
appId = task->app->hdr.appId;
|
|
else
|
|
appId = 0;
|
|
|
|
platErr = platFreeResources(taskTid); // HW resources cleanup (IRQ, DMA etc)
|
|
sensorErr = sensorFreeAll(taskTid);
|
|
timErr = timTimerCancelAll(taskTid);
|
|
heapErr = heapFreeAll(taskTid);
|
|
|
|
if (platErr || sensorErr || timErr || heapErr)
|
|
osLog(LOG_WARN, "released app ID 0x%" PRIx64 "; plat:%08" PRIx32 " sensor:%08" PRIx32 " tim:%d heap:%d; TID %04" PRIX32 "\n", appId, platErr, sensorErr, timErr, heapErr, taskTid);
|
|
else
|
|
osLog(LOG_INFO, "released app ID 0x%" PRIx64 "; TID %04" PRIX32 "\n", appId, taskTid);
|
|
}
|
|
|
|
static inline void osTaskEnd(struct Task *task)
|
|
{
|
|
if (!osTaskTestFlags(task, FL_TASK_ABORTED)) {
|
|
struct Task *preempted = osSetCurrentTask(task);
|
|
cpuAppEnd(task->app, &task->platInfo);
|
|
osSetCurrentTask(preempted);
|
|
}
|
|
|
|
// task was supposed to release it's resources,
|
|
// but we do our cleanup anyway
|
|
// NOTE: we don't need to unsubscribe from events
|
|
osTaskRelease(task);
|
|
}
|
|
|
|
static inline void osTaskHandle(struct Task *task, uint16_t evtType, uint16_t fromTid, const void* evtData)
|
|
{
|
|
struct Task *preempted = osSetCurrentTask(task);
|
|
cpuAppHandle(task->app, &task->platInfo,
|
|
EVENT_WITH_ORIGIN(evtType, osTaskIsChre(task) ? fromTid : 0),
|
|
evtData);
|
|
osSetCurrentTask(preempted);
|
|
}
|
|
|
|
void osTaskInvokeMessageFreeCallback(struct Task *task, void (*freeCallback)(void *, size_t), void *message, uint32_t messageSize)
|
|
{
|
|
if (!task || !freeCallback)
|
|
return;
|
|
cpuAppInvoke(task->app, &task->platInfo, (void (*)(uintptr_t,uintptr_t))freeCallback, (uintptr_t)message, (uintptr_t)messageSize);
|
|
}
|
|
|
|
void osTaskInvokeEventFreeCallback(struct Task *task, void (*freeCallback)(uint16_t, void *), uint16_t event, void *data)
|
|
{
|
|
if (!task || !freeCallback)
|
|
return;
|
|
cpuAppInvoke(task->app, &task->platInfo,
|
|
(void (*)(uintptr_t,uintptr_t))freeCallback,
|
|
(uintptr_t)event, (uintptr_t)data);
|
|
}
|
|
|
|
static void osPrivateEvtFreeF(void *event)
|
|
{
|
|
union SeosInternalSlabData *act = event;
|
|
uint16_t fromTid = act->privateEvt.fromTid;
|
|
struct Task *srcTask = osTaskFindByTid(fromTid);
|
|
TaggedPtr evtFreeInfo = act->privateEvt.evtFreeInfo;
|
|
uint32_t evtType = act->privateEvt.evtType;
|
|
void *evtData = act->privateEvt.evtData;
|
|
|
|
slabAllocatorFree(mMiscInternalThingsSlab, event);
|
|
|
|
if (!srcTask) {
|
|
osLog(LOG_ERROR, "ERROR: Failed to find task to free event: evtType=%08" PRIX32 "\n", evtType);
|
|
return;
|
|
}
|
|
|
|
if (taggedPtrIsPtr(evtFreeInfo) && taggedPtrToPtr(evtFreeInfo)) {
|
|
if (osTaskIsChre(srcTask) && (evtType >> 16) == EVT_PRIVATE_CLASS_CHRE) {
|
|
osChreFreeEvent(fromTid,
|
|
(void (*)(uint16_t, void *))taggedPtrToPtr(evtFreeInfo),
|
|
evtType & EVT_MASK, evtData);
|
|
} else {
|
|
// this is for internal non-CHRE tasks, and CHRE tasks
|
|
// System may schedule non-CHRE events on behalf of CHRE app;
|
|
// this is the place we release them
|
|
struct Task *preempted = osSetCurrentTask(srcTask);
|
|
((EventFreeF)taggedPtrToPtr(evtFreeInfo))(evtData);
|
|
osSetCurrentTask(preempted);
|
|
}
|
|
} else if (taggedPtrIsUint(evtFreeInfo)) {
|
|
// this is for external non-CHRE tasks
|
|
struct AppEventFreeData fd = {.evtType = evtType, .evtData = evtData};
|
|
osTaskHandle(srcTask, EVT_APP_FREE_EVT_DATA, OS_SYSTEM_TID, &fd);
|
|
}
|
|
|
|
osTaskAddIoCount(srcTask, -1);
|
|
}
|
|
|
|
static void handleEventFreeing(uint32_t evtType, void *evtData, TaggedPtr evtFreeData) // watch out, this is synchronous
|
|
{
|
|
struct Task *srcTask = osTaskFindByTid(EVENT_GET_ORIGIN(evtType));
|
|
|
|
if (!srcTask) {
|
|
osLog(LOG_ERROR, "ERROR: Failed to find task to free event: evtType=%08" PRIX32 "\n", evtType);
|
|
return;
|
|
}
|
|
|
|
// release non-CHRE event; we can't determine if this is CHRE or non-CHRE event, but
|
|
// this method is only called to release non-CHRE events, so we make use of that fact
|
|
|
|
if (taggedPtrIsPtr(evtFreeData) && taggedPtrToPtr(evtFreeData)) {
|
|
// this is for internal non-CHRE tasks, and CHRE tasks
|
|
// System may schedule non-CHRE events on behalf of CHRE app;
|
|
// this is the place we release them
|
|
struct Task *preempted = osSetCurrentTask(srcTask);
|
|
((EventFreeF)taggedPtrToPtr(evtFreeData))(evtData);
|
|
osSetCurrentTask(preempted);
|
|
} else if (taggedPtrIsUint(evtFreeData)) {
|
|
// this is for external non-CHRE tasks
|
|
struct AppEventFreeData fd = {.evtType = EVENT_GET_EVENT(evtType), .evtData = evtData};
|
|
osTaskHandle(srcTask, EVT_APP_FREE_EVT_DATA, OS_SYSTEM_TID, &fd);
|
|
}
|
|
|
|
osTaskAddIoCount(srcTask, -1);
|
|
}
|
|
|
|
static void osInit(void)
|
|
{
|
|
heapInit();
|
|
platInitialize();
|
|
|
|
osLog(LOG_INFO, "SEOS Initializing\n");
|
|
cpuInitLate();
|
|
|
|
/* create the queues */
|
|
if (!(mEvtsInternal = evtQueueAlloc(512, handleEventFreeing))) {
|
|
osLog(LOG_INFO, "events failed to init\n");
|
|
return;
|
|
}
|
|
|
|
mMiscInternalThingsSlab = slabAllocatorNew(sizeof(union SeosInternalSlabData), alignof(union SeosInternalSlabData), 64 /* for now? */);
|
|
if (!mMiscInternalThingsSlab) {
|
|
osLog(LOG_INFO, "deferred actions list failed to init\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
static struct Task* osTaskFindByAppID(uint64_t appID)
|
|
{
|
|
struct Task *task;
|
|
|
|
for_each_task(&mTasks, task) {
|
|
if (task->app && task->app->hdr.appId == appID)
|
|
return task;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void osSegmentIteratorInit(struct SegmentIterator *it)
|
|
{
|
|
uint32_t sz;
|
|
uint8_t *start = platGetSharedAreaInfo(&sz);
|
|
|
|
it->shared = (const struct Segment *)(start);
|
|
it->sharedEnd = (const struct Segment *)(start + sz);
|
|
it->seg = NULL;
|
|
}
|
|
|
|
bool osAppSegmentSetState(const struct AppHdr *app, uint32_t segState)
|
|
{
|
|
bool done;
|
|
struct Segment *seg = osGetSegment(app);
|
|
uint8_t state = segState;
|
|
|
|
if (!seg)
|
|
return false;
|
|
|
|
mpuAllowRamExecution(true);
|
|
mpuAllowRomWrite(true);
|
|
done = BL.blProgramShared(&seg->state, &state, sizeof(state), BL_FLASH_KEY1, BL_FLASH_KEY2);
|
|
mpuAllowRomWrite(false);
|
|
mpuAllowRamExecution(false);
|
|
|
|
return done;
|
|
}
|
|
|
|
bool osSegmentSetSize(struct Segment *seg, uint32_t size)
|
|
{
|
|
bool ret = true;
|
|
|
|
if (!seg)
|
|
return false;
|
|
|
|
if (size > SEG_SIZE_MAX) {
|
|
seg->state = SEG_ST_ERASED;
|
|
size = SEG_SIZE_MAX;
|
|
ret = false;
|
|
}
|
|
seg->size[0] = size;
|
|
seg->size[1] = size >> 8;
|
|
seg->size[2] = size >> 16;
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct Segment *osSegmentGetEnd()
|
|
{
|
|
uint32_t size;
|
|
uint8_t *start = platGetSharedAreaInfo(&size);
|
|
return (struct Segment *)(start + size);
|
|
}
|
|
|
|
uint32_t osSegmentGetFree()
|
|
{
|
|
struct SegmentIterator it;
|
|
const struct Segment *storageSeg = NULL;
|
|
|
|
osSegmentIteratorInit(&it);
|
|
while (osSegmentIteratorNext(&it)) {
|
|
if (osSegmentGetState(it.seg) == SEG_ST_EMPTY) {
|
|
storageSeg = it.seg;
|
|
break;
|
|
}
|
|
}
|
|
if (!storageSeg || storageSeg > it.sharedEnd)
|
|
return 0;
|
|
|
|
return (uint8_t *)it.sharedEnd - (uint8_t *)storageSeg;
|
|
}
|
|
|
|
struct Segment *osGetSegment(const struct AppHdr *app)
|
|
{
|
|
uint32_t size;
|
|
uint8_t *start = platGetSharedAreaInfo(&size);
|
|
|
|
return (struct Segment *)((uint8_t*)app &&
|
|
(uint8_t*)app >= start &&
|
|
(uint8_t*)app < (start + size) ?
|
|
(uint8_t*)app - sizeof(struct Segment) : NULL);
|
|
}
|
|
|
|
bool osEraseShared()
|
|
{
|
|
wdtDisableClk();
|
|
mpuAllowRamExecution(true);
|
|
mpuAllowRomWrite(true);
|
|
(void)BL.blEraseShared(BL_FLASH_KEY1, BL_FLASH_KEY2);
|
|
mpuAllowRomWrite(false);
|
|
mpuAllowRamExecution(false);
|
|
wdtEnableClk();
|
|
return true;
|
|
}
|
|
|
|
bool osWriteShared(void *dest, const void *src, uint32_t len)
|
|
{
|
|
bool ret;
|
|
|
|
mpuAllowRamExecution(true);
|
|
mpuAllowRomWrite(true);
|
|
ret = BL.blProgramShared(dest, src, len, BL_FLASH_KEY1, BL_FLASH_KEY2);
|
|
mpuAllowRomWrite(false);
|
|
mpuAllowRamExecution(false);
|
|
|
|
if (!ret)
|
|
osLog(LOG_ERROR, "osWriteShared: blProgramShared return false\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct AppHdr *osAppSegmentCreate(uint32_t size)
|
|
{
|
|
struct SegmentIterator it;
|
|
const struct Segment *storageSeg = NULL;
|
|
struct AppHdr *app;
|
|
|
|
osSegmentIteratorInit(&it);
|
|
while (osSegmentIteratorNext(&it)) {
|
|
if (osSegmentGetState(it.seg) == SEG_ST_EMPTY) {
|
|
storageSeg = it.seg;
|
|
break;
|
|
}
|
|
}
|
|
if (!storageSeg || osSegmentSizeGetNext(storageSeg, size) > it.sharedEnd)
|
|
return NULL;
|
|
|
|
app = osSegmentGetData(storageSeg);
|
|
osAppSegmentSetState(app, SEG_ST_RESERVED);
|
|
|
|
return app;
|
|
}
|
|
|
|
bool osAppSegmentClose(struct AppHdr *app, uint32_t segDataSize, uint32_t segState)
|
|
{
|
|
struct Segment seg;
|
|
|
|
// this is enough for holding padding to uint32_t and the footer
|
|
uint8_t footer[sizeof(uint32_t) + FOOTER_SIZE];
|
|
int footerLen;
|
|
bool ret;
|
|
uint32_t totalSize;
|
|
uint8_t *start = platGetSharedAreaInfo(&totalSize);
|
|
uint8_t *end = start + totalSize;
|
|
int32_t fullSize = segDataSize + sizeof(seg); // without footer or padding
|
|
struct Segment *storageSeg = osGetSegment(app);
|
|
|
|
// sanity check
|
|
if (segDataSize >= SEG_SIZE_MAX)
|
|
return false;
|
|
|
|
// physical limits check
|
|
if (osSegmentSizeAlignedWithFooter(segDataSize) + sizeof(struct Segment) > totalSize)
|
|
return false;
|
|
|
|
// available space check: we could truncate size, instead of disallowing it,
|
|
// but we know that we performed validation on the size before, in *Create call,
|
|
// and it was fine, so this must be a programming error, and so we fail.
|
|
// on a side note: size may grow or shrink compared to original estimate.
|
|
// typically it shrinks, since we skip some header info and padding, as well
|
|
// as signature blocks, but it is possible that at some point we may produce
|
|
// more data for some reason. At that time the logic here may need to change
|
|
if (osSegmentSizeGetNext(storageSeg, segDataSize) > (struct Segment*)end)
|
|
return false;
|
|
|
|
seg.state = segState;
|
|
osSegmentSetSize(&seg, segDataSize);
|
|
|
|
ret = osWriteShared((uint8_t*)storageSeg, (uint8_t*)&seg, sizeof(seg));
|
|
|
|
footerLen = (-fullSize) & 3;
|
|
memset(footer, 0x00, footerLen);
|
|
|
|
wdtDisableClk();
|
|
struct SegmentFooter segFooter = {
|
|
.crc = ~soft_crc32(storageSeg, fullSize, ~0),
|
|
};
|
|
wdtEnableClk();
|
|
memcpy(&footer[footerLen], &segFooter, sizeof(segFooter));
|
|
footerLen += sizeof(segFooter);
|
|
|
|
if (ret && footerLen)
|
|
ret = osWriteShared((uint8_t*)storageSeg + fullSize, footer, footerLen);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool osAppWipeData(struct AppHdr *app)
|
|
{
|
|
struct Segment *seg = osGetSegment(app);
|
|
int32_t size = osSegmentGetSize(seg);
|
|
uint8_t *p = (uint8_t*)app;
|
|
uint32_t state = osSegmentGetState(seg);
|
|
uint8_t buf[256];
|
|
bool done = true;
|
|
|
|
if (!seg || size == SEG_SIZE_INVALID || state == SEG_ST_EMPTY) {
|
|
osLog(LOG_ERROR, "%s: can't erase segment: app=%p; seg=%p"
|
|
"; size=%" PRIu32
|
|
"; state=%" PRIu32
|
|
"\n",
|
|
__func__, app, seg, size, state);
|
|
return false;
|
|
}
|
|
|
|
size = osSegmentSizeAlignedWithFooter(size);
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
while (size > 0) {
|
|
uint32_t flashSz = size > sizeof(buf) ? sizeof(buf) : size;
|
|
// keep trying to zero-out stuff even in case of intermittent failures.
|
|
// flash write may occasionally fail on some byte, but it is not good enough
|
|
// reason to not rewrite other bytes
|
|
bool res = osWriteShared(p, buf, flashSz);
|
|
done = done && res;
|
|
size -= flashSz;
|
|
p += flashSz;
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
static inline bool osAppIsValid(const struct AppHdr *app)
|
|
{
|
|
return app->hdr.magic == APP_HDR_MAGIC &&
|
|
app->hdr.fwVer == APP_HDR_VER_CUR &&
|
|
(app->hdr.fwFlags & FL_APP_HDR_APPLICATION) != 0 &&
|
|
app->hdr.payInfoType == LAYOUT_APP;
|
|
}
|
|
|
|
static bool osExtAppIsValid(const struct AppHdr *app, uint32_t len)
|
|
{
|
|
return osAppIsValid(app) &&
|
|
len >= sizeof(*app) &&
|
|
osAppSegmentGetState(app) == SEG_ST_VALID &&
|
|
osAppSegmentCalcCrcResidue(app) == CRC_RESIDUE &&
|
|
!(app->hdr.fwFlags & FL_APP_HDR_INTERNAL);
|
|
}
|
|
|
|
static bool osIntAppIsValid(const struct AppHdr *app)
|
|
{
|
|
return osAppIsValid(app) &&
|
|
osAppSegmentGetState(app) == SEG_STATE_INVALID &&
|
|
(app->hdr.fwFlags & FL_APP_HDR_INTERNAL) != 0;
|
|
}
|
|
|
|
static inline bool osExtAppErase(const struct AppHdr *app)
|
|
{
|
|
return osAppSegmentSetState(app, SEG_ST_ERASED);
|
|
}
|
|
|
|
static struct Task *osLoadApp(const struct AppHdr *app) {
|
|
struct Task *task;
|
|
|
|
task = osAllocTask();
|
|
if (!task) {
|
|
osLog(LOG_WARN, "External app id %016" PRIX64 " @ %p cannot be used as too many apps already exist.\n", app->hdr.appId, app);
|
|
return NULL;
|
|
}
|
|
task->app = app;
|
|
bool done = (app->hdr.fwFlags & FL_APP_HDR_INTERNAL) ?
|
|
cpuInternalAppLoad(task->app, &task->platInfo) :
|
|
cpuAppLoad(task->app, &task->platInfo);
|
|
|
|
if (!done) {
|
|
osLog(LOG_WARN, "App @ %p ID %016" PRIX64 " failed to load\n", app, app->hdr.appId);
|
|
osFreeTask(task);
|
|
task = NULL;
|
|
}
|
|
|
|
return task;
|
|
}
|
|
|
|
static void osUnloadApp(struct Task *task)
|
|
{
|
|
// this is called on task that has stopped running, or had never run
|
|
cpuAppUnload(task->app, &task->platInfo);
|
|
osFreeTask(task);
|
|
}
|
|
|
|
static bool osStartApp(const struct AppHdr *app)
|
|
{
|
|
bool done = false;
|
|
struct Task *task;
|
|
|
|
if ((task = osLoadApp(app)) != NULL) {
|
|
task->subbedEvtListSz = MAX_EMBEDDED_EVT_SUBS;
|
|
task->subbedEvents = task->subbedEventsInt;
|
|
osTaskMakeNewTid(task);
|
|
|
|
// print external NanoApp info to facilitate NanoApp debugging
|
|
if (!(task->app->hdr.fwFlags & FL_APP_HDR_INTERNAL))
|
|
osLog(LOG_INFO,
|
|
"loaded app ID 0x%" PRIx64 " at flash base 0x%" PRIxPTR " ram base 0x%" PRIxPTR "; TID %04" PRIX16 "\n",
|
|
task->app->hdr.appId, (uintptr_t) task->app, (uintptr_t) task->platInfo.data, task->tid);
|
|
|
|
done = osTaskInit(task);
|
|
|
|
if (!done) {
|
|
osLog(LOG_WARN, "App @ %p ID %016" PRIX64 " failed to init\n", task->app, task->app->hdr.appId);
|
|
osUnloadApp(task);
|
|
} else {
|
|
osAddTask(task);
|
|
(void)osEnqueueEvt(EVT_APP_BEGIN, task, NULL);
|
|
}
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
static bool osStopTask(struct Task *task, bool abort)
|
|
{
|
|
struct Task *preempted;
|
|
|
|
if (!task)
|
|
return false;
|
|
|
|
if (osTaskTestFlags(task, FL_TASK_STOPPED))
|
|
return true;
|
|
|
|
preempted = osSetCurrentTask(mSystemTask);
|
|
osRemoveTask(task);
|
|
osTaskClrSetFlags(task, 0, FL_TASK_STOPPED);
|
|
|
|
if (abort)
|
|
osTaskClrSetFlags(task, 0, FL_TASK_ABORTED);
|
|
else if (osTaskGetIoCount(task))
|
|
osTaskHandle(task, EVT_APP_STOP, OS_SYSTEM_TID, NULL);
|
|
osEnqueueEvt(EVT_APP_END, task, NULL);
|
|
|
|
osSetCurrentTask(preempted);
|
|
|
|
return true;
|
|
}
|
|
|
|
void osTaskAbort(struct Task *task)
|
|
{
|
|
osStopTask(task, true);
|
|
}
|
|
|
|
static bool matchAutoStart(const void *cookie, const struct AppHdr *app)
|
|
{
|
|
bool match = (bool)cookie;
|
|
|
|
if (app->hdr.fwFlags & FL_APP_HDR_CHRE) {
|
|
if (app->hdr.chreApiMajor == 0xFF && app->hdr.chreApiMinor == 0xFF)
|
|
return match;
|
|
else if ((app->hdr.chreApiMajor < 0x01) ||
|
|
(app->hdr.chreApiMajor == 0x01 && app->hdr.chreApiMinor < 0x01))
|
|
return match;
|
|
else
|
|
return !match;
|
|
} else {
|
|
return match;
|
|
}
|
|
}
|
|
|
|
static bool matchAppId(const void *data, const struct AppHdr *app)
|
|
{
|
|
uint64_t appId, vendor, seqId, curAppId;
|
|
|
|
memcpy(&appId, data, sizeof(appId));
|
|
vendor = APP_ID_GET_VENDOR(appId);
|
|
seqId = APP_ID_GET_SEQ_ID(appId);
|
|
curAppId = app->hdr.appId;
|
|
|
|
if ((vendor == APP_VENDOR_ANY || vendor == APP_ID_GET_VENDOR(curAppId)) &&
|
|
(seqId == APP_SEQ_ID_ANY || seqId == APP_ID_GET_SEQ_ID(curAppId))) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool osExtAppFind(struct SegmentIterator *it, appMatchFunc func, const void *data)
|
|
{
|
|
const struct AppHdr *app;
|
|
const struct Segment *seg;
|
|
|
|
while (osSegmentIteratorNext(it)) {
|
|
seg = it->seg;
|
|
if (!seg)
|
|
break;
|
|
if (seg->state == SEG_ST_EMPTY)
|
|
break;
|
|
if (seg->state != SEG_ST_VALID)
|
|
continue;
|
|
app = osSegmentGetData(seg);
|
|
if (func(data, app))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static uint32_t osExtAppStopEraseApps(appMatchFunc func, const void *data, bool doErase)
|
|
{
|
|
const struct AppHdr *app;
|
|
int32_t len;
|
|
struct SegmentIterator it;
|
|
uint32_t stopCount = 0;
|
|
uint32_t eraseCount = 0;
|
|
uint32_t appCount = 0;
|
|
uint32_t taskCount = 0;
|
|
struct MgmtStatus stat = { .value = 0 };
|
|
struct Task *task;
|
|
|
|
osSegmentIteratorInit(&it);
|
|
while (osExtAppFind(&it, func, data)) {
|
|
app = osSegmentGetData(it.seg);
|
|
len = osSegmentGetSize(it.seg);
|
|
if (!osExtAppIsValid(app, len))
|
|
continue;
|
|
appCount++;
|
|
/* it is safe to erase a running app;
|
|
* erase merely sets a flag in the header,
|
|
* and app keeps running until it is stopped */
|
|
if (doErase && osExtAppErase(app))
|
|
eraseCount++;
|
|
task = osTaskFindByAppID(app->hdr.appId);
|
|
if (task) {
|
|
taskCount++;
|
|
if (osStopTask(task, false))
|
|
stopCount++;
|
|
}
|
|
}
|
|
SET_COUNTER(stat.app, appCount);
|
|
SET_COUNTER(stat.task, taskCount);
|
|
SET_COUNTER(stat.op, stopCount);
|
|
SET_COUNTER(stat.erase, eraseCount);
|
|
|
|
return stat.value;
|
|
}
|
|
|
|
uint32_t osExtAppStopAppsByAppId(uint64_t appId)
|
|
{
|
|
return osExtAppStopEraseApps(matchAppId, &appId, false);
|
|
}
|
|
|
|
uint32_t osExtAppEraseAppsByAppId(uint64_t appId)
|
|
{
|
|
return osExtAppStopEraseApps(matchAppId, &appId, true);
|
|
}
|
|
|
|
static void osScanExternal()
|
|
{
|
|
struct SegmentIterator it;
|
|
osSegmentIteratorInit(&it);
|
|
while (osSegmentIteratorNext(&it)) {
|
|
switch (osSegmentGetState(it.seg)) {
|
|
case SEG_ST_EMPTY:
|
|
// everything looks good
|
|
osLog(LOG_INFO, "External area is good\n");
|
|
return;
|
|
case SEG_ST_ERASED:
|
|
case SEG_ST_VALID:
|
|
// this is valid stuff, ignore
|
|
break;
|
|
case SEG_ST_RESERVED:
|
|
default:
|
|
// something is wrong: erase everything
|
|
osLog(LOG_ERROR, "External area is damaged. Erasing\n");
|
|
osEraseShared();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint32_t osExtAppStartApps(appMatchFunc func, void *data)
|
|
{
|
|
const struct AppHdr *app;
|
|
int32_t len;
|
|
struct SegmentIterator it;
|
|
struct SegmentIterator checkIt;
|
|
uint32_t startCount = 0;
|
|
uint32_t eraseCount = 0;
|
|
uint32_t appCount = 0;
|
|
uint32_t taskCount = 0;
|
|
struct MgmtStatus stat = { .value = 0 };
|
|
|
|
osScanExternal();
|
|
|
|
osSegmentIteratorInit(&it);
|
|
while (osExtAppFind(&it, func, data)) {
|
|
app = osSegmentGetData(it.seg);
|
|
len = osSegmentGetSize(it.seg);
|
|
|
|
// skip erased or malformed apps
|
|
if (!osExtAppIsValid(app, len))
|
|
continue;
|
|
|
|
appCount++;
|
|
checkIt = it;
|
|
// find the most recent copy
|
|
while (osExtAppFind(&checkIt, matchAppId, &app->hdr.appId)) {
|
|
if (osExtAppErase(app)) // erase the old one, so we skip it next time
|
|
eraseCount++;
|
|
app = osSegmentGetData(checkIt.seg);
|
|
}
|
|
|
|
if (osTaskFindByAppID(app->hdr.appId)) {
|
|
// this either the most recent external app with the same ID,
|
|
// or internal app with the same id; in both cases we do nothing
|
|
taskCount++;
|
|
continue;
|
|
}
|
|
|
|
if (osStartApp(app))
|
|
startCount++;
|
|
}
|
|
SET_COUNTER(stat.app, appCount);
|
|
SET_COUNTER(stat.task, taskCount);
|
|
SET_COUNTER(stat.op, startCount);
|
|
SET_COUNTER(stat.erase, eraseCount);
|
|
|
|
return stat.value;
|
|
}
|
|
|
|
uint32_t osExtAppStartAppsByAppId(uint64_t appId)
|
|
{
|
|
return osExtAppStartApps(matchAppId, &appId);
|
|
}
|
|
|
|
static void osStartTasks(void)
|
|
{
|
|
const struct AppHdr *app;
|
|
uint32_t i, nApps;
|
|
struct Task* task;
|
|
uint32_t status = 0;
|
|
uint32_t taskCnt = 0;
|
|
|
|
osLog(LOG_DEBUG, "Initializing task pool...\n");
|
|
list_init(&mTasks);
|
|
list_init(&mFreeTasks);
|
|
for (i = 0; i < MAX_TASKS; ++i) {
|
|
task = &mTaskPool.data[i];
|
|
list_init(&task->list);
|
|
osFreeTask(task);
|
|
}
|
|
|
|
mSystemTask = osAllocTask(); // this is a dummy task; holder of TID 0; all system code will run with TID 0
|
|
osSetCurrentTask(mSystemTask);
|
|
osLog(LOG_DEBUG, "System task is: %p\n", mSystemTask);
|
|
|
|
/* first enum all internal apps, making sure to check for dupes */
|
|
osLog(LOG_DEBUG, "Starting internal apps...\n");
|
|
for (i = 0, app = platGetInternalAppList(&nApps); i < nApps; i++, app++) {
|
|
if (!osIntAppIsValid(app)) {
|
|
osLog(LOG_WARN, "Invalid internal app @ %p ID %016" PRIX64
|
|
"header version: %" PRIu16
|
|
"\n",
|
|
app, app->hdr.appId, app->hdr.fwVer);
|
|
continue;
|
|
}
|
|
|
|
if (!(app->hdr.fwFlags & FL_APP_HDR_INTERNAL)) {
|
|
osLog(LOG_WARN, "Internal app is not marked: [%p]: flags: 0x%04" PRIX16
|
|
"; ID: %016" PRIX64
|
|
"; ignored\n",
|
|
app, app->hdr.fwFlags, app->hdr.appId);
|
|
continue;
|
|
}
|
|
if ((task = osTaskFindByAppID(app->hdr.appId))) {
|
|
osLog(LOG_WARN, "Internal app ID %016" PRIX64
|
|
"@ %p attempting to update internal app @ %p; app @%p ignored.\n",
|
|
app->hdr.appId, app, task->app, app);
|
|
continue;
|
|
}
|
|
if (osStartApp(app))
|
|
taskCnt++;
|
|
}
|
|
|
|
osLog(LOG_DEBUG, "Starting external apps...\n");
|
|
status = osExtAppStartApps(matchAutoStart, (void *)true);
|
|
osLog(LOG_DEBUG, "Started %" PRIu32 " internal apps; EXT status: %08" PRIX32 "\n", taskCnt, status);
|
|
}
|
|
|
|
static void osInternalEvtHandle(uint32_t evtType, void *evtData)
|
|
{
|
|
union SeosInternalSlabData *da = (union SeosInternalSlabData*)evtData;
|
|
struct Task *task, *ssTask;
|
|
uint32_t i, j;
|
|
uint16_t tid = EVENT_GET_ORIGIN(evtType);
|
|
uint16_t evt = EVENT_GET_EVENT(evtType), newEvt;
|
|
struct Task *srcTask = osTaskFindByTid(tid);
|
|
struct Task *preempted = osSetCurrentTask(srcTask);
|
|
struct AppEventStartStop ssMsg;
|
|
|
|
switch (evt) {
|
|
case EVT_SUBSCRIBE_TO_EVT:
|
|
case EVT_UNSUBSCRIBE_TO_EVT:
|
|
/* get task */
|
|
task = osTaskFindByTid(da->evtSub.tid);
|
|
if (!task)
|
|
break;
|
|
|
|
for (j = 0; j < da->evtSub.numEvts; j++) {
|
|
/* find if subscribed to this evt */
|
|
for (i = 0; i < task->subbedEvtCount && task->subbedEvents[i] != da->evtSub.evts[j]; i++);
|
|
|
|
/* if unsub & found -> unsub */
|
|
if (evt == EVT_UNSUBSCRIBE_TO_EVT && i != task->subbedEvtCount)
|
|
task->subbedEvents[i] = task->subbedEvents[--task->subbedEvtCount];
|
|
/* if sub & not found -> sub */
|
|
else if (evt == EVT_SUBSCRIBE_TO_EVT && i == task->subbedEvtCount) {
|
|
if (task->subbedEvtListSz == task->subbedEvtCount) { /* enlarge the list */
|
|
uint32_t newSz = (task->subbedEvtListSz * 3 + 1) / 2;
|
|
uint32_t *newList = heapAlloc(sizeof(uint32_t[newSz])); /* grow by 50% */
|
|
if (newList) {
|
|
memcpy(newList, task->subbedEvents, sizeof(uint32_t[task->subbedEvtListSz]));
|
|
if (task->subbedEvents != task->subbedEventsInt)
|
|
heapFree(task->subbedEvents);
|
|
task->subbedEvents = newList;
|
|
task->subbedEvtListSz = newSz;
|
|
}
|
|
}
|
|
if (task->subbedEvtListSz > task->subbedEvtCount) { /* have space ? */
|
|
task->subbedEvents[task->subbedEvtCount++] = da->evtSub.evts[j];
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EVT_APP_BEGIN:
|
|
case EVT_APP_END:
|
|
ssTask = evtData;
|
|
ssMsg.appId = ssTask->app->hdr.appId;
|
|
ssMsg.version = ssTask->app->hdr.appVer;
|
|
ssMsg.tid = ssTask->tid;
|
|
if (evt == EVT_APP_BEGIN) {
|
|
newEvt = EVT_APP_STARTED;
|
|
} else {
|
|
newEvt = EVT_APP_STOPPED;
|
|
osTaskEnd(ssTask);
|
|
osUnloadApp(ssTask);
|
|
}
|
|
|
|
/* send this event to all tasks who want it */
|
|
for_each_task(&mTasks, task) {
|
|
if (task != ssTask) {
|
|
for (i = 0; i < task->subbedEvtCount; i++) {
|
|
if (task->subbedEvents[i] == newEvt) {
|
|
osTaskHandle(task, newEvt, OS_SYSTEM_TID, &ssMsg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EVT_DEFERRED_CALLBACK:
|
|
da->deferred.callback(da->deferred.cookie);
|
|
break;
|
|
|
|
case EVT_PRIVATE_EVT:
|
|
task = osTaskFindByTid(da->privateEvt.toTid);
|
|
evtType = da->privateEvt.evtType & EVT_MASK;
|
|
evtData = da->privateEvt.evtData;
|
|
if (task) {
|
|
//private events cannot be retained
|
|
TaggedPtr *tmp = mCurEvtEventFreeingInfo;
|
|
mCurEvtEventFreeingInfo = NULL;
|
|
osTaskHandle(task, evtType, da->privateEvt.fromTid, da->privateEvt.evtData);
|
|
mCurEvtEventFreeingInfo = tmp;
|
|
}
|
|
break;
|
|
}
|
|
osSetCurrentTask(preempted);
|
|
}
|
|
|
|
void abort(void)
|
|
{
|
|
/* this is necessary for va_* funcs... */
|
|
osLog(LOG_ERROR, "Abort called");
|
|
while(1);
|
|
}
|
|
|
|
bool osRetainCurrentEvent(TaggedPtr *evtFreeingInfoP)
|
|
{
|
|
if (!mCurEvtEventFreeingInfo)
|
|
return false;
|
|
|
|
*evtFreeingInfoP = *mCurEvtEventFreeingInfo;
|
|
mCurEvtEventFreeingInfo = NULL;
|
|
return true;
|
|
}
|
|
|
|
void osFreeRetainedEvent(uint32_t evtType, void *evtData, TaggedPtr *evtFreeingInfoP)
|
|
{
|
|
//TODO: figure the way to calculate src tid here to pass to handleEventFreeing
|
|
handleEventFreeing(evtType, evtData, *evtFreeingInfoP);
|
|
}
|
|
|
|
void osMainInit(void)
|
|
{
|
|
cpuInit();
|
|
cpuIntsOff();
|
|
osInit();
|
|
timInit();
|
|
sensorsInit();
|
|
syscallInit();
|
|
osApiExport(mMiscInternalThingsSlab);
|
|
osChreApiExport();
|
|
apIntInit();
|
|
cpuIntsOn();
|
|
wdtInit();
|
|
osStartTasks();
|
|
|
|
//broadcast app start to all already-loaded apps
|
|
(void)osEnqueueEvt(EVT_APP_START, NULL, NULL);
|
|
}
|
|
|
|
void osMainDequeueLoop(void)
|
|
{
|
|
TaggedPtr evtFreeingInfo;
|
|
uint32_t evtType, j;
|
|
void *evtData;
|
|
struct Task *task;
|
|
uint16_t tid, evt;
|
|
|
|
/* get an event */
|
|
if (!evtQueueDequeue(mEvtsInternal, &evtType, &evtData, &evtFreeingInfo, true))
|
|
return;
|
|
|
|
/* by default we free them when we're done with them */
|
|
mCurEvtEventFreeingInfo = &evtFreeingInfo;
|
|
tid = EVENT_GET_ORIGIN(evtType);
|
|
evt = EVENT_GET_EVENT(evtType);
|
|
|
|
if (evt < EVT_NO_FIRST_USER_EVENT) {
|
|
/* handle deferred actions and other reserved events here */
|
|
osInternalEvtHandle(evtType, evtData);
|
|
} else {
|
|
/* send this event to all tasks who want it */
|
|
for_each_task(&mTasks, task) {
|
|
for (j = 0; j < task->subbedEvtCount; j++) {
|
|
if (task->subbedEvents[j] == evt) {
|
|
osTaskHandle(task, evt, tid, evtData);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* free it */
|
|
if (mCurEvtEventFreeingInfo)
|
|
handleEventFreeing(evtType, evtData, evtFreeingInfo);
|
|
|
|
/* avoid some possible errors */
|
|
mCurEvtEventFreeingInfo = NULL;
|
|
}
|
|
|
|
void __attribute__((noreturn)) osMain(void)
|
|
{
|
|
osMainInit();
|
|
|
|
while (true)
|
|
{
|
|
osMainDequeueLoop();
|
|
platPeriodic();
|
|
}
|
|
}
|
|
|
|
static void osDeferredActionFreeF(void* event)
|
|
{
|
|
slabAllocatorFree(mMiscInternalThingsSlab, event);
|
|
}
|
|
|
|
static bool osEventsSubscribeUnsubscribeV(bool sub, uint32_t numEvts, va_list ap)
|
|
{
|
|
struct Task *task = osGetCurrentTask();
|
|
union SeosInternalSlabData *act;
|
|
int i;
|
|
|
|
if (!sub && osTaskTestFlags(task, FL_TASK_STOPPED)) // stopping, so this is a no-op
|
|
return true;
|
|
|
|
if (numEvts > MAX_EVT_SUB_CNT)
|
|
return false;
|
|
|
|
act = slabAllocatorAlloc(mMiscInternalThingsSlab);
|
|
|
|
if (!act)
|
|
return false;
|
|
|
|
act->evtSub.tid = task->tid;
|
|
act->evtSub.numEvts = numEvts;
|
|
for (i = 0; i < numEvts; i++)
|
|
act->evtSub.evts[i] = va_arg(ap, uint32_t);
|
|
|
|
return osEnqueueEvtOrFree(sub ? EVT_SUBSCRIBE_TO_EVT : EVT_UNSUBSCRIBE_TO_EVT, act, osDeferredActionFreeF);
|
|
}
|
|
|
|
static bool osEventsSubscribeUnsubscribe(bool sub, uint32_t numEvts, ...)
|
|
{
|
|
bool ret;
|
|
va_list ap;
|
|
|
|
va_start(ap, numEvts);
|
|
ret = osEventsSubscribeUnsubscribeV(sub, numEvts, ap);
|
|
va_end(ap);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool osEventSubscribe(uint32_t tid, uint32_t evtType)
|
|
{
|
|
(void)tid;
|
|
return osEventsSubscribeUnsubscribe(true, 1, evtType);
|
|
}
|
|
|
|
bool osEventUnsubscribe(uint32_t tid, uint32_t evtType)
|
|
{
|
|
(void)tid;
|
|
return osEventsSubscribeUnsubscribe(false, 1, evtType);
|
|
}
|
|
|
|
bool osEventsSubscribe(uint32_t numEvts, ...)
|
|
{
|
|
bool ret;
|
|
va_list ap;
|
|
|
|
va_start(ap, numEvts);
|
|
ret = osEventsSubscribeUnsubscribeV(true, numEvts, ap);
|
|
va_end(ap);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool osEventsUnsubscribe(uint32_t numEvts, ...)
|
|
{
|
|
bool ret;
|
|
va_list ap;
|
|
|
|
va_start(ap, numEvts);
|
|
ret = osEventsSubscribeUnsubscribeV(false, numEvts, ap);
|
|
va_end(ap);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool osEnqueueEvtCommon(uint32_t evt, void *evtData, TaggedPtr evtFreeInfo, bool urgent)
|
|
{
|
|
struct Task *task = osGetCurrentTask();
|
|
uint32_t evtType = EVENT_WITH_ORIGIN(evt, osGetCurrentTid());
|
|
|
|
osTaskAddIoCount(task, 1);
|
|
|
|
if (osTaskTestFlags(task, FL_TASK_STOPPED) ||
|
|
!evtQueueEnqueue(mEvtsInternal, evtType, evtData, evtFreeInfo, urgent)) {
|
|
osTaskAddIoCount(task, -1);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void osRemovePendingEvents(bool (*match)(uint32_t evtType, const void *evtData, void *context), void *context)
|
|
{
|
|
evtQueueRemoveAllMatching(mEvtsInternal, match, context);
|
|
}
|
|
|
|
bool osEnqueueEvt(uint32_t evtType, void *evtData, EventFreeF evtFreeF)
|
|
{
|
|
return osEnqueueEvtCommon(evtType, evtData, taggedPtrMakeFromPtr(evtFreeF), false);
|
|
}
|
|
|
|
bool osEnqueueEvtOrFree(uint32_t evtType, void *evtData, EventFreeF evtFreeF)
|
|
{
|
|
bool success = osEnqueueEvt(evtType, evtData, evtFreeF);
|
|
|
|
if (!success && evtFreeF)
|
|
evtFreeF(evtData);
|
|
|
|
return success;
|
|
}
|
|
|
|
bool osEnqueueEvtAsApp(uint32_t evtType, void *evtData, bool freeData)
|
|
{
|
|
// compatibility with existing external apps
|
|
if (evtType & EVENT_TYPE_BIT_DISCARDABLE_COMPAT)
|
|
evtType |= EVENT_TYPE_BIT_DISCARDABLE;
|
|
|
|
return osEnqueueEvtCommon(evtType, evtData, freeData ? taggedPtrMakeFromUint(osGetCurrentTid()) : taggedPtrMakeFromPtr(NULL), false);
|
|
}
|
|
|
|
bool osDefer(OsDeferCbkF callback, void *cookie, bool urgent)
|
|
{
|
|
union SeosInternalSlabData *act = slabAllocatorAlloc(mMiscInternalThingsSlab);
|
|
if (!act)
|
|
return false;
|
|
|
|
act->deferred.callback = callback;
|
|
act->deferred.cookie = cookie;
|
|
|
|
if (osEnqueueEvtCommon(EVT_DEFERRED_CALLBACK, act, taggedPtrMakeFromPtr(osDeferredActionFreeF), urgent))
|
|
return true;
|
|
|
|
slabAllocatorFree(mMiscInternalThingsSlab, act);
|
|
return false;
|
|
}
|
|
|
|
static bool osEnqueuePrivateEvtEx(uint32_t evtType, void *evtData, TaggedPtr evtFreeInfo, uint32_t toTid)
|
|
{
|
|
union SeosInternalSlabData *act = slabAllocatorAlloc(mMiscInternalThingsSlab);
|
|
bool result;
|
|
|
|
if (!act) {
|
|
osLog(LOG_ERROR, "[seos] ERROR: osEnqueuePrivateEvtEx: call to slabAllocatorAlloc() failed\n");
|
|
return false;
|
|
}
|
|
struct Task *task = osGetCurrentTask();
|
|
osTaskAddIoCount(task, 1);
|
|
|
|
act->privateEvt.evtType = evtType;
|
|
act->privateEvt.evtData = evtData;
|
|
act->privateEvt.evtFreeInfo = evtFreeInfo;
|
|
act->privateEvt.fromTid = task->tid;
|
|
act->privateEvt.toTid = toTid;
|
|
|
|
osSetCurrentTask(mSystemTask);
|
|
result = osEnqueueEvtOrFree(EVT_PRIVATE_EVT, act, osPrivateEvtFreeF);
|
|
osSetCurrentTask(task);
|
|
return result;
|
|
}
|
|
|
|
// only called to send events for CHRE apps
|
|
bool osEnqueuePrivateEvtNew(uint16_t evtType, void *evtData,
|
|
void (*evtFreeCallback)(uint16_t evtType, void *evtData),
|
|
uint32_t toTid)
|
|
{
|
|
if (!osEnqueuePrivateEvtEx(evtType | (EVT_PRIVATE_CLASS_CHRE << 16), evtData,
|
|
taggedPtrMakeFromPtr(evtFreeCallback), toTid)) {
|
|
osChreFreeEvent(osGetCurrentTid(), evtFreeCallback, evtType, evtData);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool osEnqueuePrivateEvt(uint32_t evtType, void *evtData, EventFreeF evtFreeF, uint32_t toTid)
|
|
{
|
|
return osEnqueuePrivateEvtEx(evtType & EVT_MASK, evtData, taggedPtrMakeFromPtr(evtFreeF), toTid);
|
|
}
|
|
|
|
bool osEnqueuePrivateEvtAsApp(uint32_t evtType, void *evtData, uint32_t toTid)
|
|
{
|
|
return osEnqueuePrivateEvtEx(evtType & EVT_MASK, evtData, taggedPtrMakeFromUint(osGetCurrentTid()), toTid);
|
|
}
|
|
|
|
bool osTidById(const uint64_t *appId, uint32_t *tid)
|
|
{
|
|
struct Task *task;
|
|
|
|
for_each_task(&mTasks, task) {
|
|
if (task->app && !memcmp(&task->app->hdr.appId, appId, sizeof(*appId))) {
|
|
*tid = task->tid;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool osAppInfoById(uint64_t appId, uint32_t *appIdx, uint32_t *appVer, uint32_t *appSize)
|
|
{
|
|
uint32_t i = 0;
|
|
struct Task *task;
|
|
|
|
for_each_task(&mTasks, task) {
|
|
const struct AppHdr *app = task->app;
|
|
if (app && app->hdr.appId == appId) {
|
|
*appIdx = i;
|
|
*appVer = app->hdr.appVer;
|
|
*appSize = app->sect.rel_end;
|
|
return true;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool osAppInfoByIndex(uint32_t appIdx, uint64_t *appId, uint32_t *appVer, uint32_t *appSize)
|
|
{
|
|
struct Task *task;
|
|
int i = 0;
|
|
|
|
for_each_task(&mTasks, task) {
|
|
if (i != appIdx) {
|
|
++i;
|
|
} else {
|
|
const struct AppHdr *app = task->app;
|
|
*appId = app->hdr.appId;
|
|
*appVer = app->hdr.appVer;
|
|
*appSize = app->sect.rel_end;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool osExtAppInfoByIndex(uint32_t appIdx, uint64_t *appId, uint32_t *appVer, uint32_t *appSize)
|
|
{
|
|
struct Task *task;
|
|
int i = 0;
|
|
|
|
for_each_task(&mTasks, task) {
|
|
const struct AppHdr *app = task->app;
|
|
if (!(app->hdr.fwFlags & FL_APP_HDR_INTERNAL)) {
|
|
if (i != appIdx) {
|
|
++i;
|
|
} else {
|
|
*appId = app->hdr.appId;
|
|
*appVer = app->hdr.appVer;
|
|
*appSize = app->sect.rel_end;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void osLogv(char clevel, uint32_t flags, const char *str, va_list vl)
|
|
{
|
|
void *userData = platLogAllocUserData();
|
|
|
|
platLogPutcharF(userData, clevel);
|
|
cvprintf(platLogPutcharF, flags, userData, str, vl);
|
|
|
|
platLogFlush(userData);
|
|
}
|
|
|
|
void osLog(enum LogLevel level, const char *str, ...)
|
|
{
|
|
va_list vl;
|
|
|
|
va_start(vl, str);
|
|
osLogv((char)level, 0, str, vl);
|
|
va_end(vl);
|
|
}
|
|
|
|
|
|
|
|
|
|
//Google's public key for Google's apps' signing
|
|
const uint8_t __attribute__ ((section (".pubkeys"))) _RSA_KEY_GOOGLE[] = {
|
|
0xd9, 0xcd, 0x83, 0xae, 0xb5, 0x9e, 0xe4, 0x63, 0xf1, 0x4c, 0x26, 0x6a, 0x1c, 0xeb, 0x4c, 0x12,
|
|
0x5b, 0xa6, 0x71, 0x7f, 0xa2, 0x4e, 0x7b, 0xa2, 0xee, 0x02, 0x86, 0xfc, 0x0d, 0x31, 0x26, 0x74,
|
|
0x1e, 0x9c, 0x41, 0x43, 0xba, 0x16, 0xe9, 0x23, 0x4d, 0xfc, 0xc4, 0xca, 0xcc, 0xd5, 0x27, 0x2f,
|
|
0x16, 0x4c, 0xe2, 0x85, 0x39, 0xb3, 0x0b, 0xcb, 0x73, 0xb6, 0x56, 0xc2, 0x98, 0x83, 0xf6, 0xfa,
|
|
0x7a, 0x6e, 0xa0, 0x9a, 0xcc, 0x83, 0x97, 0x9d, 0xde, 0x89, 0xb2, 0xa3, 0x05, 0x46, 0x0c, 0x12,
|
|
0xae, 0x01, 0xf8, 0x0c, 0xf5, 0x39, 0x32, 0xe5, 0x94, 0xb9, 0xa0, 0x8f, 0x19, 0xe4, 0x39, 0x54,
|
|
0xad, 0xdb, 0x81, 0x60, 0x74, 0x63, 0xd5, 0x80, 0x3b, 0xd2, 0x88, 0xf4, 0xcb, 0x6b, 0x47, 0x28,
|
|
0x80, 0xb0, 0xd1, 0x89, 0x6d, 0xd9, 0x62, 0x88, 0x81, 0xd6, 0xc0, 0x13, 0x88, 0x91, 0xfb, 0x7d,
|
|
0xa3, 0x7f, 0xa5, 0x40, 0x12, 0xfb, 0x77, 0x77, 0x4c, 0x98, 0xe4, 0xd3, 0x62, 0x39, 0xcc, 0x63,
|
|
0x34, 0x76, 0xb9, 0x12, 0x67, 0xfe, 0x83, 0x23, 0x5d, 0x40, 0x6b, 0x77, 0x93, 0xd6, 0xc0, 0x86,
|
|
0x6c, 0x03, 0x14, 0xdf, 0x78, 0x2d, 0xe0, 0x9b, 0x5e, 0x05, 0xf0, 0x93, 0xbd, 0x03, 0x1d, 0x17,
|
|
0x56, 0x88, 0x58, 0x25, 0xa6, 0xae, 0x63, 0xd2, 0x01, 0x43, 0xbb, 0x7e, 0x7a, 0xa5, 0x62, 0xdf,
|
|
0x8a, 0x31, 0xbd, 0x24, 0x1b, 0x1b, 0xeb, 0xfe, 0xdf, 0xd1, 0x31, 0x61, 0x4a, 0xfa, 0xdd, 0x6e,
|
|
0x62, 0x0c, 0xa9, 0xcd, 0x08, 0x0c, 0xa1, 0x1b, 0xe7, 0xf2, 0xed, 0x36, 0x22, 0xd0, 0x5d, 0x80,
|
|
0x78, 0xeb, 0x6f, 0x5a, 0x58, 0x18, 0xb5, 0xaf, 0x82, 0x77, 0x4c, 0x95, 0xce, 0xc6, 0x4d, 0xda,
|
|
0xca, 0xef, 0x68, 0xa6, 0x6d, 0x71, 0x4d, 0xf1, 0x14, 0xaf, 0x68, 0x25, 0xb8, 0xf3, 0xff, 0xbe,
|
|
};
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
//debug key whose privatekey is checked in as misc/debug.privkey
|
|
const uint8_t __attribute__ ((section (".pubkeys"))) _RSA_KEY_GOOGLE_DEBUG[] = {
|
|
0x2d, 0xff, 0xa6, 0xb5, 0x65, 0x87, 0xbe, 0x61, 0xd1, 0xe1, 0x67, 0x10, 0xa1, 0x9b, 0xc6, 0xca,
|
|
0xc8, 0xb1, 0xf0, 0xaa, 0x88, 0x60, 0x9f, 0xa1, 0x00, 0xa1, 0x41, 0x9a, 0xd8, 0xb4, 0xd1, 0x74,
|
|
0x9f, 0x23, 0x28, 0x0d, 0xc2, 0xc4, 0x37, 0x15, 0xb1, 0x4a, 0x80, 0xca, 0xab, 0xb9, 0xba, 0x09,
|
|
0x7d, 0xf8, 0x44, 0xd6, 0xa2, 0x72, 0x28, 0x12, 0x91, 0xf6, 0xa5, 0xea, 0xbd, 0xf8, 0x81, 0x6b,
|
|
0xd2, 0x3c, 0x50, 0xa2, 0xc6, 0x19, 0x54, 0x48, 0x45, 0x8d, 0x92, 0xac, 0x01, 0xda, 0x14, 0x32,
|
|
0xdb, 0x05, 0x82, 0x06, 0x30, 0x25, 0x09, 0x7f, 0x5a, 0xbb, 0x86, 0x64, 0x70, 0x98, 0x64, 0x1e,
|
|
0xe6, 0xca, 0x1d, 0xc1, 0xcb, 0xb6, 0x23, 0xd2, 0x62, 0x00, 0x46, 0x97, 0xd5, 0xcc, 0xe6, 0x36,
|
|
0x72, 0xec, 0x2e, 0x43, 0x1f, 0x0a, 0xaf, 0xf2, 0x51, 0xe1, 0xcd, 0xd2, 0x98, 0x5d, 0x7b, 0x64,
|
|
0xeb, 0xd1, 0x35, 0x4d, 0x59, 0x13, 0x82, 0x6c, 0xbd, 0xc4, 0xa2, 0xfc, 0xad, 0x64, 0x73, 0xe2,
|
|
0x71, 0xb5, 0xf4, 0x45, 0x53, 0x6b, 0xc3, 0x56, 0xb9, 0x8b, 0x3d, 0xeb, 0x00, 0x48, 0x6e, 0x29,
|
|
0xb1, 0xb4, 0x8e, 0x2e, 0x43, 0x39, 0xef, 0x45, 0xa0, 0xb8, 0x8b, 0x5f, 0x80, 0xb5, 0x0c, 0xc3,
|
|
0x03, 0xe3, 0xda, 0x51, 0xdc, 0xec, 0x80, 0x2c, 0x0c, 0xdc, 0xe2, 0x71, 0x0a, 0x14, 0x4f, 0x2c,
|
|
0x22, 0x2b, 0x0e, 0xd1, 0x8b, 0x8f, 0x93, 0xd2, 0xf3, 0xec, 0x3a, 0x5a, 0x1c, 0xba, 0x80, 0x54,
|
|
0x23, 0x7f, 0xb0, 0x54, 0x8b, 0xe3, 0x98, 0x22, 0xbb, 0x4b, 0xd0, 0x29, 0x5f, 0xce, 0xf2, 0xaa,
|
|
0x99, 0x89, 0xf2, 0xb7, 0x5d, 0x8d, 0xb2, 0x72, 0x0b, 0x52, 0x02, 0xb8, 0xa4, 0x37, 0xa0, 0x3b,
|
|
0xfe, 0x0a, 0xbc, 0xb3, 0xb3, 0xed, 0x8f, 0x8c, 0x42, 0x59, 0xbe, 0x4e, 0x31, 0xed, 0x11, 0x9b,
|
|
};
|
|
|
|
#endif
|