diff --git a/.gitignore b/.gitignore index b9a79b1b30..5b2a6ce078 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *.sw* *# .#* +**/.DS_Store .fn_dependencies .fn_exports .exported_interfaces @@ -28,6 +29,7 @@ GPATH GRTAGS GSYMS GTAGS +tools/.vagrant .vagrant .clang_complete Vagrantfile diff --git a/.gitmodules b/.gitmodules index 0f50366a4d..9a6e372779 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,9 @@ [submodule "src/components/lib/ps"] path = src/components/lib/ps url = https://github.com/gwsystems/ps.git +[submodule "src/extern/cFE"] + path = src/extern/cFE + url = https://github.com/Others/cFE.git [submodule "src/components/lib/ck/ck"] path = src/components/lib/ck/ck url = https://github.com/gwsystems/ck.git diff --git a/src/Makefile b/src/Makefile index 8a7bd33810..b837c58f97 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,9 +1,13 @@ MAKEFLAGS=--no-print-directory --section-alignment 0x1000 -I$(PWD) #$(info Make flags $(MAKEFLAGS)) +.PHONY: default all extern comps plat init_extern default: | all cp -all: comps plat +all: | extern comps plat + +extern: + $(MAKE) $(MAKEFLAGS) -C extern comps: $(info ) @@ -36,8 +40,15 @@ distclean: clean $(MAKE) $(MAKEFLAGS) -C components distclean @rm -f `pwd`/../transfer/* -init: +init: | ensure_config init_extern init_composite + +ensure_config: test -f PLATFORM_ID || $(MAKE) $(MAKEFLAGS) config + +init_extern: + $(MAKE) $(MAKEFLAGS) -C extern init + +init_composite: $(MAKE) $(MAKEFLAGS) -C components init $(MAKE) $(MAKEFLAGS) PLATFORM=$(shell cat PLATFORM_ID) -C platform init diff --git a/src/components/implementation/no_interface/cFE_booter/.gitignore b/src/components/implementation/no_interface/cFE_booter/.gitignore new file mode 100644 index 0000000000..74de6c3797 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/.gitignore @@ -0,0 +1,3 @@ +gen +test +*.d.[0-9]* diff --git a/src/components/implementation/no_interface/cFE_booter/Makefile b/src/components/implementation/no_interface/cFE_booter/Makefile new file mode 100644 index 0000000000..8e7f5e8e2b --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/Makefile @@ -0,0 +1,12 @@ +# C_OBJS=cFE_entrypoint.o cFE_stub.o osapi.o osfiles.o osloader.o osqueue.o ostask.o ostimer.o osnetwork.o psp.o scheddev/sl.c scheddev/sl_mod_fprr.c +ASM_OBJS= +COMPONENT=cFE_booter.o +INTERFACES=cFE +DEPENDENCIES=capmgr +IF_LIB:=./composite_cFE.o ./cFE_fs.o $(wildcard test/*.o) +ADDITIONAL_LIBS=-lcobj_format $(LIBSLCAPMGR) -lheap -lsl_lock -lsl_thd_static_backend + +include ../../Makefile.subsubdir +CFLAGS += -I./gen -I ./test/shared $(CPPFLAGS) + +MANDITORY_LIB=simple_stklib.o diff --git a/src/components/implementation/no_interface/cFE_booter/cFE_emu_support.c b/src/components/implementation/no_interface/cFE_booter/cFE_emu_support.c new file mode 100644 index 0000000000..a117fea84e --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cFE_emu_support.c @@ -0,0 +1,591 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +union shared_region *shared_regions[16]; + +int have_registered_sync_callback = 0; +asndcap_t sync_callback_delegates[CFE_TIME_MAX_NUM_SYNCH_FUNCS]; + +int32 +sync_callback_handler() +{ + int i; + asndcap_t callback; + + for (i = 0; i < CFE_TIME_MAX_NUM_SYNCH_FUNCS; i++) { + callback = sync_callback_delegates[i]; + if (callback) { cos_asnd(callback, 1); } + } + return CFE_SUCCESS; +} + +int +emu_request_memory(spdid_t client) +{ + vaddr_t our_addr = 0; + int id = memmgr_shared_page_allocn(SHARED_REGION_NUM_PAGES, &our_addr); + + assert(our_addr); + shared_regions[client] = (void *)our_addr; + + /* FIXME: This is broken if applications can stop (because then the handler could get auto-deregistered) */ + if (!have_registered_sync_callback) { + CFE_TIME_RegisterSynchCallback(sync_callback_handler); + have_registered_sync_callback = 1; + } + + return id; +} + +arcvcap_t +emu_create_aep_thread(spdid_t client, thdclosure_index_t idx, cos_channelkey_t key) +{ + struct sl_thd * thd; + sched_param_t aep_priority; + struct cos_defcompinfo child_dci; + arcvcap_t extrcv; + + cos_defcompinfo_childid_init(&child_dci, client); + thd = sl_thd_aep_alloc_ext(&child_dci, NULL, idx, 1, 0, key, 0, 0, &extrcv); + assert(thd); + + aep_priority = sched_param_pack(SCHEDP_PRIO, CFE_TIME_1HZ_TASK_PRIORITY); + sl_thd_param_set(thd, aep_priority); + + return extrcv; +} + +/* Methods for stashing and retrieving a idx, spdid pair + * This is done when a OS_TaskCreate call is rooted in another component + */ +struct { + thdclosure_index_t idx; + spdid_t spdid; +} stashed_task_values; + +void +emu_stash(thdclosure_index_t idx, spdid_t spdid) +{ + assert(stashed_task_values.idx == 0 && stashed_task_values.spdid == 0); + stashed_task_values.idx = idx; + stashed_task_values.spdid = spdid; +} + +void +emu_stash_clear() +{ + stashed_task_values.idx = 0; + stashed_task_values.spdid = 0; +} + + +thdclosure_index_t +emu_stash_retrieve_thdclosure() +{ + return stashed_task_values.idx; +} + +spdid_t +emu_stash_retrieve_spdid() +{ + return stashed_task_values.spdid; +} + +/* Methods that wrap cFE methods + * They use data in memory shared with the calling component + */ + +int32 +emu_CFE_ES_CalculateCRC(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_CalculateCRC(s->cfe_es_calculateCRC.Data, s->cfe_es_calculateCRC.DataLength, + s->cfe_es_calculateCRC.InputCRC, s->cfe_es_calculateCRC.TypeCRC); +} + +int32 +emu_CFE_ES_CopyToCDS(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_CopyToCDS(s->cfe_es_copyToCDS.CDSHandle, s->cfe_es_copyToCDS.DataToCopy); +} + +int32 +emu_CFE_ES_CreateChildTask(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_CreateChildTask(&s->cfe_es_createChildTask.TaskId, s->cfe_es_createChildTask.TaskName, + s->cfe_es_createChildTask.FunctionPtr, NULL, 0, + s->cfe_es_createChildTask.Priority, s->cfe_es_createChildTask.Flags); +} + + +int32 +emu_CFE_ES_GetAppIDByName(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_GetAppIDByName(&s->cfe_es_getAppIDByName.AppId, s->cfe_es_getAppIDByName.AppName); +} + +int32 +emu_CFE_ES_GetAppInfo(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_GetAppInfo(&s->cfe_es_getAppInfo.AppInfo, s->cfe_es_getAppInfo.AppId); +} + +int32 +emu_CFE_ES_GetGenCount(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_GetGenCount(s->cfe_es_getGenCount.CounterId, &s->cfe_es_getGenCount.Count); +} + +int32 +emu_CFE_ES_GetGenCounterIDByName(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_GetGenCounterIDByName(&s->cfe_es_getGenCounterIDByName.CounterId, + s->cfe_es_getGenCounterIDByName.CounterName); +} + +int32 +emu_CFE_ES_GetResetType(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_GetResetType(&s->cfe_es_getResetType.ResetSubtype); +} + +int32 +emu_CFE_ES_GetTaskInfo(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_GetTaskInfo(&s->cfe_es_getTaskInfo.TaskInfo, s->cfe_es_getTaskInfo.TaskId); +} + +int32 +emu_CFE_ES_RegisterCDS(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_RegisterCDS(&s->cfe_es_registerCDS.CDS_Handle, s->cfe_es_registerCDS.BlockSize, + s->cfe_es_registerCDS.Name); +} + +int32 +emu_CFE_ES_RestoreFromCDS(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_RestoreFromCDS(s->cfe_es_restoreFromCDS.RestoreToMemory, s->cfe_es_restoreFromCDS.CDSHandle); +} + + +int32 +emu_CFE_ES_RunLoop(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_RunLoop(&s->cfe_es_runLoop.RunStatus); +} + +int32 +emu_CFE_ES_WriteToSysLog(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_ES_WriteToSysLog("%s", s->cfe_es_writeToSysLog.String); +} + +int32 +emu_CFE_EVS_Register(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_EVS_Register(s->cfe_evs_register.filters, s->cfe_evs_register.NumEventFilters, + s->cfe_evs_register.FilterScheme); +} + +int32 +emu_CFE_FS_Decompress(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_FS_Decompress(s->cfe_fs_decompress.SourceFile, s->cfe_fs_decompress.DestinationFile); +} + +int32 +emu_CFE_FS_ReadHeader(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_FS_ReadHeader(&s->cfe_fs_writeHeader.Hdr, s->cfe_fs_writeHeader.FileDes); +} + +int32 +emu_CFE_FS_WriteHeader(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_FS_WriteHeader(s->cfe_fs_writeHeader.FileDes, &s->cfe_fs_writeHeader.Hdr); +} + +int32 +emu_CFE_SB_CreatePipe(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_SB_CreatePipe(&s->cfe_sb_createPipe.PipeId, s->cfe_sb_createPipe.Depth, + s->cfe_sb_createPipe.PipeName); +} + +int32 +emu_CFE_EVS_SendEvent(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_EVS_SendEvent(s->cfe_evs_sendEvent.EventID, s->cfe_evs_sendEvent.EventType, "%s", + s->cfe_evs_sendEvent.Msg); +} + +uint16 +emu_CFE_SB_GetCmdCode(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_SB_GetCmdCode((CFE_SB_MsgPtr_t)s->cfe_sb_msg.Msg); +} + +CFE_SB_MsgId_t +emu_CFE_SB_GetMsgId(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_SB_GetMsgId((CFE_SB_MsgPtr_t)s->cfe_sb_msg.Msg); +} + +void +emu_CFE_SB_GetMsgTime(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + CFE_TIME_SysTime_t time = CFE_SB_GetMsgTime((CFE_SB_MsgPtr_t)&s->cfe_sb_msg.Msg); + s->time = time; +} + +uint16 +emu_CFE_SB_GetTotalMsgLength(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_SB_GetTotalMsgLength(&s->cfe_sb_getMsgLen.Msg); +} + +void +emu_CFE_SB_InitMsg(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + CFE_SB_InitMsg(s->cfe_sb_initMsg.MsgBuffer, s->cfe_sb_initMsg.MsgId, s->cfe_sb_initMsg.Length, + s->cfe_sb_initMsg.Clear); +} + +int32 +emu_CFE_SB_RcvMsg(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + CFE_SB_MsgPtr_t BufPtr; + int32 result = CFE_SB_RcvMsg(&BufPtr, s->cfe_sb_rcvMsg.PipeId, s->cfe_sb_rcvMsg.TimeOut); + int len; + + /* We want to save the message contents to the shared region + * But we need to be sure there is something to copy, so we check the call was successful + */ + if (result == CFE_SUCCESS) { + len = CFE_SB_GetTotalMsgLength(BufPtr); + assert(len <= EMU_BUF_SIZE); + memcpy(s->cfe_sb_rcvMsg.Msg, (char *)BufPtr, len); + } + return result; +} + +int32 +emu_CFE_SB_SetCmdCode(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_SB_SetCmdCode((CFE_SB_MsgPtr_t)s->cfe_sb_setCmdCode.Msg, s->cfe_sb_setCmdCode.CmdCode); +} + +int32 +emu_CFE_SB_SendMsg(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_SB_SendMsg((CFE_SB_MsgPtr_t)s->cfe_sb_msg.Msg); +} + +int32 +emu_CFE_SB_SubscribeEx(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_SB_SubscribeEx(s->cfe_sb_subscribeEx.MsgId, s->cfe_sb_subscribeEx.PipeId, + s->cfe_sb_subscribeEx.Quality, s->cfe_sb_subscribeEx.MsgLim); +} + +void +emu_CFE_SB_TimeStampMsg(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + CFE_SB_TimeStampMsg((CFE_SB_MsgPtr_t)s->cfe_sb_msg.Msg); +} + +boolean +emu_CFE_SB_ValidateChecksum(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_SB_ValidateChecksum((CFE_SB_MsgPtr_t)s->cfe_sb_msg.Msg); +} + +struct { + size_t size; + void * tbl_ptr; /* FIXME: Wrap CFE_TBL_ReleaseAddress to set this back to NULL */ +} table_info[CFE_TBL_MAX_NUM_HANDLES]; + +int32 +emu_CFE_TBL_GetAddress(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + CFE_TBL_Handle_t handle = s->cfe_tbl_getAddress.TblHandle; + int32 result = CFE_TBL_GetAddress(&table_info[handle].tbl_ptr, handle); + + if (result == CFE_SUCCESS || result == CFE_TBL_INFO_UPDATED) { + memcpy(s->cfe_tbl_getAddress.Buffer, table_info[handle].tbl_ptr, table_info[handle].size); + } + + return result; +} + +int32 +emu_CFE_TBL_GetInfo(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_TBL_GetInfo(&s->cfe_tbl_getInfo.TblInfo, s->cfe_tbl_getInfo.TblName); +} + +int32 +emu_CFE_TBL_Load(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return CFE_TBL_Load(s->cfe_tbl_load.TblHandle, s->cfe_tbl_load.SrcType, s->cfe_tbl_load.SrcData); +} + +int32 +emu_CFE_TBL_Modified(spdid_t client) +{ + /* FIXME: We assume the passed data is valid, which isn't safe */ + + union shared_region *s = shared_regions[client]; + CFE_TBL_Handle_t handle = s->cfe_tbl_modified.TblHandle; + void * tbl_ptr = table_info[handle].tbl_ptr; + size_t size = table_info[handle].size; + + assert(tbl_ptr); + memcpy(tbl_ptr, s->cfe_tbl_modified.Buffer, size); + + return CFE_TBL_Modified(handle); +} + + +int32 +emu_CFE_TBL_Register(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + int32 result = CFE_TBL_Register(&s->cfe_tbl_register.TblHandle, s->cfe_tbl_register.Name, + s->cfe_tbl_register.TblSize, s->cfe_tbl_register.TblOptionFlags, NULL); + + if (result == CFE_SUCCESS || result == CFE_TBL_INFO_RECOVERED_TBL) { + table_info[s->cfe_tbl_register.TblHandle].size = s->cfe_tbl_register.TblSize; + } + + return result; +} + + +void +emu_CFE_TIME_Add(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + s->cfe_time_add.Result = CFE_TIME_Add(s->cfe_time_add.Time1, s->cfe_time_add.Time2); +} + +void +emu_CFE_TIME_Compare(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + s->cfe_time_compare.Result = CFE_TIME_Compare(s->cfe_time_compare.Time1, s->cfe_time_compare.Time2); +} + +void +emu_CFE_TIME_GetTime(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + s->time = CFE_TIME_GetTime(); +} + +void +emu_CFE_TIME_Print(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + CFE_TIME_Print(s->cfe_time_print.PrintBuffer, s->cfe_time_print.TimeToPrint); +} + +int32 +emu_CFE_TIME_RegisterSynchCallback(cos_channelkey_t key) +{ + int i; + for (i = 0; i < CFE_TIME_MAX_NUM_SYNCH_FUNCS; i++) { + if (!sync_callback_delegates[i]) { + sync_callback_delegates[i] = capmgr_asnd_key_create(key); + return CFE_SUCCESS; + } + } + return CFE_TIME_TOO_MANY_SYNCH_CALLBACKS; +} + +int32 +emu_OS_cp(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_cp(s->os_cp.src, s->os_cp.dest); +} + +int32 +emu_OS_creat(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_creat(s->os_creat.path, s->os_creat.access); +} + +int32 +emu_OS_FDGetInfo(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_FDGetInfo(s->os_FDGetInfo.filedes, &s->os_FDGetInfo.fd_prop); +} + +int32 +emu_OS_fsBytesFree(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_fsBytesFree(s->os_fsBytesFree.name, &s->os_fsBytesFree.bytes_free); +} + +int32 +emu_OS_mkdir(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_mkdir(s->os_mkdir.path, s->os_mkdir.access); +} + +int32 +emu_OS_open(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_open(s->os_open.path, s->os_open.access, s->os_open.mode); +} + +os_dirp_t +emu_OS_opendir(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_opendir(s->os_opendir.path); +} + +int32 +emu_OS_mv(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_mv(s->os_cp.src, s->os_cp.dest); +} + +int32 +emu_OS_read(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_read(s->os_read.filedes, s->os_read.buffer, s->os_read.nbytes); +} + +void +emu_OS_readdir(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + s->os_readdir.dirent = *OS_readdir(s->os_readdir.directory); +} + +int32 +emu_OS_remove(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_remove(s->os_remove.path); +} + +int32 +emu_OS_rename(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_rename(s->os_rename.old_filename, s->os_rename.new_filename); +} + +int32 +emu_OS_rmdir(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_rmdir(s->os_rmdir.path); +} + +int32 +emu_OS_stat(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_stat(s->os_stat.path, &s->os_stat.filestats); +} + +int32 +emu_OS_write(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_write(s->os_write.filedes, s->os_write.buffer, s->os_write.nbytes); +} + +int32 +emu_OS_BinSemCreate(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_BinSemCreate(&s->os_semCreate.sem_id, s->os_semCreate.sem_name, s->os_semCreate.sem_initial_value, + s->os_semCreate.options); +} + +int32 +emu_OS_CountSemCreate(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_CountSemCreate(&s->os_semCreate.sem_id, s->os_semCreate.sem_name, s->os_semCreate.sem_initial_value, + s->os_semCreate.options); +} + +int32 +emu_OS_MutSemCreate(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_MutSemCreate(&s->os_mutSemCreate.sem_id, s->os_mutSemCreate.sem_name, s->os_mutSemCreate.options); +} + +int32 +emu_OS_TaskGetIdByName(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_TaskGetIdByName(&s->os_taskGetIdByName.task_id, s->os_taskGetIdByName.task_name); +} + +int32 +emu_OS_SymbolLookup(spdid_t client) +{ + union shared_region *s = shared_regions[client]; + return OS_SymbolLookup(&s->os_symbolLookup.symbol_address, s->os_symbolLookup.symbol_name); +} diff --git a/src/components/implementation/no_interface/cFE_booter/cFE_entrypoint.c b/src/components/implementation/no_interface/cFE_booter/cFE_entrypoint.c new file mode 100644 index 0000000000..fbc003b467 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cFE_entrypoint.c @@ -0,0 +1,153 @@ +#include + +#include "cFE_util.h" +#include "ostask.h" + +#include "gen/cfe_psp.h" +#include "gen/common_types.h" +#include "gen/osapi.h" + +#ifdef UNIT_TESTS +#include "test/shared/ut_main_composite.h" +#endif + +/* This is based on an old build technique, so we can ignore this warning. + * But I'm leaving it in, just in case we ever switch to cmake + */ + +/* + * cfe_platform_cfg.h needed for CFE_ES_NONVOL_STARTUP_FILE, CFE_CPU_ID/CPU_NAME/SPACECRAFT_ID + * + * - this should NOT be included here - + * + * it is only for compatibility with the old makefiles. Including this makes the PSP build + * ONLY compatible with a CFE build using this exact same CFE platform config. + */ + +#include "gen/cfe_platform_cfg.h" + +extern void CFE_ES_Main(uint32 StartType, uint32 StartSubtype, uint32 ModeId, const char *StartFilePath); +extern void CFE_TIME_Local1HzISR(void); + +#define CFE_ES_MAIN_FUNCTION CFE_ES_Main +#define CFE_TIME_1HZ_FUNCTION CFE_TIME_Local1HzISR + +/* + * The classic build does not support static modules, + * so stub the ModuleInit() function out right here + */ +void +CFE_PSP_ModuleInit(void) +{ +} + +// "Magic" constants +#define CFE_PSP_CPU_NAME_LENGTH 32 +#define CFE_PSP_RESET_NAME_LENGTH 10 + +/* + * Structure for the Command line parameters + * Stolen from the Linux psp_start function... + */ +struct CFE_PSP_CommandData_t { + char ResetType[CFE_PSP_RESET_NAME_LENGTH]; /* Reset type can be "PO" for Power on or "PR" for Processor Reset */ + uint32 SubType; /* Reset Sub Type ( 1 - 5 ) */ + char CpuName[CFE_PSP_CPU_NAME_LENGTH]; /* CPU Name */ + uint32 CpuId; /* CPU ID */ + uint32 SpacecraftId; /* Spacecraft ID */ +}; + +void +command_line_set_defaults(struct CFE_PSP_CommandData_t *args) +{ + strncpy(args->ResetType, "PO", 2); + args->SubType = 1; + args->CpuId = 1; + args->SpacecraftId = CFE_SPACECRAFT_ID; +} + +// This must be global so that cos_init_delegate can read it +// TODO: Consider passing cos_init_delegate this data instead +uint32 reset_type; +struct CFE_PSP_CommandData_t args; + +// This is the delegate function called by the scheduler +void +cos_init_delegate(void *data) +{ + OS_printf("CFE_PSP: Doing PSP setup...\n"); + +#ifdef UNIT_TESTS + OS_printf("Beginning unit tests\n"); + Composite_UT_oscore(); + Composite_UT_osfile(); + Composite_UT_osfilesys(); + Composite_UT_osloader(); + Composite_UT_osnetwork(); + Composite_UT_ostimer(); + OS_printf("End unit tests\n"); +#endif + + /* + ** Initialize the statically linked modules (if any) + ** This is only applicable to CMake build - classic build + ** does not have the logic to selectively include/exclude modules + ** + ** This is useless until we support cmake + */ + CFE_PSP_ModuleInit(); + + /* + ** Initialize the reserved memory + */ + CFE_PSP_InitProcessorReservedMemory(reset_type); + + OS_printf("CFE_PSP: PSP setup successful!\n"); + + OS_printf("CFE_PSP: Starting the cFE proper...\n"); + /* + ** Call cFE entry point. + */ + CFE_ES_MAIN_FUNCTION(reset_type, args.SubType, 1, CFE_ES_NONVOL_STARTUP_FILE); + + OS_printf("CFE_PSP: cFE started, main thread sleeping\n"); + + /* + ** Let the main thread sleep. + ** + ** OS_IdleLoop() will wait forever and return if + ** someone calls OS_ApplicationShutdown(TRUE) + */ + OS_IdleLoop(); + + PANIC("Application was shutdown!"); +} + +void +cos_init(void) +{ + command_line_set_defaults(&args); + + /* + ** Set the reset type + */ + if (strncmp("PR", args.ResetType, 2) == 0) { + reset_type = CFE_PSP_RST_TYPE_PROCESSOR; + OS_printf("CFE_PSP: Starting the cFE with a PROCESSOR reset.\n"); + } else { + reset_type = CFE_PSP_RST_TYPE_POWERON; + OS_printf("CFE_PSP: Starting the cFE with a POWER ON reset.\n"); + } + + CFE_PSP_SpacecraftId = args.SpacecraftId; + CFE_PSP_CpuId = args.CpuId; + /* + ** Initialize the OS API + */ + OS_printf("CFE_PSP: Initializing the OS API...\n"); + OS_API_Init(); + OS_printf("CFE_PSP: The the OS API was successfully initialized!\n"); + + OS_printf("CFE_PSP: Delegating to scheduler setup... \n"); + OS_SchedulerStart(&cos_init_delegate); +} diff --git a/src/components/implementation/no_interface/cFE_booter/cFE_util.c b/src/components/implementation/no_interface/cFE_booter/cFE_util.c new file mode 100644 index 0000000000..5fab5a84c2 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cFE_util.c @@ -0,0 +1,24 @@ +#include +#include + +#include +#include +#include + +#include "gen/osapi.h" +#include "cFE_util.h" + +void +panic_impl(const char *function, char *message) +{ + printc("cFE panic in %s: %s\n", function, message); + assert(0); +} + +void +print_with_error_name(char *message, int32 error) +{ + os_err_name_t local_name; + OS_GetErrorName(error, &local_name); + printc("%s, error %s\n", message, local_name); +} diff --git a/src/components/implementation/no_interface/cFE_booter/cFE_util.h b/src/components/implementation/no_interface/cFE_booter/cFE_util.h new file mode 100644 index 0000000000..ceb5fb06dc --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cFE_util.h @@ -0,0 +1,23 @@ +#ifndef _CFE_UTIL_ +#define _CFE_UTIL_ + +#include +#include + +#include +#include +#include + +#include "gen/common_types.h" + +// These variables store the global SPACECRAFT_ID and CPU_ID +uint32 CFE_PSP_SpacecraftId; +uint32 CFE_PSP_CpuId; + +#define PANIC(a) panic_impl(__func__, a) + +void panic_impl(const char *function, char *message); + +void print_with_error_name(char *message, int32 error); + +#endif diff --git a/src/components/implementation/no_interface/cFE_booter/cfe_psp_eeprom.c b/src/components/implementation/no_interface/cFE_booter/cfe_psp_eeprom.c new file mode 100644 index 0000000000..29692c8ee0 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cfe_psp_eeprom.c @@ -0,0 +1,352 @@ +/* +** File : cfe_psp_eeprom.c +** +** +** Copyright (c) 2004-2011, United States Government as represented by +** Administrator for The National Aeronautics and Space Administration. +** All Rights Reserved. +** +** This is governed by the NASA Open Source Agreement and may be used, +** distributed and modified only pursuant to the terms of that agreement. +** +** Author : Ezra Yeheskeli +** +** Purpose: +** This file contains some of the OS APIs abstraction layer. +** It contains the processor architecture specific calls. +** +** 16-Nov-2003 Ezra Yeheskeli +** - First Creation. +** +*/ + +/* +** Include section +*/ +#include + +#include "gen/cfe_psp.h" + +/* +** global memory +*/ + +/* + ** Name: CFE_PSP_EepromWrite32 + ** + ** Purpose: + ** + ** Assumptions and Notes: + ** + ** Parameters: + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** Return Values: + ** CFE_PSP_SUCCESS + ** CFE_PSP_ERROR_TIMEOUT write operation did not go through after a specific + ** timeout. + ** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit addressing + ** scheme. + */ +int32 CFE_PSP_EepromWrite32( cpuaddr MemoryAddress, uint32 uint32Value ) +{ + uint32 ret_value = CFE_PSP_SUCCESS; + + /* check 32 bit alignment */ + if( MemoryAddress & 0x00000003) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + + /* make the Write */ + *((uint32 *)MemoryAddress) = uint32Value; + + return(ret_value) ; +} + +/* + ** Name: CFE_PSP_EepromWrite16 + ** + ** Purpose: + ** + ** Assumptions and Notes: + ** + ** Parameters: + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** Return Values: + ** CFE_PSP_SUCCESS + ** CFE_PSP_ERROR_TIMEOUT write operation did not go through after a specific + ** timeout. + ** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit addressing + ** scheme. + */ +int32 CFE_PSP_EepromWrite16( cpuaddr MemoryAddress, uint16 uint16Value ) +{ + uint32 write32; + uint32 temp32; + uint32 aligned_address ; + + /* + ** check 16 bit alignment , check the 1st lsb + */ + if( MemoryAddress & 0x00000001) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + + temp32 = uint16Value ; + +#ifdef SOFTWARE_LITTLE_BIT_ORDER + /* + ** Implementation for Little Endian architectures ( x86 ) + */ + + /* + ** check the 2nd lsb to see if it's the 1st or 2nd 16 bit word + */ + if( (MemoryAddress & 0x00000002) ) + { + /* + ** writing the 16 high bit order of 32 bit field + */ + aligned_address = MemoryAddress - 2 ; + CFE_PSP_MemRead32 ( aligned_address ,&write32) ; + write32 = (write32 & 0x0000FFFF) | (temp32 << 16 ) ; + } + else + { + /* + ** writing the 16 low bit order of 32 bit field + */ + aligned_address = MemoryAddress; + CFE_PSP_MemRead32 ( aligned_address, &write32 ) ; + write32 = ( write32 & 0xFFFF0000 ) | ( temp32 ); + + } + +#else + + /* + ** Implementation for Big Endian architectures (PPC, Coldfire ) + */ + /* + ** check the 2nd lsb to see if it's the 1st or 2nd 16 bit word + */ + if( (MemoryAddress & 0x00000002) ) + { + /* + ** writing the 16 high bit order of 32 bit field + */ + aligned_address = MemoryAddress - 2 ; + CFE_PSP_MemRead32 ( aligned_address ,&write32) ; + write32 = (write32 & 0xFFFF0000) | (temp32) ; + } + else + { + /* + ** writing the 16 low bit order of 32 bit field + */ + aligned_address = MemoryAddress; + CFE_PSP_MemRead32 ( aligned_address, &write32 ) ; + write32 = ( write32 & 0x0000FFFF ) | ( temp32 << 16 ); + + } +#endif + + return(CFE_PSP_EepromWrite32(aligned_address,write32)) ; + +} + + +/* + ** Name: CFE_PSP_EepromWrite8 + ** + ** Purpose: + ** + ** Assumptions and Notes: + ** + ** Parameters: + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** Return Values: + ** CFE_PSP_SUCCESS + ** CFE_PSP_ERROR_TIMEOUT write operation did not go through after a specific + ** timeout. + */ + +int32 CFE_PSP_EepromWrite8( cpuaddr MemoryAddress, uint8 ByteValue ) +{ + uint32 aligned_address ; + uint16 write16 ,temp16; + + temp16 = ByteValue ; + + +#ifdef SOFTWARE_LITTLE_BIT_ORDER + /* + ** Implementation for Little Endian architectures ( x86 ) + */ + /* + ** check the 1st lsb + */ + if( MemoryAddress & 0x00000001) + { + /* + ** writing the 8 high bit order of 16 bit field + */ + aligned_address = MemoryAddress - 1; + CFE_PSP_MemRead16 ( aligned_address ,&write16) ; + write16 = (write16 & 0x00FF) | ( temp16 << 8) ; + } + else + { + /* + ** writing the 8 low bit order of 16 bit field + */ + aligned_address = MemoryAddress ; + CFE_PSP_MemRead16 ( aligned_address, &write16 ) ; + write16 = (temp16 ) | (write16 & 0xFF00 ) ; + } +#else + + /* + ** Implementation for Big Endian architectures (PPC, Coldfire ) + */ + + /* + ** check the 1st lsb + */ + if( MemoryAddress & 0x00000001) + { + /* + ** writing the 8 high bit order of 16 bit field + */ + aligned_address = MemoryAddress - 1; + CFE_PSP_MemRead16 ( aligned_address ,&write16) ; + write16 = (write16 & 0xFF00) | ( temp16) ; + } + else + { + /* + ** writing the 8 low bit order of 16 bit field + */ + aligned_address = MemoryAddress ; + CFE_PSP_MemRead16 ( aligned_address, &write16 ) ; + write16 = (temp16 << 8 ) | (write16 & 0x00FF ) ; + } + +#endif + + return(CFE_PSP_EepromWrite16(aligned_address,write16)) ; + +} + +/* +** Name: CFE_PSP_EepromWriteEnable +** +** Purpose: +** Eable the eeprom for write operation +** +** Assumptions and Notes: +** +** Parameters: +** Bank: Which bank of EEPROM +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** Return Values: +** CFE_PSP_SUCCESS +*/ +int32 CFE_PSP_EepromWriteEnable(uint32 Bank) +{ + return(CFE_PSP_SUCCESS) ; +} + +/* +** Name: CFE_PSP_EepromWriteDisable +** +** Purpose: +** Disable the eeprom from write operation +** +** Assumptions and Notes: +** +** Parameters: +** Bank: Which bank of EEPROM +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** Return Values: +** CFE_PSP_SUCCESS +*/ +int32 CFE_PSP_EepromWriteDisable(uint32 Bank) +{ + return(CFE_PSP_SUCCESS) ; +} + + +/* +** Name: CFE_PSP_EepromPowerUp +** +** Purpose: +** Power up the eeprom +** Assumptions and Notes: +** +** Parameters: +** Bank: Which bank of EEPROM +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** Return Values: +** CFE_PSP_SUCCESS +*/ +int32 CFE_PSP_EepromPowerUp(uint32 Bank) +{ + return(CFE_PSP_SUCCESS) ; +} + + + +/* +** Name: CFE_PSP_EepromPowerDown +** +** Purpose: +** Power down the eeprom +** Assumptions and Notes: +** +** Parameters: +** Bank: Which bank of EEPROM +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** Return Values: +** CFE_PSP_SUCCESS +*/ +int32 CFE_PSP_EepromPowerDown(uint32 Bank) +{ + return(CFE_PSP_SUCCESS) ; +} diff --git a/src/components/implementation/no_interface/cFE_booter/cfe_psp_memrange.c b/src/components/implementation/no_interface/cFE_booter/cfe_psp_memrange.c new file mode 100644 index 0000000000..1fd554ae24 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cfe_psp_memrange.c @@ -0,0 +1,311 @@ +/* +** File : cfe_psp_memrange.c +** +** +** Copyright (c) 2004-2011, United States Government as represented by +** Administrator for The National Aeronautics and Space Administration. +** All Rights Reserved. +** +** This is governed by the NASA Open Source Agreement and may be used, +** distributed and modified only pursuant to the terms of that agreement. +** +** Author : Alan Cudmore +** +** Purpose: +** This file contains the memory range functions for the cFE Platform Support Package. +** The memory range is a table of valid memory address ranges maintained by the cFE. +** +** +*/ + +/* +** Include section +*/ + +#include + +#include "cfe_psp.h" + +#ifdef _ENHANCED_BUILD_ + +/* + * The "extern" declaration for the MemRange table is in the configdata header + */ +#include "cfe_psp_configdata.h" + +#else + +/* +** The CFE_PSP_MemoryTable is defined in the BSP section: +** Example: arch/x86/pc/linux/bsp/CFE_PSP_memtab.c +** That is where the CPU and board specific memory ranges are known. +*/ +extern CFE_PSP_MemTable_t CFE_PSP_MemoryTable[CFE_PSP_MEM_TABLE_SIZE]; + +#endif + +/* +** Name: CFE_PSP_MemValidateRange +** +** Purpose: +** Validate the memory range and type using the global CFE_PSP_MemoryTable +** +** Assumptions and Notes: +** +** Parameters: +** Address -- A 32 bit starting address of the memory range +** Size -- A 32 bit size of the memory range ( Address + Size = End Address ) +** MemoryType -- The memory type to validate, including but not limited to: +** CFE_PSP_MEM_RAM, CFE_PSP_MEM_EEPROM, or CFE_PSP_MEM_ANY +** Any defined CFE_PSP_MEM_* enumeration can be specified +** +** Global Inputs: None +** +** Global Outputs: None +** +** Return Values: +** CFE_PSP_SUCCESS -- Memory range and type information is valid and can be used. +** CFE_PSP_INVALID_MEM_ADDR -- Starting address is not valid +** CFE_PSP_INVALID_MEM_TYPE -- Memory type associated with the range does not match the passed in type. +** CFE_PSP_INVALID_MEM_RANGE -- The Memory range associated with the address is not large enough to contain +** Address + Size. +*/ +int32 CFE_PSP_MemValidateRange(cpuaddr Address, uint32 Size, uint32 MemoryType) +{ + cpuaddr StartAddressToTest = Address; + cpuaddr EndAddressToTest = Address + Size - 1; + cpuaddr StartAddressInTable; + cpuaddr EndAddressInTable; + uint32 TypeInTable; + int32 ReturnCode = CFE_PSP_INVALID_MEM_ADDR; + uint32 i; + + /* + ** Before searching table, do a preliminary parameter validation + */ + if ( MemoryType != CFE_PSP_MEM_ANY && MemoryType != CFE_PSP_MEM_RAM && MemoryType != CFE_PSP_MEM_EEPROM ) + { + return(CFE_PSP_INVALID_MEM_TYPE); + } + + if ( EndAddressToTest < StartAddressToTest ) + { + return(CFE_PSP_INVALID_MEM_RANGE); + } + + for ( i = 0; i < CFE_PSP_MEM_TABLE_SIZE; i++ ) + { + /* + ** Only look at valid memory table entries + */ + if ( CFE_PSP_MemoryTable[i].MemoryType != CFE_PSP_MEM_INVALID ) + { + StartAddressInTable = CFE_PSP_MemoryTable[i].StartAddr; + EndAddressInTable = CFE_PSP_MemoryTable[i].StartAddr + CFE_PSP_MemoryTable[i].Size - 1; + TypeInTable = CFE_PSP_MemoryTable[i].MemoryType; + + /* + ** Step 1: Get the Address to Fit within the range + */ + if (( StartAddressToTest >= StartAddressInTable ) && ( StartAddressToTest <= EndAddressInTable )) + { + /* + ** Step 2: Does the End Address Fit within the Range? + ** should not have to test the lower address, + ** since the StartAddressToTest is already in the range. + ** Can it be fooled by overflowing the 32 bit int? + */ + if ( EndAddressToTest <= EndAddressInTable ) + { + /* + ** Step 3: Is the type OK? + */ + if ( MemoryType == CFE_PSP_MEM_ANY ) + { + ReturnCode = CFE_PSP_SUCCESS; + break; /* The range is valid, break out of the loop */ + } + else if ( MemoryType == CFE_PSP_MEM_RAM && TypeInTable == CFE_PSP_MEM_RAM ) + { + ReturnCode = CFE_PSP_SUCCESS; + break; /* The range is valid, break out of the loop */ + } + else if ( MemoryType == CFE_PSP_MEM_EEPROM && TypeInTable == CFE_PSP_MEM_EEPROM ) + { + ReturnCode = CFE_PSP_SUCCESS; + break; /* The range is valid, break out of the loop */ + } + else + { + ReturnCode = CFE_PSP_INVALID_MEM_TYPE; + /* The range is not valid, move to the next entry */ + } + } + else + { + ReturnCode = CFE_PSP_INVALID_MEM_RANGE; + /* The range is not valid, move to the next entry */ + } + } + else + { + ReturnCode = CFE_PSP_INVALID_MEM_ADDR; + /* The range is not valid, move to the next entry */ + } + } /* End if MemoryType != CFE_PSP_MEM_INVALID */ + + } /* End for */ + return(ReturnCode); +} + +/* +** Name: CFE_PSP_MemRanges +** +** Purpose: +** Return the number of memory ranges in the CFE_PSP_MemoryTable +** +** Assumptions and Notes: +** +** Parameters: +** None +** +** Global Inputs: None +** +** Global Outputs: None +** +** Return Values: +** Positive integer number of entries in the memory range table +*/ +uint32 CFE_PSP_MemRanges(void) +{ + return(CFE_PSP_MEM_TABLE_SIZE) ; +} + + +/* +** Name: CFE_PSP_MemRangeSet +** +** Purpose: +** This function populates one of the records in the CFE_PSP_MemoryTable. +** +** Assumptions and Notes: +** Because the table is fixed size, the entries are set by using the integer index. +** No validation is done with the address or size. +** +** Parameters: +** RangeNum -- A 32 bit integer ( starting with 0 ) specifying the MemoryTable entry. +** MemoryType -- The memory type to validate, including but not limited to: +** CFE_PSP_MEM_RAM, CFE_PSP_MEM_EEPROM, or CFE_PSP_MEM_ANY +** Any defined CFE_PSP_MEM_* enumeration can be specified +** Address -- A 32 bit starting address of the memory range +** Size -- A 32 bit size of the memory range ( Address + Size = End Address ) +** WordSize -- The minimum addressable size of the range: +** ( CFE_PSP_MEM_SIZE_BYTE, CFE_PSP_MEM_SIZE_WORD, CFE_PSP_MEM_SIZE_DWORD ) +** Attributes -- The attributes of the Memory Range: +** (CFE_PSP_MEM_ATTR_WRITE, CFE_PSP_MEM_ATTR_READ, CFE_PSP_MEM_ATTR_READWRITE) +** +** Global Inputs: Reads CFE_PSP_MemoryTable +** +** Global Outputs: Changes CFE_PSP_MemoryTable +** +** Return Values: +** CFE_PSP_SUCCESS -- Memory range set successfuly. +** CFE_PSP_INVALID_MEM_RANGE -- The index into the table is invalid +** CFE_PSP_INVALID_MEM_ADDR -- Starting address is not valid +** CFE_PSP_INVALID_MEM_TYPE -- Memory type associated with the range does not match the passed in type. +** OP_INVALID_MEM_SIZE -- The Memory range associated with the address is not large enough to contain +** Address + Size. +** CFE_PSP_INVALID_MEM_WORDSIZE -- The WordSIze parameter is not one of the predefined types. +** CFE_PSP_INVALID_MEM_ATTR -- The Attributes parameter is not one of the predefined types. +*/ +int32 CFE_PSP_MemRangeSet (uint32 RangeNum, uint32 MemoryType, cpuaddr StartAddr, + uint32 Size, uint32 WordSize, uint32 Attributes) +{ + + if ( RangeNum >= CFE_PSP_MEM_TABLE_SIZE ) + { + return(CFE_PSP_INVALID_MEM_RANGE); + } + + if ( ( MemoryType != CFE_PSP_MEM_RAM ) && ( MemoryType != CFE_PSP_MEM_EEPROM ) ) + { + return(CFE_PSP_INVALID_MEM_TYPE); + } + + if ( ( WordSize != CFE_PSP_MEM_SIZE_BYTE ) && ( WordSize != CFE_PSP_MEM_SIZE_WORD ) && + ( WordSize != CFE_PSP_MEM_SIZE_DWORD ) ) + { + return(CFE_PSP_INVALID_MEM_WORDSIZE); + } + + if ( ( Attributes != CFE_PSP_MEM_ATTR_READ ) && ( Attributes != CFE_PSP_MEM_ATTR_WRITE ) && + ( Attributes != CFE_PSP_MEM_ATTR_READWRITE )) + { + return(CFE_PSP_INVALID_MEM_ATTR); + } + + /* + ** Parameters check out, add the range + */ + CFE_PSP_MemoryTable[RangeNum].MemoryType = MemoryType; + CFE_PSP_MemoryTable[RangeNum].StartAddr = StartAddr; + CFE_PSP_MemoryTable[RangeNum].Size = Size; + CFE_PSP_MemoryTable[RangeNum].WordSize = WordSize; + CFE_PSP_MemoryTable[RangeNum].Attributes = Attributes; + + return(CFE_PSP_SUCCESS) ; +} + +/* +** Name: CFE_PSP_MemRangeGet +** +** Purpose: +** This function retrieves one of the records in the CFE_PSP_MemoryTable. +** +** Assumptions and Notes: +** Becasue the table is fixed size, the entries are accessed by using the integer index. +** +** Parameters: +** RangeNum -- A 32 bit integer ( starting with 0 ) specifying the MemoryTable entry. +** *MemoryType -- A pointer to the 32 bit integer where the Memory Type is stored. +** Any defined CFE_PSP_MEM_* enumeration can be specified +** *Address -- A pointer to the 32 bit integer where the 32 bit starting address of the memory range +** is stored. +** *Size -- A pointer to the 32 bit integer where the 32 bit size of the memory range +** is stored. +** *WordSize -- A pointer to the 32 bit integer where the the minimum addressable size of the range: +** ( CFE_PSP_MEM_SIZE_BYTE, CFE_PSP_MEM_SIZE_WORD, CFE_PSP_MEM_SIZE_DWORD ) +** Attributes -- The attributes of the Memory Range: +** (CFE_PSP_MEM_ATTR_WRITE, CFE_PSP_MEM_ATTR_READ, CFE_PSP_MEM_ATTR_READWRITE) +** +** Global Inputs: Reads CFE_PSP_MemoryTable +** +** Global Outputs: Changes CFE_PSP_MemoryTable +** +** Return Values: +** CFE_PSP_SUCCESS -- Memory range returned successfuly. +** CFE_PSP_INVALID_POINTER -- Parameter error +** CFE_PSP_INVALID_MEM_RANGE -- The index into the table is invalid +*/ +int32 CFE_PSP_MemRangeGet (uint32 RangeNum, uint32 *MemoryType, cpuaddr *StartAddr, + uint32 *Size, uint32 *WordSize, uint32 *Attributes) +{ + + if ( MemoryType == NULL || StartAddr == NULL || Size == NULL || WordSize == NULL || Attributes == NULL ) + { + return(CFE_PSP_INVALID_POINTER); + } + + if ( RangeNum >= CFE_PSP_MEM_TABLE_SIZE ) + { + return(CFE_PSP_INVALID_MEM_RANGE); + } + + *MemoryType = CFE_PSP_MemoryTable[RangeNum].MemoryType; + *StartAddr = CFE_PSP_MemoryTable[RangeNum].StartAddr; + *Size = CFE_PSP_MemoryTable[RangeNum].Size; + *WordSize = CFE_PSP_MemoryTable[RangeNum].WordSize; + *Attributes = CFE_PSP_MemoryTable[RangeNum].Attributes; + + return(CFE_PSP_SUCCESS) ; +} diff --git a/src/components/implementation/no_interface/cFE_booter/cfe_psp_memtab.c b/src/components/implementation/no_interface/cFE_booter/cfe_psp_memtab.c new file mode 100644 index 0000000000..c2cef1e59b --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cfe_psp_memtab.c @@ -0,0 +1,47 @@ +/* +** File : cfe_psp_memtab.c +** +** +** Copyright (c) 2004-2011, United States Government as represented by +** Administrator for The National Aeronautics and Space Administration. +** All Rights Reserved. +** +** This is governed by the NASA Open Source Agreement and may be used, +** distributed and modified only pursuant to the terms of that agreement. +** +** Author : Alan Cudmore +** +** Purpose: Memory Range Table for cFE/PSP. +** +** +*/ + +/* +** Includes +*/ + +#include +#include "common_types.h" +#include "osapi.h" +#include "cfe_psp.h" +#include "cfe_psp_config.h" + + + +/* +** Valid memory map for this target. +** If you need to add more entries, increase CFE_PSP_MEM_TABLE_SIZE in the osconfig.h file. +*/ +CFE_PSP_MemTable_t CFE_PSP_MemoryTable[CFE_PSP_MEM_TABLE_SIZE] = +{ + { CFE_PSP_MEM_RAM, CFE_PSP_MEM_SIZE_DWORD, 0, 0xFFFFFFFF, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, + { CFE_PSP_MEM_INVALID, 0, 0, 0, CFE_PSP_MEM_ATTR_READWRITE }, +}; diff --git a/src/components/implementation/no_interface/cFE_booter/cfe_psp_memutils.c b/src/components/implementation/no_interface/cFE_booter/cfe_psp_memutils.c new file mode 100644 index 0000000000..6379c9c49a --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cfe_psp_memutils.c @@ -0,0 +1,94 @@ +/* +** File : cfe_psp_memutils.c +** +** +** Copyright (c) 2004-2011, United States Government as represented by +** Administrator for The National Aeronautics and Space Administration. +** All Rights Reserved. +** +** This is governed by the NASA Open Source Agreement and may be used, +** distributed and modified only pursuant to the terms of that agreement. +** +** Author : Ezra Yeheskeli +** +** Purpose: +** This file contains some of the cFE Platform Support Layer. +** It contains the processor architecture specific calls. +** +** +*/ + +/* +** Include section +*/ + +#include + +/* +** User defined include files +*/ + +#include "cfe_psp.h" +/* +** global memory +*/ + +/* +** Name: CFE_PSP_MemCpy +** +** Purpose: +** Copies 'size' byte from memory address pointed by 'src' to memory +** address pointed by ' dst' For now we are using the standard c library +** call 'memcpy' but if we find we need to make it more efficient then +** we'll implement it in assembly. +** +** Assumptions and Notes: +** +** Parameters: +** dst : pointer to an address to copy to +** src : pointer address to copy from +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** Return Values: CFE_PSP_SUCCESS +*/ +int32 CFE_PSP_MemCpy ( void *dst, void *src, uint32 size) +{ + memcpy( dst, src, size); + return(CFE_PSP_SUCCESS) ; +} + + + +/* +** Name: CFE_PSP_MemSet +** +** Purpose: +** Copies 'size' number of byte of value 'value' to memory address pointed +** by 'dst' .For now we are using the standard c library call 'memset' +** but if we find we need to make it more efficient then we'll implement +** it in assembly. +** +** +** Assumptions and Notes: +** +** Parameters: +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** Return Values: CFE_PSP_SUCCESS +*/ +/* +** CFE_PSP_MemSet +*/ +int32 CFE_PSP_MemSet ( void *dst, uint8 value , uint32 size) +{ + memset( dst, (int)value, (size_t)size); + return(CFE_PSP_SUCCESS) ; +} diff --git a/src/components/implementation/no_interface/cFE_booter/cfe_psp_port.c b/src/components/implementation/no_interface/cFE_booter/cfe_psp_port.c new file mode 100644 index 0000000000..a88dd0aada --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cfe_psp_port.c @@ -0,0 +1,231 @@ +/* +** File : cfe_pep_memport.c +** +** +** Copyright (c) 2004-2011, United States Government as represented by +** Administrator for The National Aeronautics and Space Administration. +** All Rights Reserved. +** +** This is governed by the NASA Open Source Agreement and may be used, +** distributed and modified only pursuant to the terms of that agreement. +** +** Author : Ezra Yeheskeli +** +** Purpose: +** This file contains some of the cFE Platform Support Layer. +** It contains the processor architecture specific calls. +** +** 16-Nov-2003 Ezra Yeheskeli +** - First Creation. +** +*/ + +/* +** Include section +*/ +#include +#include "cfe_psp.h" + + +/* +** global memory +*/ + + + + +/* +** Name: CFE_PSP_PortRead8 +** +** Purpose: +** Read one byte of memory. +** +** +** Parameters: +** PortAddress : Address to be read +** ByteValue : The address content will be copied to the location pointed by +** this argument +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** +** Return Values: CFE_PSP_SUCCESS +*/ +int32 CFE_PSP_PortRead8( cpuaddr PortAddress, uint8 *ByteValue ) +{ + + (*ByteValue) = (uint8)*((uint8 *)PortAddress) ; + + return(CFE_PSP_SUCCESS) ; +} + +/* +** Name: CFE_PSP_PortWrite8 +** +** Purpose: +** Write one byte of memory. +** +** +** Parameters: +** PortAddress : Address to be written to +** ByteValue : The content pointed by this argument will be copied to the +** address +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** +** Return Values: +** CFE_PSP_SUCCESS +*/ +int32 CFE_PSP_PortWrite8 ( cpuaddr PortAddress, uint8 ByteValue ) +{ + *((uint8 *)PortAddress) = ByteValue; + return(CFE_PSP_SUCCESS) ; + +} + +/* +** Name: CFE_PSP_PortRead16 +** +** Purpose: +** Read 2 bytes of memory. +** +** +** Parameters: +** PortAddress : Address to be read +** uint16Value : The address content will be copied to the location pointed by +** this argument +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** +** Return Values: +** CFE_PSP_SUCCESS +** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit +** addressing scheme. +*/ +int32 CFE_PSP_PortRead16( cpuaddr PortAddress, uint16 *uint16Value ) +{ + /* check 16 bit alignment , check the 1st lsb */ + if( PortAddress & 0x00000001) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + (*uint16Value) = *((uint16 *)PortAddress) ; + return(CFE_PSP_SUCCESS) ; + +} + + +/* +** Name: CFE_PSP_PortWrite16 +** +** Purpose: +** Write 2 byte of memory. +** +** +** Parameters: +** PortAddress : Address to be written to +** uint16Value : The content pointed by this argument will be copied to the +** address +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** +** Return Values: +** CFE_PSP_SUCCESS +** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit +** addressing scheme. +*/ +int32 CFE_PSP_PortWrite16 ( cpuaddr PortAddress, uint16 uint16Value ) +{ + /* check 16 bit alignment , check the 1st lsb */ + if( PortAddress & 0x00000001) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + *((uint16 *)PortAddress) = uint16Value; + return(CFE_PSP_SUCCESS) ; +} + +/* +** Name: CFE_PSP_PortRead32 +** +** Purpose: +** Read 4 bytes of memory. +** +** +** Parameters: +** PortAddress : Address to be read +** uint32Value : The address content will be copied to the location pointed by +** this argument +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** +** Return Values: +** CFE_PSP_SUCCESS +** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit +** addressing scheme. +*/ +int32 CFE_PSP_PortRead32( cpuaddr PortAddress, uint32 *uint32Value ) +{ + /* check 32 bit alignment */ + if( PortAddress & 0x00000003) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + (*uint32Value) = *((uint32 *)PortAddress) ; + return(CFE_PSP_SUCCESS) ; + +} + +/* +** Name: CFE_PSP_PortWrite32 +** +** Purpose: +** Write 4 byte of memory. +** +** +** Parameters: +** PortAddress : Address to be written to +** uint32Value : The content pointed by this argument will be copied to the +** address +** +** Global Inputs: None +** +** Global Outputs: None +** +** +** +** Return Values: +** CFE_PSP_SUCCESS +** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit +** addressing scheme. +*/ +int32 CFE_PSP_PortWrite32 ( cpuaddr PortAddress, uint32 uint32Value ) +{ + /* check 32 bit alignment */ + if( PortAddress & 0x00000003) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + *((uint32 *)PortAddress) = uint32Value; + return(CFE_PSP_SUCCESS) ; + +} diff --git a/src/components/implementation/no_interface/cFE_booter/cfe_psp_ram.c b/src/components/implementation/no_interface/cFE_booter/cfe_psp_ram.c new file mode 100644 index 0000000000..8fcae8fd57 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/cfe_psp_ram.c @@ -0,0 +1,225 @@ +/* +** File : cfe_psp_memram.c +** +** +** Copyright (c) 2004-2011, United States Government as represented by +** Administrator for The National Aeronautics and Space Administration. +** All Rights Reserved. +** +** This is governed by the NASA Open Source Agreement and may be used, +** distributed and modified only pursuant to the terms of that agreement. +** +** Author : Ezra Yeheskeli +** +** Purpose: +** This file contains some of the cFE Platform Support Layer. +** It contains the processor architecture specific calls. +** +** 16-Nov-2003 Ezra Yeheskeli +** - First Creation. +** +*/ + +/* +** Include section +*/ +#include +#include "cfe_psp.h" + + +/* +** global memory +*/ + +/* + ** Name: CFE_PSP_MemRead8 + ** + ** Purpose: + ** Read one byte of memory. + ** + ** + ** Parameters: + ** MemoryAddress : Address to be read + ** ByteValue : The address content will be copied to the location pointed by this argument + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** + ** Return Values: CFE_PSP_SUCCESS + */ +int32 CFE_PSP_MemRead8( cpuaddr MemoryAddress, uint8 *ByteValue ) +{ + + (*ByteValue) = *((uint8 *)MemoryAddress) ; + + return(CFE_PSP_SUCCESS) ; +} + +/* + ** Name: CFE_PSP_MemWrite8 + ** + ** Purpose: + ** Write one byte of memory. + ** + ** + ** Parameters: + ** MemoryAddress : Address to be written to + ** ByteValue : The content pointed by this argument will be copied to the address + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** + ** Return Values: + ** CFE_PSP_SUCCESS + */ +int32 CFE_PSP_MemWrite8 ( cpuaddr MemoryAddress, uint8 ByteValue ) +{ + *((uint8 *)MemoryAddress) = ByteValue; + return(CFE_PSP_SUCCESS) ; + +} + +/* + ** Name: CFE_PSP_MemRead16 + ** + ** Purpose: + ** Read 2 bytes of memory. + ** + ** + ** Parameters: + ** MemoryAddress : Address to be read + ** uint16Value : The address content will be copied to the location pointed by + ** this argument + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** + ** Return Values: + ** CFE_PSP_SUCCESS + ** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit + ** addressing scheme. + */ +int32 CFE_PSP_MemRead16( cpuaddr MemoryAddress, uint16 *uint16Value ) +{ + /* check 16 bit alignment , check the 1st lsb */ + if( MemoryAddress & 0x00000001) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + (*uint16Value) = *((uint16 *)MemoryAddress) ; + return(CFE_PSP_SUCCESS) ; + +} +/* + ** Name: CFE_PSP_MemWrite16 + ** + ** Purpose: + ** Write 2 byte of memory. + ** + ** + ** Parameters: + ** MemoryAddress : Address to be written to + ** uint16Value : The content pointed by this argument will be copied to the + ** address + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** + ** Return Values: + ** CFE_PSP_SUCCESS + ** CFE_PSP_ERROR_ADD_MISALIGNED The MemoryAddress is not aligned to 16 bit + ** addressing scheme. + */ +int32 CFE_PSP_MemWrite16 ( cpuaddr MemoryAddress, uint16 uint16Value ) +{ + /* check 16 bit alignment , check the 1st lsb */ + if( MemoryAddress & 0x00000001) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + *((uint16 *)MemoryAddress) = uint16Value; + return(CFE_PSP_SUCCESS) ; +} +/* + ** Name: CFE_PSP_MemRead32 + ** + ** Purpose: + ** Read 4 bytes of memory. + ** + ** + ** Parameters: + ** MemoryAddress : Address to be read + ** uint32Value : The address content will be copied to the location pointed by + ** this argument + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** + ** Return Values: + ** CFE_PSP_SUCCESS + ** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit + ** addressing scheme. + */ +int32 CFE_PSP_MemRead32( cpuaddr MemoryAddress, uint32 *uint32Value ) +{ + /* check 32 bit alignment */ + if( MemoryAddress & 0x00000003) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + (*uint32Value) = *((uint32 *)MemoryAddress) ; + + return(CFE_PSP_SUCCESS) ; +} + +/* + ** Name: CFE_PSP_MemWrite32 + ** + ** Purpose: + ** Write 4 byte of memory. + ** + ** + ** Parameters: + ** MemoryAddress : Address to be written to + ** uint32Value : The content pointed by this argument will be copied to the + ** address + ** + ** Global Inputs: None + ** + ** Global Outputs: None + ** + ** + ** + ** Return Values: + ** CFE_PSP_SUCCESS + ** CFE_PSP_ERROR_ADD_MISALIGNED The Address is not aligned to 16 bit + ** addressing scheme. + */ +int32 CFE_PSP_MemWrite32 ( cpuaddr MemoryAddress, uint32 uint32Value ) +{ + + /* check 32 bit alignment */ + if( MemoryAddress & 0x00000003) + { + return(CFE_PSP_ERROR_ADDRESS_MISALIGNED) ; + } + + *((uint32 *)MemoryAddress) = uint32Value; + + return(CFE_PSP_SUCCESS) ; +} diff --git a/src/components/implementation/no_interface/cFE_booter/osapi.c b/src/components/implementation/no_interface/cFE_booter/osapi.c new file mode 100644 index 0000000000..093ce94875 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/osapi.c @@ -0,0 +1,463 @@ +#include +#include + +#include +#include + +#include "gen/osapi.h" +#include "gen/cfe_psp.h" +#include "gen/cfe_time.h" +#include "gen/common_types.h" + +#include "cFE_util.h" + +/* + * Initialization of API + */ +int have_initialized = 0; + +int32 +OS_API_Init(void) +{ + struct cos_defcompinfo *defci; + struct cos_compinfo * ci; + + if (have_initialized) return OS_SUCCESS; + + cos_defcompinfo_init(); + defci = cos_defcompinfo_curr_get(); + ci = cos_compinfo_get(defci); + cos_meminfo_init(&(ci->mi), BOOT_MEM_KM_BASE, COS_MEM_KERN_PA_SZ, BOOT_CAPTBL_SELF_UNTYPED_PT); + + OS_FS_Init(); + OS_ModuleTableInit(); + + have_initialized = 1; + + return OS_SUCCESS; +} + +/* + * OS_DeleteAllObjects() provides a means to clean up all resources allocated by this + * instance of OSAL. It would typically be used during an orderly shutdown but may also + * be helpful for testing purposes. + */ +void +OS_DeleteAllObjects(void) +{ + uint32 i; + + /* FIXME: Add deleting tasks when we have a way of iterating through them + * for (i = 0; i < OS_MAX_TASKS; ++i) + * { + * OS_TaskDelete(i); + * } + * for (i = 0; i < OS_MAX_TIMERS; ++i) + * { + * OS_TimerDelete(i); + * } */ + for (i = 0; i < OS_MAX_QUEUES; ++i) { OS_QueueDelete(i); } + for (i = 0; i < OS_MAX_MUTEXES; ++i) { OS_MutSemDelete(i); } + for (i = 0; i < OS_MAX_COUNT_SEMAPHORES; ++i) { OS_CountSemDelete(i); } + for (i = 0; i < OS_MAX_BIN_SEMAPHORES; ++i) { OS_BinSemDelete(i); } + for (i = 0; i < OS_MAX_MODULES; ++i) { OS_ModuleUnload(i); } + for (i = 0; i < OS_MAX_NUM_OPEN_FILES; ++i) { OS_close(i); } +} + + +/* + * OS Time/Tick related API + */ + +int32 +OS_Milli2Ticks(uint32 milliseconds) +{ + uint32 ticks_per_millisecond = CFE_PSP_GetTimerTicksPerSecond() / 1000; + return (int32)(ticks_per_millisecond * milliseconds); +} + +int32 +OS_Tick2Micros(void) +{ + return SL_MIN_PERIOD_US; +} + +OS_time_t local_time; +microsec_t last_time_check; + +OS_time_t +OS_AdvanceTime(OS_time_t initial_time, microsec_t usec) +{ + microsec_t old_seconds = (microsec_t)initial_time.seconds; + microsec_t old_additional_usec = (microsec_t)initial_time.microsecs; + + microsec_t old_usec = old_seconds * (1000 * 1000) + old_additional_usec; + microsec_t new_usec = old_usec + usec; + + microsec_t new_seconds = new_usec / (1000 * 1000); + microsec_t new_additional_usec = new_usec % (1000 * 1000); + + return (OS_time_t){.seconds = new_seconds, .microsecs = new_additional_usec}; +} + +int32 +OS_GetLocalTime(OS_time_t *time_struct) +{ + if (!time_struct) { return OS_INVALID_POINTER; } + + if (last_time_check == 0) { + local_time = (OS_time_t){.seconds = 1181683060, .microsecs = 0}; + last_time_check = sl_now_usec(); + } else { + microsec_t current_time = sl_now_usec(); + microsec_t elapsed_usec = current_time - last_time_check; + + local_time = OS_AdvanceTime(local_time, elapsed_usec); + last_time_check = current_time; + } + + *time_struct = local_time; + + return OS_SUCCESS; +} /* end OS_GetLocalTime */ + +int32 +OS_SetLocalTime(OS_time_t *time_struct) +{ + if (!time_struct) { return OS_INVALID_POINTER; } + + local_time = *time_struct; + last_time_check = sl_now_usec(); + + return OS_SUCCESS; +} /*end OS_SetLocalTime */ + +/* + * Exception API + */ + +int32 +OS_ExcAttachHandler(uint32 ExceptionNumber, void (*ExceptionHandler)(uint32, const void *, uint32), int32 parameter) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + + +int32 +OS_ExcEnable(int32 ExceptionNumber) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_ExcDisable(int32 ExceptionNumber) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +/* + * Floating Point Unit API + */ + +int32 +OS_FPUExcAttachHandler(uint32 ExceptionNumber, void *ExceptionHandler, int32 parameter) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_FPUExcEnable(int32 ExceptionNumber) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_FPUExcDisable(int32 ExceptionNumber) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_FPUExcSetMask(uint32 mask) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_FPUExcGetMask(uint32 *mask) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +/* + * Interrupt API + * The disabling APIs always work, since interrupts are always disabled + */ +int32 +OS_IntAttachHandler(uint32 InterruptNumber, osal_task_entry InterruptHandler, int32 parameter) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_IntUnlock(int32 IntLevel) +{ + return OS_SUCCESS; +} + +int32 +OS_IntLock(void) +{ + return OS_SUCCESS; +} + +int32 +OS_IntEnable(int32 Level) +{ + return OS_SUCCESS; +} + +int32 +OS_IntDisable(int32 Level) +{ + return OS_SUCCESS; +} + +int32 +OS_IntSetMask(uint32 mask) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_IntGetMask(uint32 *mask) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_IntAck(int32 InterruptNumber) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +/* + * Shared memory API + */ +int32 +OS_ShMemInit(void) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_ShMemCreate(uint32 *Id, uint32 NBytes, const char *SegName) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_ShMemSemTake(uint32 Id) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_ShMemSemGive(uint32 Id) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_ShMemAttach(cpuaddr *Address, uint32 Id) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_ShMemGetIdByName(uint32 *ShMemId, const char *SegName) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +/* + * Heap API + */ +int32 +OS_HeapGetInfo(OS_heap_prop_t *heap_prop) +{ + /* TODO: Implement me! */ + return OS_ERR_NOT_IMPLEMENTED; +} + +/* + * API for useful debugging function + * (Implementation stolen from the posix osapi) + */ + +int32 +OS_GetErrorName(int32 error_num, os_err_name_t *err_name) +{ + /* + * Implementation note for developers: + * + * The size of the string literals below (including the terminating null) + * must fit into os_err_name_t. Always check the string length when + * adding or modifying strings in this function. If changing os_err_name_t + * then confirm these strings will fit. + */ + + os_err_name_t local_name; + uint32 return_code = OS_SUCCESS; + + if (err_name == NULL) { return (OS_INVALID_POINTER); } + + switch (error_num) { + case OS_SUCCESS: + strcpy(local_name, "OS_SUCCESS"); + break; + case OS_ERROR: + strcpy(local_name, "OS_ERROR"); + break; + case OS_INVALID_POINTER: + strcpy(local_name, "OS_INVALID_POINTER"); + break; + case OS_ERROR_ADDRESS_MISALIGNED: + strcpy(local_name, "OS_ADDRESS_MISALIGNED"); + break; + case OS_ERROR_TIMEOUT: + strcpy(local_name, "OS_ERROR_TIMEOUT"); + break; + case OS_INVALID_INT_NUM: + strcpy(local_name, "OS_INVALID_INT_NUM"); + break; + case OS_SEM_FAILURE: + strcpy(local_name, "OS_SEM_FAILURE"); + break; + case OS_SEM_TIMEOUT: + strcpy(local_name, "OS_SEM_TIMEOUT"); + break; + case OS_QUEUE_EMPTY: + strcpy(local_name, "OS_QUEUE_EMPTY"); + break; + case OS_QUEUE_FULL: + strcpy(local_name, "OS_QUEUE_FULL"); + break; + case OS_QUEUE_TIMEOUT: + strcpy(local_name, "OS_QUEUE_TIMEOUT"); + break; + case OS_QUEUE_INVALID_SIZE: + strcpy(local_name, "OS_QUEUE_INVALID_SIZE"); + break; + case OS_QUEUE_ID_ERROR: + strcpy(local_name, "OS_QUEUE_ID_ERROR"); + break; + case OS_ERR_NAME_TOO_LONG: + strcpy(local_name, "OS_ERR_NAME_TOO_LONG"); + break; + case OS_ERR_NO_FREE_IDS: + strcpy(local_name, "OS_ERR_NO_FREE_IDS"); + break; + case OS_ERR_NAME_TAKEN: + strcpy(local_name, "OS_ERR_NAME_TAKEN"); + break; + case OS_ERR_INVALID_ID: + strcpy(local_name, "OS_ERR_INVALID_ID"); + break; + case OS_ERR_NAME_NOT_FOUND: + strcpy(local_name, "OS_ERR_NAME_NOT_FOUND"); + break; + case OS_ERR_SEM_NOT_FULL: + strcpy(local_name, "OS_ERR_SEM_NOT_FULL"); + break; + case OS_ERR_INVALID_PRIORITY: + strcpy(local_name, "OS_ERR_INVALID_PRIORITY"); + break; + + default: + strcpy(local_name, "ERROR_UNKNOWN"); + return_code = OS_ERROR; + } + + strcpy((char *)err_name, local_name); + + return return_code; +} + + +/* + * Abstraction for printf statements + */ +int is_printf_enabled = TRUE; + +/* We expose this function so that app components can use it */ +int +emu_is_printf_enabled() +{ + return is_printf_enabled; +} + +void +OS_printf(const char *string, ...) +{ + char s[OS_BUFFER_SIZE]; + va_list arg_ptr; + int ret, len = OS_BUFFER_SIZE; + + if (!is_printf_enabled) return; + + va_start(arg_ptr, string); + ret = vsnprintf(s, len, string, arg_ptr); + va_end(arg_ptr); + cos_llprint(s, ret); +} + +void +OS_sprintf(char *str, const char *format, ...) +{ + va_list arg_ptr; + va_start(arg_ptr, format); + vsprintf(str, format, arg_ptr); + va_end(arg_ptr); +} + +void +OS_printf_disable(void) +{ + is_printf_enabled = FALSE; +} + +void +OS_printf_enable(void) +{ + is_printf_enabled = TRUE; +} + +/* + * Call to exit the running application + * Normally embedded applications run forever, but for debugging purposes + * (unit testing for example) this is needed in order to end the test + */ +void +OS_ApplicationExit(int32 Status) +{ + PANIC("Application exit invoked!"); +} diff --git a/src/components/implementation/no_interface/cFE_booter/osfiles.c b/src/components/implementation/no_interface/cFE_booter/osfiles.c new file mode 100644 index 0000000000..8a928d5c66 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/osfiles.c @@ -0,0 +1,443 @@ +#include "osfilesys.h" +#include "tar.h" + +/****************************************************************************** +** Standard File system API +******************************************************************************/ +/* + * Initializes the File System functions + */ + +int32 +OS_FS_Init(void) +{ + os_dirent_t d; + uint32 ret = 0; + + ret = tar_load(); + if (ret != OS_FS_SUCCESS) return ret; + ret = fs_init("/ramdev0", "RAM", 512, 4096); + if (ret != OS_FS_SUCCESS) return ret; + return tar_parse(); +} + +/* + * Creates a file specified by path + */ +int32 +OS_creat(const char *path, int32 access) +{ + int32 ret = path_isvalid(path); + if (access != OS_READ_WRITE && access != OS_WRITE_ONLY) return OS_FS_ERROR; + if (ret != OS_FS_SUCCESS) return ret; + return file_create((char *)path, access); +} + +/* + * Open a file for reading/writing. Returns file descriptor + */ +int32 +OS_open(const char *path, int32 access, uint32 mode) +{ + int32 ret; + + if (access != OS_READ_WRITE && access != OS_WRITE_ONLY && access != OS_READ_ONLY) { return OS_FS_ERROR; } + ret = path_exists(path); + if (ret != OS_FS_SUCCESS) return ret; + return file_open((char *)path, access); +} + +/* + * Closes an open file. + */ +int32 +OS_close(int32 filedes) +{ + if (chk_fd(filedes) != OS_FS_SUCCESS) return OS_FS_ERR_INVALID_FD; + return file_close(filedes); +} + +/* + * Reads nbytes bytes from file into buffer + */ +int32 +OS_read(int32 filedes, void *buffer, uint32 nbytes) +{ + if (chk_fd(filedes) != OS_FS_SUCCESS) return OS_FS_ERR_INVALID_FD; + return file_read(filedes, buffer, nbytes); +} + +/* + * Write nybytes bytes of buffer into the file + */ +int32 +OS_write(int32 filedes, void *buffer, uint32 nbytes) +{ + return file_write(filedes, buffer, nbytes); +} + +/* + * Changes the permissions of a file + * This is not used by the cFE and UT tests that it returns NOT_IMPLEMENTED + */ +int32 +OS_chmod(const char *path, uint32 access) +{ + return OS_ERR_NOT_IMPLEMENTED; +} + +/* + * Returns file status information in filestats + */ +int32 +OS_stat(const char *path, os_fstat_t *filestats) +{ + int32 ret; + + if (!filestats || !path) return OS_FS_ERR_INVALID_POINTER; + ret = path_exists(path); + if (ret != OS_FS_SUCCESS) return ret; + return file_stat((char *)path, filestats); +} + +/* + * Seeks to the specified position of an open file + */ +int32 +OS_lseek(int32 filedes, int32 offset, uint32 whence) +{ + return file_lseek(filedes, offset, whence); +} + +/* + * Removes a file from the file system + */ +int32 +OS_remove(const char *path) +{ + int32 ret = path_exists(path); + if (ret != OS_FS_SUCCESS) return ret; + return file_remove((char *)path); +} + +/* + * Renames a file in the file system + */ +int32 +OS_rename(const char *old_filename, const char *new_filename) +{ + int32 ret; + + if (!old_filename || !new_filename) return OS_FS_ERR_INVALID_POINTER; + ret = path_exists(old_filename); + if (ret != OS_FS_SUCCESS) return ret; + ret = path_isvalid(new_filename); + if (ret != OS_FS_SUCCESS) return ret; + // if new filename already exists + if (path_exists(new_filename) == OS_SUCCESS) return OS_FS_ERR_PATH_INVALID; + return file_rename((char *)old_filename, (char *)new_filename); +} + +/* + * copies a single file from src to dest + */ +int32 +OS_cp(const char *src, const char *dest) +{ + int32 ret; + char *src_path; + char *dest_path; + + if (!src || !dest) return OS_FS_ERR_INVALID_POINTER; + src_path = (char *)src; + dest_path = (char *)dest; + + if (strlen(src_path) > OS_MAX_PATH_LEN) return OS_FS_ERR_PATH_TOO_LONG; + if (strlen(dest_path) > OS_MAX_PATH_LEN) return OS_FS_ERR_PATH_TOO_LONG; + if (strlen(path_to_name(src_path)) > OS_MAX_FILE_NAME) return OS_FS_ERR_NAME_TOO_LONG; + if (strlen(path_to_name(dest_path)) > OS_MAX_FILE_NAME) return OS_FS_ERR_NAME_TOO_LONG; + + ret = path_exists(src_path); + if (ret != OS_FS_SUCCESS) return ret; + ret = path_isvalid(dest_path); + if (ret != OS_FS_SUCCESS) return ret; + + return file_cp(src_path, dest_path); +} + +/* + * moves a single file from src to dest + */ +int32 +OS_mv(const char *src, const char *dest) +{ + int32 ret; + char *src_path = (char *)src; + char *dest_path = (char *)dest; + + if (!src_path || !dest_path) return OS_FS_ERR_INVALID_POINTER; + if (strlen(src_path) > OS_MAX_PATH_LEN) return OS_FS_ERR_PATH_TOO_LONG; + if (strlen(dest_path) > OS_MAX_PATH_LEN) return OS_FS_ERR_PATH_TOO_LONG; + if (strlen(path_to_name(src_path)) > OS_MAX_FILE_NAME) return OS_FS_ERR_NAME_TOO_LONG; + if (strlen(path_to_name(dest_path)) > OS_MAX_FILE_NAME) return OS_FS_ERR_NAME_TOO_LONG; + + ret = path_exists(src); + if (ret != OS_FS_SUCCESS) return ret; + ret = path_isvalid(dest); + if (ret != OS_FS_SUCCESS) return ret; + + return file_mv(src_path, dest_path); +} + +/* + * Copies the info of an open file to the structure + */ +int32 +OS_FDGetInfo(int32 filedes, OS_FDTableEntry *fd_prop) +{ + if (!fd_prop) return OS_FS_ERR_INVALID_POINTER; + if (filedes <= 0 || filedes > MAX_NUM_FILES) return OS_FS_ERR_INVALID_FD; + + return file_FDGetInfo(filedes, fd_prop); +} + +/* +** Check to see if a file is open +*/ +int32 +OS_FileOpenCheck(char *Filename) +{ + struct fsobj *file; + int32 ret = path_exists(Filename); + + if (ret != OS_FS_SUCCESS) return OS_FS_ERR_INVALID_POINTER; + + file = file_find(Filename); + if (!file) return OS_INVALID_POINTER; + if (file->refcnt == 0) return OS_FS_ERROR; + return OS_FS_SUCCESS; +} + +/* +** Close all open files +*/ +int32 +OS_CloseAllFiles(void) +{ + uint32 i; + for (i = 1; i <= MAX_NUM_FILES; i++) { OS_close(i); } + return OS_FS_SUCCESS; +} + +/* +** Close a file by filename +*/ +int32 +OS_CloseFileByName(char *Filename) +{ + int32 ret = path_exists(Filename); + if (ret != OS_FS_SUCCESS) return ret; + return file_close_by_name(Filename); +} + +/****************************************************************************** +** Directory API +******************************************************************************/ + +/* + * Makes a new directory + * access is not used by cFE + */ +int32 +OS_mkdir(const char *path, uint32 access) +{ + int32 ret = path_isvalid(path); + if (ret != OS_FS_SUCCESS) return ret; + return file_mkdir((char *)path); +} + +/* + * Opens a directory for searching + */ +os_dirp_t +OS_opendir(const char *path) +{ + int32 FD; + if (path_exists(path) != OS_FS_SUCCESS) return NULL; + FD = dir_open((char *)path); + if (FD == 0) return NULL; + return (os_dirp_t)FD; +} + +/* + * Closes an open directory + */ +int32 +OS_closedir(os_dirp_t directory) +{ + if (!directory) return OS_FS_ERR_INVALID_POINTER; + return dir_close((int32)directory); +} + +/* + * Rewinds an open directory + */ +void +OS_rewinddir(os_dirp_t directory) +{ + dir_rewind((int32)directory); + return; +} + +/* + * Reads the next object in the directory + */ +os_dirent_t * +OS_readdir(os_dirp_t directory) +{ + if (!directory) return NULL; + return dir_read((int32)directory); +} + +/* + * Removes an empty directory from the file system. + */ +int32 +OS_rmdir(const char *path) +{ + int32 ret = path_exists(path); + if (ret != OS_FS_SUCCESS) return ret; + return file_rmdir((char *)path); +} + +/****************************************************************************** +** System Level API +******************************************************************************/ +/* + * Makes a file system + */ +int32 +OS_mkfs(char *address, char *devname, char *volname, uint32 blocksize, uint32 numblocks) +{ + if (address) return OS_FS_ERR_INVALID_POINTER; + if (!devname || !volname) return OS_FS_ERR_INVALID_POINTER; + if (strlen(devname) >= OS_FS_DEV_NAME_LEN || strlen(volname) >= OS_FS_VOL_NAME_LEN) + return OS_FS_ERR_PATH_TOO_LONG; + return fs_init(devname, volname, blocksize, numblocks); +} +/* + * Mounts a file system + */ +int32 +OS_mount(const char *devname, char *mountpoint) +{ + if (!devname || !mountpoint) return OS_FS_ERR_INVALID_POINTER; + return fs_mount((char *)devname, mountpoint); +} + +/* + * Initializes an existing filesystem + * address will be null if wants to initialize an empty fs, non-null to load an fs from memory + * we could easily load a tar from memory but if an application wants to load a filesystem it + * is safer to panic as we do not know what format the application is attempting to load + */ +int32 +OS_initfs(char *address, char *devname, char *volname, uint32 blocksize, uint32 numblocks) +{ + if (address) PANIC("No support for loading a filesystem from arbitrary memory"); + return OS_FS_SUCCESS; +} + +/* + * removes a file system + */ +int32 +OS_rmfs(char *devname) +{ + if (!devname) return OS_FS_ERR_INVALID_POINTER; + return fs_remove(devname); +} + +/* + * Unmounts a mounted file system + */ +int32 +OS_unmount(const char *mountpoint) +{ + int32 ret; + + if (!mountpoint) return OS_FS_ERR_INVALID_POINTER; + ret = path_exists(mountpoint); + if (ret != OS_FS_SUCCESS) return ret; + return fs_unmount((char *)mountpoint); +} + +/* + * Returns the number of free blocks in a file system + */ +int32 +OS_fsBlocksFree(const char *name) +{ + return OS_ERR_NOT_IMPLEMENTED; +} + +int32 +OS_fsBytesFree(const char *name, uint64 *bytes_free) +{ + return OS_ERR_NOT_IMPLEMENTED; +} + +/* + * Checks the health of a file system and repairs it if neccesary + */ +os_fshealth_t +OS_chkfs(const char *name, boolean repair) +{ + return OS_ERR_NOT_IMPLEMENTED; +} + +/* + * Returns in the parameter the physical drive underneith the mount point + */ +int32 +OS_FS_GetPhysDriveName(char *PhysDriveName, char *MountPoint) +{ + int32 ret; + + if (!PhysDriveName || !MountPoint) return OS_FS_ERR_INVALID_POINTER; + ret = path_exists(MountPoint); + if (ret != OS_FS_SUCCESS) return ret; + return fs_get_drive_name(PhysDriveName, MountPoint); +} + +/* + * This is currently not used by osal + * Translates a OSAL Virtual file system path to a host Local path + */ +int32 +OS_TranslatePath(const char *VirtualPath, char *LocalPath) +{ + return path_translate((char *)VirtualPath, LocalPath); +} + +/* +** Returns information about the file system in an os_fsinfo_t +*/ +int32 +OS_GetFsInfo(os_fsinfo_t *filesys_info) +{ + if (!filesys_info) return OS_FS_ERR_INVALID_POINTER; + return fs_get_info(filesys_info); +} + +/****************************************************************************** +** Shell API +******************************************************************************/ + +/* executes the shell command passed into is and writes the output of that + * command to the file specified by the given OSAPI file descriptor */ +int32 +OS_ShellOutputToFile(char *Cmd, int32 OS_fd) +{ + return OS_ERR_NOT_IMPLEMENTED; +} diff --git a/src/components/implementation/no_interface/cFE_booter/osfilesys.c b/src/components/implementation/no_interface/cFE_booter/osfilesys.c new file mode 100644 index 0000000000..74f2643272 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/osfilesys.c @@ -0,0 +1,991 @@ +#include "osfilesys.h" +#include "tar.h" + +struct fs filesystems[MAX_NUM_FS]; +struct fs * openfs = &filesystems[0]; +struct fsobj files[MAX_NUM_FILES]; +struct fd fd_tbl[OS_MAX_NUM_OPEN_FILES + 1]; + +/* + * Notes on this version: + * It provides all of the functionality required by the cFE and more. It does + * not fully satisfy all of the requirements for posix in general. It passes all + * of cFE's unit tests, and all of the testing and debugging I have thrown at it + * + * Beware when using struct dirent and struct stat. As a temporary measure, + * they are currently generated to comply with glibc rather than musl. + * + * Future plans: + * - Compile cFE with musl and fix stat and dirent structures + * - modularize into a bare bones filesystem library + * - Refactor rest of code into posix compatible filesystem built on bare bones fs + * + */ + +/****************************************************************************** +** fsobj Level Methods +******************************************************************************/ + +/* checks if a file descriptor is valid and in use */ +int32 +chk_fd(int32 FD) +{ + struct fd *filedes; + + if (FD > OS_MAX_NUM_OPEN_FILES) return OS_FS_ERR_INVALID_FD; + if (FD <= 0) return OS_FS_ERR_INVALID_FD; + + filedes = &fd_tbl[FD]; + if (!filedes->file) return OS_FS_ERR_INVALID_FD; + if (filedes->ino == 0 || filedes->file->ino == 0) return OS_FS_ERR_INVALID_FD; + assert(filedes->ino == filedes->file->ino); + return OS_FS_SUCCESS; +} + +/* finds the next free file */ +uint32 +file_get_new(struct fsobj **o) +{ + uint32 count = 0; + while (count < MAX_NUM_FILES && files[count].ino) { count++; } + if (count == MAX_NUM_FILES) return OS_FS_ERROR; + *o = &files[count]; + + /* ino needs to be unique and nonzero, so ino is defined as index+1 */ + **o = (struct fsobj){.ino = count + 1}; + return OS_FS_SUCCESS; +} + +uint32 +file_insert(struct fsobj *o, char *path) +{ + assert(o && path && openfs); + + /* paths should always begin with '/' but we do not need it here */ + if (path[0] != '/') return OS_FS_ERR_PATH_INVALID; + path++; + + if (!openfs->root) { + if (strcmp(o->name, path) != 0) return OS_FS_ERR_PATH_INVALID; + openfs->root = o; + return OS_FS_SUCCESS; + } + assert(openfs->root->ino); + struct fsobj *cur = openfs->root; + + /* token is the current directory in path */ + char path_temp[OS_MAX_PATH_LEN * 2]; + strcpy(path_temp, path); + const char delim[2] = "/"; + char * token = strtok(path_temp, delim); + + if (strcmp(token, cur->name) != 0) return OS_FS_ERR_PATH_INVALID; + + /* loop terminates when it finds a place to put o or determines path is invalid */ + while (1) { + if (token == NULL) { return OS_FS_ERR_PATH_INVALID; } + assert(cur->name); + + /* if there is no child, then insert as child */ + if (!cur->child) { + /* if the next part of the path is not o->name or there is a part after it, bad path */ + token = strtok(NULL, delim); + if (strcmp(token, o->name) != 0 || strtok(NULL, delim) != NULL) { + return OS_FS_ERR_PATH_INVALID; + } + + o->parent = cur; + cur->child = o; + o->next = NULL; + o->prev = NULL; + return OS_FS_SUCCESS; + } + cur = cur->child; + token = strtok(NULL, delim); + + /* precondition: cur is the first in a non-empty list of children + * postcondition: cur is an ancestor of o or o has been inserted in list + * while cur is not ancestor of o + */ + while (strcmp(token, cur->name) != 0) { + if (cur->next == NULL) { + /* if the next part of the path is o->name or there is a part after it, bad path */ + if (strcmp(token, o->name) != 0 || strtok(NULL, delim) != NULL) { + return OS_FS_ERR_PATH_INVALID; + } + /* insert o as the last child in a linked list of children */ + cur->next = o; + o->prev = cur; + o->parent = cur->parent; + o->next = NULL; + return OS_FS_SUCCESS; + } + cur = cur->next; + } + } + PANIC("Unreachable Statement"); + return 0; +} + +/* Internally, FDs are considered unused when ino == 0 */ +static int32 +fd_get(int32 ino) +{ + struct fd *filedes; + uint32 count = 1; + + while (count <= OS_MAX_NUM_OPEN_FILES + 1 && fd_tbl[count].ino != 0) { count++; } + if (count == OS_MAX_NUM_OPEN_FILES + 1) return OS_FS_ERROR; + + filedes = &fd_tbl[count]; + filedes->ino = ino; + filedes->access = NONE; + return count; +} + +int32 +file_open(char *path, enum fs_permissions permission) +{ + int32 FD; + struct fsobj *file; + struct fd * filedes; + + assert(openfs); + if (!openfs->root) return OS_FS_ERROR; + if (!path) return OS_FS_ERR_INVALID_POINTER; + + file = file_find(path); + if (!file) return OS_FS_ERR_PATH_INVALID; + if (file->type != FSOBJ_FILE) return OS_FS_ERROR; + + /* get a new fd */ + FD = fd_get(file->ino); + if (FD == OS_FS_ERROR) { return OS_FS_ERR_NO_FREE_FDS; } + + filedes = &fd_tbl[FD]; + + filedes->access = permission; + filedes->file = file; + filedes->position.file_pos.open_part = file->file_part; + filedes->position.file_pos.file_offset = 0; + filedes->position.file_pos.part_offset = 0; + file->refcnt++; + return FD; +} + +int32 +file_close(int32 FD) +{ + int32 ret = chk_fd(FD); + if (ret != OS_FS_SUCCESS) return OS_FS_ERROR; + + struct fd *filedes = &fd_tbl[FD]; + if (filedes->ino == 0) return OS_FS_ERROR; + + uint32 index = filedes->ino - 1; + assert(files[index].refcnt > 0); + files[index].refcnt--; + filedes->ino = 0; + return OS_FS_SUCCESS; +} + +int32 +file_close_by_name(char *path) +{ + int i; + struct fsobj *file = file_find(path); + + for (i = 0; i < OS_MAX_NUM_OPEN_FILES + 1; i++) { + if (fd_tbl[i].file == file) { + assert(fd_tbl[i].ino = file->ino); + file_close(i); + return OS_FS_SUCCESS; + } + } + return OS_FS_ERROR; +} + +/* converts from the cFE defined permission constants to internal permission type + * unknown permissions return NONE, cFE should treat none as an error + */ +enum fs_permissions +permission_cFE_to_cos(uint32 permission) +{ + switch (permission) { + case OS_READ_WRITE: + return READ & WRITE; + case OS_WRITE_ONLY: + return WRITE; + case OS_READ_ONLY: + return READ; + default: + PANIC("Invalid permission from cFE"); + } + PANIC("unreachable statement"); + return 0; +} + +uint32 +permission_cos_to_cFE(enum fs_permissions permission) +{ + switch (permission) { + case READ &WRITE: + return OS_READ_WRITE; + case WRITE: + return OS_WRITE_ONLY; + case READ: + return OS_READ_ONLY; + default: + PANIC("Invalid permission in existing file"); + } + PANIC("unreachable statement"); + return 0; +} + +int32 +path_exists(const char *path) +{ + int32 ret = path_isvalid(path); + if (ret != OS_FS_SUCCESS) return ret; + if (file_find((char *)path) == NULL) return OS_FS_ERROR; + return OS_FS_SUCCESS; +} + +int32 +path_isvalid(const char *path) +{ + if (path == NULL) return OS_FS_ERR_INVALID_POINTER; + if (strlen(path) > OS_MAX_PATH_LEN) return OS_FS_ERR_PATH_TOO_LONG; + if (strlen(path_to_name((char *)path)) > OS_MAX_FILE_NAME) return OS_FS_ERR_NAME_TOO_LONG; + if (path[0] != '/') return OS_FS_ERR_PATH_INVALID; + assert(openfs); + + if (openfs->root) { + assert(openfs->root->name); + if (memcmp(openfs->root->name, path + 1, strlen(openfs->root->name))) { return OS_FS_ERR_PATH_INVALID; } + } + return OS_FS_SUCCESS; +} + +int32 +path_translate(char *virt, char *local) +{ + int32 ret; + + if (!virt || !local) return OS_FS_ERR_INVALID_POINTER; + ret = path_isvalid(virt); + if (ret != OS_FS_SUCCESS) return ret; + if (!openfs->root) return OS_FS_ERR_PATH_INVALID; + ret = path_exists(virt); + if (ret != OS_FS_SUCCESS) return ret; + strcpy(local, virt); + return OS_FS_SUCCESS; +} + +/****************************************************************************** +** f_part Level Methods +******************************************************************************/ + +uint32 +part_get_new(struct f_part **part) +{ + *part = (void *)memmgr_heap_page_alloc(); + + assert(part != NULL); + (*part)->next = NULL; + (*part)->prev = NULL; + (*part)->file = NULL; + (*part)->data = (char *)*part + sizeof(struct f_part); + return OS_FS_SUCCESS; +} + +int32 +file_read(int32 FD, void *buffer, uint32 nbytes) +{ + if (!buffer) return OS_FS_ERR_INVALID_POINTER; + int32 ret = chk_fd(FD); + if (ret != OS_FS_SUCCESS) return ret; + + struct fd *filedes = &fd_tbl[FD]; + + struct fsobj *o = filedes->file; + assert(o->refcnt >= 1); + if (o->type != FSOBJ_FILE) return OS_FS_ERR_INVALID_FD; + struct file_position *position = &filedes->position.file_pos; + struct f_part * part = position->open_part; + + /* nbytes > number of bytes left in file, only number left are read */ + if (nbytes > o->size - position->file_offset) { nbytes = o->size - position->file_offset; } + + if (nbytes == OS_FS_SUCCESS) return 0; + uint32 bytes_to_read = nbytes; + + if (o->memtype == DYNAMIC) { + while (1) { + /* read_size is the length of a continuous segment to be read from */ + uint32 read_size = F_PART_DATA_SIZE - position->file_offset; + part = position->open_part; + assert(part); + + if (bytes_to_read > read_size) { + memcpy(buffer, &part->data[position->part_offset], read_size); + + buffer += read_size; + bytes_to_read -= read_size; + position->file_offset += read_size; + + if (!part->next) { + position->part_offset = F_PART_DATA_SIZE; + return nbytes - bytes_to_read; + } + position->open_part = part->next; + position->part_offset = 0; + + } else if (bytes_to_read == read_size) { + memcpy(buffer, &part->data[position->part_offset], read_size); + position->file_offset += read_size; + if (!part->next) { + position->part_offset = F_PART_DATA_SIZE; + return nbytes; + } + position->open_part = part->next; + position->part_offset = 0; + return nbytes; + + /* bytes_to_read < the continuous space left on f_part */ + } else { + memcpy(buffer, position->open_part->data + position->part_offset, bytes_to_read); + position->part_offset += bytes_to_read; + position->file_offset += bytes_to_read; + return nbytes; + } + } + } else if (o->memtype == STATIC) { + memcpy(buffer, &part->data[position->file_offset], bytes_to_read); + position->part_offset += bytes_to_read; + position->file_offset += bytes_to_read; + return nbytes; + } else { + PANIC("Memtype is neither static nor dynamic"); + } + + PANIC("Unreachable Statement"); + return 0; +} + +int32 +file_write(int32 FD, void *buffer, uint32 nbytes) +{ + int32 ret; + uint32 bytes_to_write; + uint32 bytes_remaining; + + if (!buffer) return OS_FS_ERR_INVALID_POINTER; + ret = chk_fd(FD); + if (ret != OS_FS_SUCCESS) return ret; + + struct fd * filedes = &fd_tbl[FD]; + struct fsobj * o = filedes->file; + struct file_position *position = &filedes->position.file_pos; + + if (o->refcnt < 1) return OS_FS_ERROR; + if (o->memtype == STATIC) return OS_FS_ERROR; + if (o->type == FSOBJ_DIR) return OS_FS_ERROR; + if (nbytes == 0) return 0; + + bytes_to_write = nbytes; + bytes_remaining = F_PART_DATA_SIZE - position->part_offset; + + /* while there are enough bytes to be written to fill a f_part */ + while (bytes_to_write > bytes_remaining) { + memcpy(position->open_part->data + position->part_offset, buffer, bytes_remaining); + position->file_offset += bytes_remaining; + buffer += bytes_remaining; + bytes_to_write -= bytes_remaining; + position->part_offset = 0; + if (position->open_part->next == NULL) { + struct f_part *part; + part_get_new(&part); + part->file = o; + part->next = NULL; + part->prev = position->open_part; + position->open_part->next = part; + } + + position->open_part = position->open_part->next; + bytes_remaining = F_PART_DATA_SIZE - position->part_offset; + } + /* bytes_to_write < bytes_remaining */ + memcpy(position->open_part->data, buffer, bytes_to_write); + position->part_offset += bytes_to_write; + position->file_offset += bytes_to_write; + if (o->size < position->file_offset) { o->size = position->file_offset; } + return nbytes; +} + +struct fsobj * +file_find(char *path) +{ + char path_temp[OS_MAX_PATH_LEN * 2]; + const char delim[2] = "/"; + char * token; + struct fsobj *cur; + + assert(path); + /* paths should always begin with '/' dir names do not */ + if (path[0] != '/') return NULL; + path++; + + /* token is the current directory in path */ + strcpy(path_temp, path); + token = strtok(path_temp, delim); + + if (!openfs || !openfs->root) return NULL; + cur = openfs->root; + assert(cur && cur->name); + if (strcmp(token, cur->name) != 0) return NULL; + + while (1) { + /* iterate through linked list of children until ancestor is found */ + while (strcmp(token, cur->name) != 0) { + if (!cur->next) return NULL; + cur = cur->next; + } + token = strtok(NULL, delim); + if (token == NULL) return cur; + if (!cur->child) return NULL; + cur = cur->child; + } + PANIC("Unreachable Statement"); + return NULL; +} + +int32 +file_create(char *path, enum fs_permissions permission) +{ + struct fsobj *o; + + assert(path); + + if (file_get_new(&o) != OS_FS_SUCCESS) return OS_FS_ERROR; + o->name = path_to_name(path); + o->type = FSOBJ_FILE; + o->size = 0; + o->permission = permission; + o->memtype = DYNAMIC; + + struct f_part *part; + part_get_new(&part); + + o->file_part = part; + part->file = o; + part->data = (char *)part + sizeof(struct f_part); + if (file_insert(o, path) != OS_FS_SUCCESS) { + o->ino = 0; + return OS_FS_ERR_PATH_INVALID; + } + return file_open(path, permission); +} + +int32 +file_remove(char *path) +{ + struct fsobj *file = file_find(path); + + if (!file) return OS_FS_ERR_PATH_INVALID; + file_rm(file); + return OS_FS_SUCCESS; +} + +int32 +file_rename(char *old_filename, char *new_filename) +{ + struct fsobj *file = file_find(old_filename); + + if (!file) return OS_FS_ERR_PATH_INVALID; + file->name = path_to_name(new_filename); + return OS_FS_SUCCESS; +} + +/* This is part of but not a full posix implementation, + * stat has a lot of fields not applicable to us + */ +int32 +file_stat(char *path, os_fstat_t *filestats) +{ + struct fsobj *file = file_find(path); + + if (!file) return OS_FS_ERROR; + *filestats = + (os_fstat_t){.st_dev = 0, .st_ino = file->ino, .st_size = file->size, .st_blksize = F_PART_DATA_SIZE}; + + if (file->type == FSOBJ_FILE) { filestats->st_mode = S_IFREG; } + if (file->type == FSOBJ_DIR) { filestats->st_mode = S_IFDIR; } + + return OS_FS_SUCCESS; +} + +int32 +file_lseek(int32 FD, int32 offset, uint32 whence) +{ + uint32 target_offset = 0; + int32 ret = chk_fd(FD); + + if (ret != OS_FS_SUCCESS) return ret; + + struct fd * filedes = &fd_tbl[FD]; + struct fsobj * o = filedes->file; + struct file_position *position = &filedes->position.file_pos; + + /* wasnt sure if it should be legal to pass negative offset, went with yes */ + if (whence == SEEK_SET) { + if (offset < 0) return OS_FS_ERROR; + target_offset = offset; + } else if (whence == SEEK_CUR) { + if (offset + (int32)position->file_offset < 0) return OS_FS_ERROR; + target_offset = offset + position->file_offset; + } else if (whence == SEEK_END) { + if (offset + (int32)position->file_offset < 0) return OS_FS_ERROR; + target_offset = offset + o->size; + } else { + return OS_FS_ERROR; + } + + /* you cannot write past the end of a static file */ + if (target_offset > o->size && o->memtype == STATIC) { return OS_FS_ERROR; } + + position->open_part = o->file_part; + position->file_offset = 0; + + while (target_offset - position->file_offset > F_PART_DATA_SIZE) { + /* seeking past the end of a file writes zeros until that position */ + if (position->open_part->next == NULL) { + struct f_part *part; + part_get_new(&part); + part->file = o; + part->next = NULL; + part->prev = position->open_part; + position->open_part->next = part; + } + position->open_part = position->open_part->next; + position->file_offset += F_PART_DATA_SIZE; + } + position->file_offset += target_offset % F_PART_DATA_SIZE; + position->part_offset = target_offset % F_PART_DATA_SIZE; + + if (position->file_offset > o->size) { o->size = position->file_offset; } + return target_offset; +} + +int32 +file_cp(char *src, char *dest) +{ + int32 fd_src; + int32 fd_dest; + int32 to_copy; + int32 read_size, write_size; + static char copy_buffer[F_PART_DATA_SIZE]; + + fd_src = file_open(src, READ); + if (chk_fd(fd_src) != OS_FS_SUCCESS) return fd_src; + + /* if the dest already exists, overwrite it */ + fd_dest = file_open(dest, WRITE); + if (chk_fd(fd_dest) == OS_FS_SUCCESS) { + /* writing size to zero effectivly deletes all the old data */ + fd_tbl[fd_dest].file->size = 0; + } else { + fd_dest = file_create(dest, fd_tbl[fd_src].file->permission); + } + if (chk_fd(fd_dest) != OS_FS_SUCCESS) return fd_dest; + + to_copy = fd_tbl[fd_src].file->size; + read_size = 0; + write_size = 0; + + /* TODO: copy buffer is aggressively not thread safe, take a lock */ + while (to_copy > 0) { + if (to_copy > (int32)F_PART_DATA_SIZE) { + read_size = F_PART_DATA_SIZE; + } else { + read_size = to_copy; + } + read_size = file_read(fd_src, copy_buffer, read_size); + write_size = file_write(fd_dest, copy_buffer, read_size); + if (read_size == 0 || write_size != read_size) return OS_FS_ERROR; + to_copy -= write_size; + } + + file_close(fd_src); + file_close(fd_dest); + + return OS_FS_SUCCESS; +} + +int32 +file_mv(char *src, char *dest) +{ + struct fsobj *file = file_find(src); + + if (!file) return OS_FS_ERROR; + + if (file->next) { file->next->prev = file->prev; } + if (file->prev) { file->prev->next = file->next; } + if (file->parent->child == file) { file->parent->child = file->next; } + + file->name = path_to_name(dest); + if (file_insert(file, dest) != OS_FS_SUCCESS) return OS_FS_ERROR; + return OS_FS_SUCCESS; +} + +/* + * currently returns name and in path field + * perhaps it would be a good idea to track path in fsobj + * but it looks like cFE uses this only to check is fd is valid + */ +int32 +file_FDGetInfo(int32 FD, OS_FDTableEntry *fd_prop) +{ + struct fd *filedes; + int32 ret = chk_fd(FD); + + if (ret != OS_FS_SUCCESS) return OS_FS_ERR_INVALID_FD; + + filedes = &fd_tbl[FD]; + if (filedes->ino == 0) return OS_FS_ERR_INVALID_FD; + + fd_prop->OSfd = FD; + memcpy(&fd_prop->Path, filedes->file->name, strlen(filedes->file->name)); + fd_prop->User = 0; + fd_prop->IsValid = 1; + return OS_FS_SUCCESS; +} + + +/****************************************************************************** +** Dirent Level Methods +******************************************************************************/ + +int32 +dir_open(char *path) +{ + int32 FD; + struct fsobj * file; + struct fd * filedes; + struct dir_position *position; + + file = file_find(path); + if (!file) return 0; + if (file->ino == 0) return 0; + if (file->type != FSOBJ_DIR) return 0; + + FD = fd_get(file->ino); + if (FD > OS_MAX_NUM_OPEN_FILES + 1 || FD <= 0) return 0; + file->refcnt++; + + filedes = &fd_tbl[FD]; + filedes->access = READ; + filedes->file = file; + + position = &filedes->position.dir_pos; + position->open_dir = file; + position->cur = file; + position->status = NORMAL; + + return FD; +} + +uint32 +dir_close(int32 FD) +{ + struct fd *filedes; + + if (FD > OS_MAX_NUM_OPEN_FILES + 1 || FD <= 0) return OS_FS_ERROR; + filedes = &fd_tbl[FD]; + + filedes->ino = 0; + return OS_FS_SUCCESS; +} + +void +dir_rewind(int32 FD) +{ + struct fd *filedes; + + if (FD >= OS_MAX_NUM_OPEN_FILES || FD <= 0) return; + filedes = &fd_tbl[FD]; + + if (filedes->ino == 0) return; + if (filedes->file->type != FSOBJ_DIR) return; + + /* cur == open_dir indicates that stream is in initial position, prior to first read */ + filedes->position.dir_pos.cur = filedes->position.dir_pos.open_dir; + filedes->position.dir_pos.status = NORMAL; +} + +os_dirent_t * +dir_read(int32 FD) +{ + struct fd * filedes; + os_dirent_t *dir; + + if (FD > OS_MAX_NUM_OPEN_FILES + 1 || FD <= 0) return NULL; + filedes = &fd_tbl[FD]; + + if (filedes->ino == 0) return NULL; + if (filedes->file->type != FSOBJ_DIR) return NULL; + + dir = &filedes->position.dir_pos.dirent; + + switch (filedes->position.dir_pos.status) { + case NORMAL: + break; + + case END_OF_STREAM: + return NULL; + + case PARENT_DIR_LINK: + filedes->position.dir_pos.cur = NULL; + filedes->position.dir_pos.status = END_OF_STREAM; + return NULL; + + case CUR_DIR_LINK: + strcpy(dir->d_name, ".."); + dir->d_ino = 0; + filedes->position.dir_pos.status = PARENT_DIR_LINK; + return dir; + } + + if (filedes->position.dir_pos.cur == filedes->position.dir_pos.open_dir) { + filedes->position.dir_pos.cur = filedes->position.dir_pos.open_dir->child; + } else { + filedes->position.dir_pos.cur = filedes->position.dir_pos.cur->next; + } + + if (!filedes->position.dir_pos.cur) { + filedes->position.dir_pos.status = CUR_DIR_LINK; + strcpy(dir->d_name, "."); + dir->d_ino = 0; + } else { + strcpy(dir->d_name, filedes->position.dir_pos.cur->name); + dir->d_ino = filedes->position.dir_pos.cur->ino; + } + + return (os_dirent_t *)dir; +} + +int32 +file_mkdir(char *path) +{ + struct fsobj *o; + + assert(path); + + if (file_get_new(&o)) return OS_FS_ERR_DRIVE_NOT_CREATED; + o->name = path_to_name(path); + o->type = FSOBJ_DIR; + o->next = NULL; + o->prev = NULL; + o->parent = NULL; + o->child = NULL; + o->size = 0; + if (file_insert(o, path) != OS_FS_SUCCESS) return OS_FS_ERR_PATH_INVALID; + return OS_FS_SUCCESS; +} + +int32 +file_rmdir(char *path) +{ + struct fsobj *root; + struct fsobj *cur; + + assert(path); + + root = file_find(path); + cur = root; + if (!root) return OS_FS_ERROR; + + while (root->child) { + /* if cur is the last leaf in a list */ + if (!cur->next && !cur->child) { + if (cur->prev != NULL) { + assert(cur->prev->next == cur); + cur = cur->prev; + file_rm(cur->next); + } else { + assert(cur->parent->child == cur); + cur = cur->parent; + file_rm(cur->child); + } + } else if (cur->child != NULL) { + cur = cur->child; + } else { + cur = cur->next; + } + } + file_rm(root); + return OS_FS_SUCCESS; +} + +int32 +file_rm(struct fsobj *o) +{ + /* TODO, pass an error back out of library if someone implicitly tries to close open file */ + /* assert(o->refcnt == 0); */ + assert(o && o->child == NULL); + /* if o is first in list of children, update parent link to it */ + if (o->prev == NULL && o->parent) { + assert(o->parent->child == o); + /* if next = null this still works */ + o->parent->child = o->next; + } + + /* update link from prev still work if next or prev = null */ + if (o->prev) { + assert(o->prev->next == o); + o->prev->next = o->next; + } + /* update link from next */ + if (o->next) { + assert(o->next->prev == o); + o->next->prev = o->prev; + } + /* there should now be no links within the fs to o + * we do not do deallocate file data but we do reuse fsobj + */ + *o = (struct fsobj){.name = NULL}; + + return OS_FS_SUCCESS; +} + +/* close all of the open FDs associated with file */ +int32 +file_close_by_ino(int32 ino) +{ + int i; + for (i = 1; i <= OS_MAX_NUM_OPEN_FILES; i++) { + if (fd_tbl[i].ino == ino) { file_close(i); } + } + return OS_FS_SUCCESS; +} + +/****************************************************************************** +** fs Level Methods +******************************************************************************/ + +uint32 +fs_mount(char *devname, char *mountpoint) +{ + uint32 i; + + assert(devname); + + for (i = 0; i < MAX_NUM_FS && filesystems[i].devname != NULL; i++) { + if (!strcmp(filesystems[i].devname, devname)) { + /* This is a bad hack that I have not found a solution to + * basically mount should fail if already mounted + * but to load tar I need to pre-mount the first filesystem + */ + if (strcmp(mountpoint, "/ram") && filesystems[i].root) return OS_FS_ERROR; + struct fsobj *o; + if (file_get_new(&o)) return OS_FS_ERROR; + filesystems[i].mountpoint = mountpoint; + openfs = &filesystems[i]; + if (!filesystems[i].root) { file_mkdir(mountpoint); } + assert(strcmp(openfs->mountpoint, mountpoint) == 0); + return OS_FS_SUCCESS; + } + } + return OS_FS_ERROR; +} + +uint32 +fs_unmount(char *mountpoint) +{ + uint32 i; + + assert(mountpoint); + for (i = 0; i < MAX_NUM_FS && filesystems[i].mountpoint != NULL; i++) { + if (mountpoint != NULL && !strcmp(filesystems[i].mountpoint, mountpoint)) { + filesystems[i].mountpoint = NULL; + return OS_FS_SUCCESS; + } + } + return OS_FS_ERROR; +} + +uint32 +fs_init(char *devname, char *volname, uint32 blocksize, uint32 numblocks) +{ + uint32 count = 0, ret = 0; + + if (!devname) return OS_FS_ERR_INVALID_POINTER; + if (blocksize == 0 || numblocks == 0) return OS_FS_ERROR; + if (strlen(devname) >= OS_FS_DEV_NAME_LEN || strlen(volname) >= OS_FS_VOL_NAME_LEN) return OS_FS_ERROR; + + while (count < MAX_NUM_FS && filesystems[count].devname) { count++; } + if (count == MAX_NUM_FS) return OS_FS_ERR_DEVICE_NOT_FREE; + + filesystems[count] = (struct fs){.devname = devname, + .volname = volname, + .mountpoint = "", + .blocksize = blocksize, + .numblocks = numblocks, + .root = NULL}; + + openfs = &filesystems[count]; + return OS_FS_SUCCESS; +} + +int32 +fs_remove(char *devname) +{ + uint32 i; + + if (!devname) return OS_FS_ERR_INVALID_POINTER; + + for (i = 0; i < MAX_NUM_FS && filesystems[i].devname != NULL; i++) { + if (devname && filesystems[i].devname && !strcmp(filesystems[i].devname, devname)) { + filesystems[i].devname = NULL; + filesystems[i].volname = NULL; + filesystems[i].mountpoint = NULL; + filesystems[i].blocksize = 0; + filesystems[i].numblocks = 0; + filesystems[i].root = NULL; + return OS_FS_SUCCESS; + } + } + return OS_FS_ERROR; +} + +int32 +fs_get_drive_name(char *PhysDriveName, char *MountPoint) +{ + uint32 i; + for (i = 0; i < MAX_NUM_FS && filesystems[i].devname != NULL; i++) { + if (filesystems[i].mountpoint && !strcmp(filesystems[i].mountpoint, MountPoint)) { + char *new_name = "Ram FS\n"; + memcpy(PhysDriveName, new_name, strlen(new_name)); + return OS_FS_SUCCESS; + } + } + return OS_FS_ERROR; +} + +int32 +fs_get_info(os_fsinfo_t *filesys_info) +{ + uint32 i, count = 0; + + filesys_info->MaxFds = MAX_NUM_FILES; + for (i = 0; i < MAX_NUM_FILES; i++) { + if (files[i].ino == 0) count++; + } + filesys_info->FreeFds = count; + filesys_info->MaxVolumes = MAX_NUM_FS; + for (i = 0, count = 0; i < MAX_NUM_FS; i++) { + if (!filesystems[i].devname) count++; + } + filesys_info->FreeVolumes = count; + return OS_FS_SUCCESS; +} diff --git a/src/components/implementation/no_interface/cFE_booter/osfilesys.h b/src/components/implementation/no_interface/cFE_booter/osfilesys.h new file mode 100644 index 0000000000..10bd71286e --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/osfilesys.h @@ -0,0 +1,231 @@ +#include +#include + +#include +#include +#include + +#include + +#include "gen/common_types.h" +#include "gen/osapi.h" +#include "gen/osapi-os-filesys.h" + +#include "cFE_util.h" + +/* Not to be confused with similar OSAL constants. + * These are only to define size of statically allocated data + */ +#define MAX_NUM_FS NUM_TABLE_ENTRIES +#define MAX_NUM_FILES 100 +#define MAX_NUM_DIRENT 10 + +/* a page is 4096, size of f_part is 5 values * 4 bytes */ +#define F_PART_DATA_SIZE (4096 - sizeof(struct f_part)) + +enum fsobj_type +{ + FSOBJ_FILE, + FSOBJ_DIR, +}; + +enum fs_permissions +{ + NONE = 0, + READ = 0x001, + WRITE = 0x010, + EXECUTE = 0x100, + ALL = READ | WRITE | EXECUTE, +}; + +struct file_position { + struct f_part *open_part; // part of file being read/written to + uint32 part_offset; // offset into part's data + uint32 file_offset; // position within file as a whole +}; + +enum fpart_alloc_type +{ + STATIC, + DYNAMIC, +}; + +/* + * The structure of the filesystem is stored in the fsobj struct + * each non-leaf dir points to its first child, which then has a pointer + * to the next, etc. Each file has a linked list of f_parts to store blocks of data + */ + +struct fsobj { + char * name; + int32 ino; // 0 for free file + enum fsobj_type type; /* dir vs file, determines the type of FD position */ + size_t size; + uint32 refcnt; // number of filedes which have it opened + enum fs_permissions permission; // most permissive possible status it may be opened with + enum fpart_alloc_type memtype; + struct f_part * file_part; + struct fsobj * next, *prev; + struct fsobj * child, *parent; // child != NULL iff type = dir +}; + +struct f_part { + struct fsobj * file; + struct f_part *next, *prev; + char * data; +}; + +/* + * The state of a directory stream is either iterating through list of files, + * at one of two special paths, or at the end of the stream. The two special + * paths are '.' and '..' and the occur at the end of the list of files + */ +enum dir_stream_status +{ + NORMAL, + CUR_DIR_LINK, + PARENT_DIR_LINK, + END_OF_STREAM, +}; + +// offset into linked list of children +struct dir_position { + struct fsobj * open_dir; /* Stream is children of open_dir */ + struct fsobj * cur; /* refers to current (last returned) file in dir stream */ + enum dir_stream_status status; /* indicates if special file or end of stream */ + os_dirent_t dirent; /* I really don't like storing this here. */ +}; + +/* + * The type being used must be consistent with fsobj->type + */ +union fd_position { + struct dir_position dir_pos; + struct file_position file_pos; +}; + +// Currently this filedes is used only for dir streams, and not real filedes +// TODO: Switch non-dir to table based filedes +struct fd { + int32 ino; + enum fs_permissions access; /* must be < or == permissive as file->permission */ + union fd_position position; /* the type of position is determined by file->type */ + struct fsobj * file; +}; + +struct fs { + char * devname; + char * volname; + char * mountpoint; + uint32 blocksize; + uint32 numblocks; + struct fsobj *root; +}; + +static char * +path_to_name(char *path) +{ + uint32 path_len, offset; + + assert(path); + path_len = strlen(path); + assert(path_len > 1); + + // remove one or more '/' at the end of path + while (path[strlen(path) - 1] == '/') { path[strlen(path) - 1] = 0; } + + // iterate from right to left through the path until you find a '/' + // everything you have iterated through is the name of the file + for (offset = path_len - 2; path[offset] != '/' && offset > 0; offset--) { + // do nothing + } + char *name = path + offset + 1; + + assert(0 < strlen(name)); + return name; +} + +/****************************************************************************** +** fsobj Level Methods +******************************************************************************/ +int32 file_rm(struct fsobj *o); + +int32 file_close_by_ino(int32 ino); + +int32 file_close_by_name(char *path); + +uint32 part_get_new(struct f_part **part); + +uint32 file_get_new(struct fsobj **o); + +uint32 file_insert(struct fsobj *o, char *path); + +int32 file_open(char *path, enum fs_permissions permission); + +int32 file_close(int32 filedes); + +int32 file_read(int32 FD, void *buffer, uint32 nbytes); + +int32 file_write(int32 FD, void *buffer, uint32 nbytes); + +struct fsobj *file_find(char *path); + +int32 file_create(char *path, enum fs_permissions permission); + +int32 file_remove(char *path); + +int32 file_rename(char *old_filename, char *new_filename); + +int32 file_cp(char *src, char *dest); + +int32 file_mv(char *src, char *dest); + +int32 chk_fd(int32 FD); + +int32 file_FDGetInfo(int32 FD, OS_FDTableEntry *fd_prop); + +int32 file_stat(char *path, os_fstat_t *filestats); + +int32 file_lseek(int32 FD, int32 offset, uint32 whence); + +enum fs_permissions permission_cFE_to_COS(uint32 permission); + +uint32 permission_COS_to_cFE(enum fs_permissions permission); + +/****************************************************************************** +** dirent Level Methods +******************************************************************************/ +// int32 newfd_get(int32 ino); + +int32 dir_open(char *path); + +uint32 dir_close(int32 FD); + +void dir_rewind(int32 FD); + +os_dirent_t *dir_read(int32 FD); + +int32 file_mkdir(char *path); + +int32 file_rmdir(char *path); + +/****************************************************************************** +** fs Level Methods +******************************************************************************/ +int32 path_isvalid(const char *path); + +int32 path_exists(const char *path); + +int32 path_translate(char *virt, char *local); + +uint32 fs_mount(char *devname, char *mountpoint); + +uint32 fs_unmount(char *mountpoint); + +uint32 fs_init(char *defilvname, char *volname, uint32 blocksize, uint32 numblocks); + +int32 fs_remove(char *devname); + +int32 fs_get_drive_name(char *PhysDriveName, char *MountPoint); + +int32 fs_get_info(os_fsinfo_t *finesys_info); diff --git a/src/components/implementation/no_interface/cFE_booter/osloader.c b/src/components/implementation/no_interface/cFE_booter/osloader.c new file mode 100644 index 0000000000..25498bbf84 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/osloader.c @@ -0,0 +1,159 @@ +#include + +#include +#include +#include +#include +#include + +#include "gen/osapi.h" +#include "gen/common_types.h" + +#include "cFE_util.h" +#include "ostask.h" + +thdid_t id_overrides[SL_MAX_NUM_THDS] = {0}; + +int32 +OS_ModuleTableInit(void) +{ + return OS_SUCCESS; +} + +int32 +OS_ModuleLoad(uint32 *module_id, const char *module_name, const char *filename) +{ + return OS_SUCCESS; +} + +int32 +OS_ModuleUnload(uint32 module_id) +{ + return OS_SUCCESS; +} + +int32 +get_this_threads_priority() +{ + OS_task_prop_t prop; + int32 result = OS_TaskGetInfo(sl_thdid(), &prop); + + assert(result == OS_SUCCESS); + return prop.priority; +} + +void +launch_other_component(int child_id, int is_library) +{ + struct sl_thd * t; + struct cos_defcompinfo child_dci; + + cos_defcompinfo_childid_init(&child_dci, child_id); + t = sl_thd_initaep_alloc(&child_dci, NULL, 0, 0, 0, 0, 0); + + /* We need to override the delegate thread id, so the cFE think it's this thread + * Otherwise cFE application id detection is broken + */ + id_overrides[sl_thd_thdid(t)] = sl_thdid(); + + if (is_library) { + sl_thd_param_set(t, sched_param_pack(SCHEDP_PRIO, 1)); + sl_thd_yield(sl_thd_thdid(t)); + } else { + sl_thd_param_set(t, sched_param_pack(SCHEDP_PRIO, get_this_threads_priority())); + OS_TaskExit(); + } +} + +// Component proxy hack +// To add new component: +// 1) Do all the cFE stuff +// 2) Create a component from the app +// 3) Add an init routine in the component +// 4) Add a proxy here (sensitive to runscript changes) + +void +ds_proxy() +{ + launch_other_component(1, 0); +} + +void +fm_proxy() +{ + launch_other_component(3, 0); +} + +void +hs_proxy() +{ + launch_other_component(6, 0); +} + +void +mm_proxy() +{ + launch_other_component(7, 0); +} + +void +sc_proxy() +{ + launch_other_component(5, 0); +} + +void +shc_lab_proxy() +{ + launch_other_component(8, 0); +} + +int32 +cfs_lib_proxy() +{ + /* This is a total fake! CFS Lib doesn't do useful initialization... */ + OS_printf("CFS Lib Initialized. Version [FAKE INITIALIZTION]"); + + return OS_SUCCESS; +} + +struct symbol_proxy { + char *symbol_name; + void *proxy; +}; + +#define NUM_PROXIES 7 +struct symbol_proxy proxies[NUM_PROXIES] = {{"DS_AppMain", ds_proxy}, + {"FM_AppMain", fm_proxy}, + {"HS_AppMain", hs_proxy}, + {"MM_AppMain", mm_proxy}, + {"SC_AppMain", sc_proxy}, + {"SCH_Lab_AppMain", shc_lab_proxy}, + {"CFS_LibInit", cfs_lib_proxy}}; + +int32 +OS_SymbolLookup(cpuaddr *symbol_address, const char *symbol_name) +{ + int i; + for (i = 0; i < NUM_PROXIES; i++) { + if (!strcmp(symbol_name, proxies[i].symbol_name)) { + *symbol_address = (cpuaddr)proxies[i].proxy; + return OS_SUCCESS; + } + } + return OS_ERROR; +} + +int32 +OS_ModuleInfo(uint32 module_id, OS_module_prop_t *module_info) +{ + return OS_ERR_NOT_IMPLEMENTED; +} + +int32 +OS_SymbolTableDump(const char *filename, uint32 size_limit) +{ + /* Not needed. */ + assert(0); + return OS_ERR_NOT_IMPLEMENTED; +} diff --git a/src/components/implementation/no_interface/cFE_booter/osnetwork.c b/src/components/implementation/no_interface/cFE_booter/osnetwork.c new file mode 100644 index 0000000000..010eedb778 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/osnetwork.c @@ -0,0 +1,123 @@ +#include "cFE_util.h" + +#include "gen/osapi.h" +#include "gen/common_types.h" + +/* + * Networking API + */ +int32 +OS_SocketOpen(uint32 *sock_id, OS_SocketDomain_t Domain, OS_SocketType_t Type) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketClose(uint32 sock_id) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketBind(uint32 sock_id, const OS_SockAddr_t *Addr) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketConnect(uint32 sock_id, const OS_SockAddr_t *Addr, int32 timeout) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketAccept(uint32 sock_id, uint32 *connsock_id, OS_SockAddr_t *Addr, int32 timeout) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketRecvFrom(uint32 sock_id, void *buffer, uint32 buflen, OS_SockAddr_t *RemoteAddr, int32 timeout) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketSendTo(uint32 sock_id, const void *buffer, uint32 buflen, const OS_SockAddr_t *RemoteAddr) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketGetIdByName(uint32 *sock_id, const char *sock_name) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketGetInfo(uint32 sock_id, OS_socket_prop_t *sock_prop) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketAddrInit(OS_SockAddr_t *Addr, OS_SocketDomain_t Domain) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketAddrToString(char *buffer, uint32 buflen, const OS_SockAddr_t *Addr) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketAddrFromString(OS_SockAddr_t *Addr, const char *string) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketAddrGetPort(uint16 *PortNum, const OS_SockAddr_t *Addr) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_SocketAddrSetPort(OS_SockAddr_t *Addr, uint16 PortNum) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +/* + * OS_NetworkGetID is currently [[deprecated]] as its behavior is + * unknown and not consistent across operating systems. + */ +int32 +OS_NetworkGetID(void) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_NetworkGetHostName(char *host_name, uint32 name_len) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} diff --git a/src/components/implementation/no_interface/cFE_booter/osqueue.c b/src/components/implementation/no_interface/cFE_booter/osqueue.c new file mode 100644 index 0000000000..6acdece0cf --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/osqueue.c @@ -0,0 +1,229 @@ +#include "cFE_util.h" + +#include "gen/common_types.h" +#include "gen/osapi.h" + +#include + +#include + +#include + +#define MAX_QUEUE_DATA_SIZE (1024 * 1024) + +struct sl_lock queue_lock = SL_LOCK_STATIC_INIT(); + +/* The main queue data structure. */ +struct queue { + int32 used; + + /* The number of elements allowed in the queue */ + uint32 depth; + + /* The size, in bytes, of each element in the queue */ + uint32 data_size; + + char name[OS_MAX_API_NAME]; + + uint32 head; + uint32 tail; +}; + +struct queue queues[OS_MAX_QUEUES]; + +char queue_data[OS_MAX_QUEUES][MAX_QUEUE_DATA_SIZE]; + +int32 +OS_QueueCreate(uint32 *queue_id, const char *queue_name, uint32 queue_depth, uint32 data_size, uint32 flags) +{ + int32 i; + uint32 qid; + + if (queue_id == NULL || queue_name == NULL) { return OS_INVALID_POINTER; } + + if (strlen(queue_name) >= OS_MAX_API_NAME) { return OS_ERR_NAME_TOO_LONG; } + + /* Check to see if the name is already taken */ + for (i = 0; i < OS_MAX_QUEUES; i++) { + if ((queues[i].used == TRUE) && strcmp((char *)queue_name, queues[i].name) == 0) { + return OS_ERR_NAME_TAKEN; + } + } + + /* Find a free queue ID */ + for (qid = 0; qid < OS_MAX_QUEUES; qid++) { + if (queues[qid].used == FALSE) { break; } + } + + /* Fail if there are too many queues */ + if (qid >= OS_MAX_QUEUES || queues[qid].used == TRUE) { return OS_ERR_NO_FREE_IDS; } + + /* OS_ERROR may also be returned in the event that an OS call fails, but none are used here */ + + *queue_id = qid; + queues[*queue_id].used = TRUE; + queues[*queue_id].depth = queue_depth; + queues[*queue_id].data_size = data_size; + strcpy(queues[*queue_id].name, queue_name); + + return OS_SUCCESS; +} + +int32 +OS_QueueDelete(uint32 queue_id) +{ + if (queue_id > OS_MAX_QUEUES) { return OS_ERR_INVALID_ID; } + if (queues[queue_id].used == FALSE) { return OS_ERR_INVALID_ID; } + + /* Reset all values in the queue */ + queues[queue_id].used = FALSE; + queues[queue_id].depth = 0; + queues[queue_id].data_size = 0; + strcpy(queues[queue_id].name, ""); + queues[queue_id].head = 0; + queues[queue_id].tail = 0; + + return OS_SUCCESS; +} + +int32 +OS_QueuePoll(uint32 queue_id, void *data, uint32 size, uint32 *size_copied) +{ + uint32 i; + + /* Check if there are messages to be received */ + if (queues[queue_id].head == queues[queue_id].tail) { return OS_QUEUE_EMPTY; } + + if (size < queues[queue_id].data_size) { return OS_QUEUE_INVALID_SIZE; } + + struct queue *cur = &queues[queue_id]; + + /* Walk through the bytes at the head of the queue and write them to buffer `data` */ + for (i = 0; i < size; i++) { *((char *)data + i) = queue_data[queue_id][cur->head * cur->data_size + i]; } + + /* Advance the queue head, wrapping if it is passed `depth` */ + cur->head = (cur->head + 1) % cur->depth; + + return OS_SUCCESS; +} + +int32 +OS_QueueGet(uint32 queue_id, void *data, uint32 size, uint32 *size_copied, int32 timeout) +{ + uint32 i; + int32 intervals; + int32 current_interval; + int result = OS_ERROR; + + sl_lock_take(&queue_lock); + + if (queue_id > OS_MAX_QUEUES || queues[queue_id].used == FALSE) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + if (data == NULL || size_copied == NULL) { + result = OS_INVALID_POINTER; + goto exit; + } + + /* FIXME: Block instead of poll */ + if (timeout == OS_CHECK) { + result = OS_QueuePoll(queue_id, data, size, size_copied); + goto exit; + } else if (timeout == OS_PEND) { + intervals = 0xFFFFFF; + } else { + intervals = timeout / 50 + 1; + } + + for (current_interval = 0; current_interval < intervals; current_interval++) { + result = OS_QueuePoll(queue_id, data, size, size_copied); + if (result == OS_SUCCESS) { goto exit; } + sl_lock_release(&queue_lock); + OS_TaskDelay(50); + sl_lock_take(&queue_lock); + } + assert(result != OS_ERROR); + +exit: + sl_lock_release(&queue_lock); + if (result != OS_SUCCESS && timeout != OS_CHECK) { return OS_QUEUE_TIMEOUT; } + return result; +} + +/* + * This function is used to send data on an existing queue. The flags can be used to specify + * the behavior of the queue if it is full. + */ +int32 +OS_QueuePut(uint32 queue_id, const void *data, uint32 size, uint32 flags) +{ + uint32 i; + struct queue *cur; + + if (queue_id > OS_MAX_QUEUES) { return OS_ERR_INVALID_ID; } + + if (queues[queue_id].used == FALSE) { return OS_ERR_INVALID_ID; } + + if (data == NULL) { return OS_INVALID_POINTER; } + + /* Check if space remains in the queue */ + if ((queues[queue_id].tail + 1) % queues[queue_id].depth == queues[queue_id].head) { return OS_QUEUE_FULL; } + + cur = &queues[queue_id]; + + /* Walk through the bytes in `data` and write them to the tail of the specified queue */ + for (i = 0; i < size; i++) { queue_data[queue_id][cur->tail * cur->data_size + i] = *((char *)data + i); } + + /* Advance the queue tail, wrapping if it is past `depth` */ + cur->tail = (cur->tail + 1) % cur->depth; + + return OS_SUCCESS; +} + + +int32 +OS_QueueGetIdByName(uint32 *queue_id, const char *queue_name) +{ + uint32 i; + uint32 queue_found = FALSE; + + if (queue_id == NULL || queue_name == NULL) { return OS_INVALID_POINTER; } + + if (strlen(queue_name) > OS_MAX_API_NAME) { return OS_ERR_NAME_TOO_LONG; } + + for (i = 0; i < OS_MAX_QUEUES; ++i) { + if (strcmp(queue_name, queues[i].name) == 0) { + *queue_id = i; + queue_found = TRUE; + break; + } + } + + if (queue_found == FALSE) { return OS_ERR_NAME_NOT_FOUND; } + + return OS_SUCCESS; +} + +int32 +OS_QueueGetInfo(uint32 queue_id, OS_queue_prop_t *queue_prop) +{ + if (queue_id > OS_MAX_QUEUES) { return OS_ERR_INVALID_ID; } + + if (queue_prop == NULL) { return OS_INVALID_POINTER; } + + if (queues[queue_id].used == FALSE) { return OS_ERR_INVALID_ID; } + + /* TODO: Identify creator; `0` is a dummy value */ + queue_prop->creator = 0; + + strcpy(queue_prop->name, queues[queue_id].name); + + /* + * NOTE: The OSAL documentation claims that there are two additional fields in `OS_queue_prop_t` called `free` + * and `id`. These members do not appear in our working version. + */ + + return OS_SUCCESS; +} diff --git a/src/components/implementation/no_interface/cFE_booter/ostask.c b/src/components/implementation/no_interface/cFE_booter/ostask.c new file mode 100644 index 0000000000..2ffe9dd603 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/ostask.c @@ -0,0 +1,848 @@ +#include +#include +#include +#include + +#include + +#include "cFE_util.h" +#include "ostask.h" + +#include "gen/osapi.h" +#include "gen/common_types.h" +#include "gen/cfe_time.h" + +#define HZ_PAUSE (1000 * 1000) + +void +timer_fn_1hz(void *d) +{ + cycles_t now, first_deadline; + + rdtscll(now); + first_deadline = now + sl_usec2cyc(HZ_PAUSE); + + while (1) { + rdtscll(now); + if (now > first_deadline) { CFE_TIME_Local1HzISR(); } + + sl_thd_block_periodic(0); + } +} + +/* + * Internal Task helper functions + */ + +/* We delegate the main thread of execution to a different thread + * (the main thread needs to run the scheduling loop) + */ +#define MAIN_DELEGATE_THREAD_PRIORITY 2 + +/* We need to keep track of this to check if register or delete handler calls are invalid */ +thdid_t main_delegate_thread_id; + +struct cfe_task_info { + osal_task_entry delete_handler; + OS_task_prop_t osal_task_prop; +}; + +struct cfe_task_info cfe_tasks[SL_MAX_NUM_THDS] = {{0}}; + +void +OS_SchedulerStart(cos_thd_fn_t main_delegate) +{ + struct sl_thd * main_delegate_thread; + sched_param_t sp; + struct cfe_task_info *task_info; + struct sl_thd * timer_thd; + sched_param_t timer_window; + sched_param_t timer_priority; + + sl_init(SL_MIN_PERIOD_US); + + main_delegate_thread = sl_thd_alloc(main_delegate, NULL); + sp = sched_param_pack(SCHEDP_PRIO, MAIN_DELEGATE_THREAD_PRIORITY); + sl_thd_param_set(main_delegate_thread, sp); + main_delegate_thread_id = sl_thd_thdid(main_delegate_thread); + + task_info = &cfe_tasks[main_delegate_thread_id]; + strcpy(task_info->osal_task_prop.name, "MAIN_THREAD"); + task_info->osal_task_prop.priority = MAIN_DELEGATE_THREAD_PRIORITY; + task_info->osal_task_prop.OStask_id = (uint32)sl_thd_thdid(main_delegate_thread); + + timer_thd = sl_thd_alloc(timer_fn_1hz, NULL); + timer_window = sched_param_pack(SCHEDP_WINDOW, HZ_PAUSE); + timer_priority = sched_param_pack(SCHEDP_PRIO, MAIN_DELEGATE_THREAD_PRIORITY + 1); + sl_thd_param_set(timer_thd, timer_window); + sl_thd_param_set(timer_thd, timer_priority); + + // Must call this before entering scheduler loop + hypercall_comp_init_done(); + + OS_printf("CFE_PSP: Entering scheduler loop...\n"); + sl_sched_loop_nonblock(); + OS_printf("CFE_PSP: Exiting scheduler loop???\n"); +} + +void +osal_task_entry_wrapper(void *task_entry) +{ + ((osal_task_entry)task_entry)(); +} + +int +is_valid_name(const char *name) +{ + int i; + for (i = 0; i < OS_MAX_API_NAME; i++) { + if (name[i] == '\0') { return TRUE; } + } + return FALSE; +} + +/* TODO: Figure out how to check if thread names are taken */ +int +is_thread_name_taken(const char *name) +{ + return FALSE; +} + +/* + * Task API + */ + +/* NOTE: We don't do flags, but I can't find an implementation that does */ +int32 +OS_TaskCreate(uint32 *task_id, const char *task_name, osal_task_entry function_pointer, uint32 *stack_pointer, + uint32 stack_size, uint32 priority, uint32 flags) +{ + struct sl_thd * thd; + sched_param_t sp; + struct cfe_task_info *task_info; + struct cos_defcompinfo child_dci; + + if (task_id == NULL || task_name == NULL || function_pointer == NULL) { return OS_INVALID_POINTER; } + + if (!is_valid_name(task_name)) { return OS_ERR_NAME_TOO_LONG; } + + if (is_thread_name_taken(task_name)) { return OS_ERR_NAME_TAKEN; } + + if (priority > 255 || priority < 1) { return OS_ERR_INVALID_PRIORITY; } + + /* If the create call is rooted in another component, STASH_MAGIC_VALUE will be passed as the function_pointer */ + if (function_pointer == STASH_MAGIC_VALUE) { + /* Since we know this is rooted in another component, we take the values from the stash */ + thdclosure_index_t idx = emu_stash_retrieve_thdclosure(); + spdid_t spdid = emu_stash_retrieve_spdid(); + + printc("task create in server (task_name = %s, fp = %p, idx = %d, spdid = %d)\n", task_name, function_pointer, idx, spdid); + + cos_defcompinfo_childid_init(&child_dci, spdid); + thd = sl_thd_aep_alloc_ext(&child_dci, NULL, idx, 0, 0, 0, 0, 0, NULL); + assert(thd); + } else { + thd = sl_thd_alloc(osal_task_entry_wrapper, function_pointer); + assert(thd); + } + + sp = sched_param_pack(SCHEDP_PRIO, priority); + sl_thd_param_set(thd, sp); + + task_info = &cfe_tasks[sl_thd_thdid(thd)]; + strcpy(task_info->osal_task_prop.name, task_name); + task_info->osal_task_prop.creator = OS_TaskGetId(); + task_info->osal_task_prop.stack_size = stack_size; + task_info->osal_task_prop.priority = priority; + task_info->osal_task_prop.OStask_id = (uint32)sl_thd_thdid(thd); + task_info->delete_handler = NULL; + + *task_id = (uint32)sl_thd_thdid(thd); + + return OS_SUCCESS; +} + +int32 +OS_TaskDelete(uint32 task_id) +{ + struct cfe_task_info *task_info; + struct sl_thd * thd; + osal_task_entry delete_handler; + + thd = sl_thd_lkup(task_id); + if (!thd) { return OS_ERR_INVALID_ID; } + /* FIXME: Need to handle the deletion of a thread pretending to be another thread */ + if (thd->state == SL_THD_FREE) { return OS_SUCCESS; } + + task_info = &cfe_tasks[task_id]; + + delete_handler = task_info->delete_handler; + if (delete_handler) { delete_handler(); } + + sl_thd_free(thd); + + return OS_SUCCESS; +} + +uint32 +OS_TaskGetId(void) +{ + thdid_t real_id = sl_thdid(); + /* Sometimes we need to disguise a thread as another thread... */ + thdid_t possible_override = id_overrides[real_id]; + if (possible_override) return possible_override; + return real_id; +} + +void +OS_TaskExit(void) +{ + sl_thd_free(sl_thd_curr()); + PANIC("Should be unreachable!"); +} + +int32 +OS_TaskInstallDeleteHandler(osal_task_entry function_pointer) +{ + struct cfe_task_info *task_info; + + if (OS_TaskGetId() == main_delegate_thread_id) { return OS_ERR_INVALID_ID; } + + task_info = &cfe_tasks[sl_thd_thdid(sl_thd_curr())]; + task_info->delete_handler = function_pointer; + + return OS_SUCCESS; +} + +int32 +OS_TaskDelay(uint32 millisecond) +{ + cycles_t wakeup = sl_now() + sl_usec2cyc(millisecond * 1000); + sl_thd_block_timeout(0, wakeup); + return OS_SUCCESS; +} + +int32 +OS_TaskSetPriority(uint32 task_id, uint32 new_priority) +{ + struct sl_thd *thd; + sched_param_t sp; + + if (new_priority > 255 || new_priority < 1) { return OS_ERR_INVALID_PRIORITY; } + + thd = sl_thd_lkup(task_id); + if (!thd) { return OS_ERR_INVALID_ID; } + + sp = sched_param_pack(SCHEDP_PRIO, new_priority); + sl_thd_param_set(thd, sp); + + return OS_SUCCESS; +} + +int32 +OS_TaskRegister(void) +{ + if (OS_TaskGetId() == main_delegate_thread_id) { return OS_ERR_INVALID_ID; } + + return OS_SUCCESS; +} + + +int32 +OS_TaskGetIdByName(uint32 *task_id, const char *task_name) +{ + thdid_t i; + + if (!task_id || !task_name) return OS_INVALID_POINTER; + + for (i = 1; i < SL_MAX_NUM_THDS; i++) { + struct sl_thd *thd = sl_thd_lkup(i); + if (!thd || thd->state == SL_THD_FREE) continue; + if (strcmp(cfe_tasks[i].osal_task_prop.name, task_name) == 0) { + *task_id = i; + return OS_SUCCESS; + } + } + + return OS_ERR_NAME_NOT_FOUND; +} + +int32 +OS_TaskGetInfo(uint32 task_id, OS_task_prop_t *task_prop) +{ + struct sl_thd *thd; + + if (!task_prop) { return OS_INVALID_POINTER; } + + thd = sl_thd_lkup(task_id); + + /* TODO: Fix this ugly workaround */ + if (!thd || thd->state == SL_THD_FREE) { return OS_ERR_INVALID_ID; } + + struct cfe_task_info *task_info = &cfe_tasks[task_id]; + *task_prop = task_info->osal_task_prop; + + return OS_SUCCESS; +} + +/* + * Main thread waiting API + */ + +/* + * OS-specific background thread implementation - waits forever for events to occur. + * + * This should be called from the BSP main routine / initial thread after all other + * board / application initialization has taken place and all other tasks are running. + */ +void +OS_IdleLoop(void) +{ + while (1) sl_thd_block(0); +} + +/* + * OS_ApplicationShutdown() provides a means for a user-created thread to request the orderly + * shutdown of the whole system, such as part of a user-commanded reset command. + * This is preferred over e.g. ApplicationExit() which exits immediately and does not + * provide for any means to clean up first. + */ +void +OS_ApplicationShutdown(uint8 flag) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ +} + +/* + * Mutex API + */ + +struct mutex { + int used; + struct sl_lock lock; + OS_mut_sem_prop_t prop; +}; + +struct sl_lock mutex_data_lock = SL_LOCK_STATIC_INIT(); +struct mutex mutexes[OS_MAX_MUTEXES]; + +int32 +OS_MutSemCreate(uint32 *sem_id, const char *sem_name, uint32 options) +{ + uint32 id; + int32 result = OS_SUCCESS; + + sl_lock_take(&mutex_data_lock); + + if (sem_id == NULL || sem_name == NULL) { + result = OS_INVALID_POINTER; + goto exit; + } + + if (!is_valid_name(sem_name)) { + result = OS_ERR_NAME_TOO_LONG; + goto exit; + } + + for (id = 0; id < OS_MAX_MUTEXES; id++) { + if (mutexes[id].used && strcmp(sem_name, mutexes[id].prop.name) == 0) { + result = OS_ERR_NAME_TAKEN; + goto exit; + } + } + + for (id = 0; id < OS_MAX_MUTEXES; id++) { + if (!mutexes[id].used) { break; } + } + if (id >= OS_MAX_MUTEXES || mutexes[id].used) { + result = OS_ERR_NO_FREE_IDS; + goto exit; + } + + *sem_id = id; + + mutexes[id].used = TRUE; + sl_lock_init(&mutexes[id].lock); + mutexes[id].prop.creator = sl_thdid(); + strcpy(mutexes[id].prop.name, sem_name); + +exit: + sl_lock_release(&mutex_data_lock); + return result; +} + +int32 +OS_MutSemGive(uint32 sem_id) +{ + sl_lock_take(&mutex_data_lock); + if (sem_id >= OS_MAX_MUTEXES || !mutexes[sem_id].used) { + sl_lock_release(&mutex_data_lock); + return OS_ERR_INVALID_ID; + } + sl_lock_release(&mutex_data_lock); + + sl_lock_release(&mutexes[sem_id].lock); + + return OS_SUCCESS; +} + +int32 +OS_MutSemTake(uint32 sem_id) +{ + sl_lock_take(&mutex_data_lock); + if (sem_id >= OS_MAX_MUTEXES || !mutexes[sem_id].used) { + sl_lock_release(&mutex_data_lock); + return OS_ERR_INVALID_ID; + } + sl_lock_release(&mutex_data_lock); + + sl_lock_take(&mutexes[sem_id].lock); + + return OS_SUCCESS; +} + +int32 +OS_MutSemDelete(uint32 sem_id) +{ + int32 result = OS_SUCCESS; + + sl_lock_take(&mutex_data_lock); + + if (sem_id >= OS_MAX_MUTEXES || !mutexes[sem_id].used) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + if (sl_lock_holder(&mutexes[sem_id].lock) != 0) { + result = OS_SEM_FAILURE; + goto exit; + } + + mutexes[sem_id].used = FALSE; + +exit: + sl_lock_release(&mutex_data_lock); + return result; +} + +int32 +OS_MutSemGetIdByName(uint32 *sem_id, const char *sem_name) +{ + int i; + int32 result = OS_SUCCESS; + + sl_lock_take(&mutex_data_lock); + + if (sem_id == NULL || sem_name == NULL) { + result = OS_INVALID_POINTER; + goto exit; + } + + if (strlen(sem_name) >= OS_MAX_API_NAME) { + result = OS_ERR_NAME_TOO_LONG; + goto exit; + } + + for (i = 0; i < OS_MAX_MUTEXES; i++) { + if (mutexes[i].used && (strcmp(mutexes[i].prop.name, (char *)sem_name) == 0)) { + *sem_id = i; + goto exit; + } + } + + /* The name was not found in the table, + * or it was, and the sem_id isn't valid anymore */ + result = OS_ERR_NAME_NOT_FOUND; +exit: + sl_lock_release(&mutex_data_lock); + return result; +} + +int32 +OS_MutSemGetInfo(uint32 sem_id, OS_mut_sem_prop_t *mut_prop) +{ + int32 result = OS_SUCCESS; + + sl_lock_take(&mutex_data_lock); + + if (!mut_prop) { + result = OS_INVALID_POINTER; + goto exit; + } + + if (sem_id >= OS_MAX_MUTEXES || !mutexes[sem_id].used) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + *mut_prop = mutexes[sem_id].prop; + +exit: + sl_lock_release(&mutex_data_lock); + return result; +} + +/* + * Semaphore API + */ + +struct semaphore { + int used; + + uint32 count; + thdid_t holder; + + uint32 creator; + char name[OS_MAX_API_NAME]; +}; + +struct sl_lock semaphore_data_lock = SL_LOCK_STATIC_INIT(); + +struct semaphore binary_semaphores[OS_MAX_BIN_SEMAPHORES]; +struct semaphore counting_semaphores[OS_MAX_COUNT_SEMAPHORES]; + +int32 +OS_SemaphoreCreate(struct semaphore *semaphores, uint32 max_semaphores, uint32 *sem_id, const char *sem_name, + uint32 sem_initial_value, uint32 options) +{ + uint32 id; + int32 result = OS_SUCCESS; + + sl_lock_take(&semaphore_data_lock); + + if (sem_id == NULL || sem_name == NULL) { + result = OS_INVALID_POINTER; + goto exit; + } + + if (!is_valid_name(sem_name)) { + result = OS_ERR_NAME_TOO_LONG; + goto exit; + } + + for (id = 0; id < max_semaphores; id++) { + if (semaphores[id].used && strcmp(sem_name, semaphores[id].name) == 0) { + result = OS_ERR_NAME_TAKEN; + goto exit; + } + } + + for (id = 0; id < max_semaphores; id++) { + if (!semaphores[id].used) { break; } + } + + if (id >= max_semaphores || semaphores[id].used) { + result = OS_ERR_NO_FREE_IDS; + goto exit; + } + + *sem_id = id; + semaphores[id].used = TRUE; + semaphores[id].creator = sl_thdid(); + semaphores[id].count = sem_initial_value; + semaphores[id].holder = 0; + strcpy(semaphores[id].name, sem_name); + +exit: + sl_lock_release(&semaphore_data_lock); + return result; +} + +int32 +OS_SemaphoreFlush(struct semaphore *semaphores, uint32 max_semaphores, uint32 sem_id) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + + +int32 +OS_SemaphoreGive(struct semaphore *semaphores, uint32 max_semaphores, uint32 sem_id) +{ + int32 result = OS_SUCCESS; + + sl_lock_take(&semaphore_data_lock); + + if (sem_id >= max_semaphores || !semaphores[sem_id].used) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + semaphores[sem_id].count += 1; + if (semaphores[sem_id].holder == sl_thdid()) { semaphores[sem_id].holder = 0; } + +exit: + sl_lock_release(&semaphore_data_lock); + return result; +} + +int32 +OS_SemaphoreTake(struct semaphore *semaphores, uint32 max_semaphores, uint32 sem_id) +{ + int32 result = OS_SUCCESS; + + sl_lock_take(&semaphore_data_lock); + + if (sem_id >= max_semaphores) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + while (semaphores[sem_id].used && semaphores[sem_id].count < 1) { + thdid_t holder = semaphores[sem_id].holder; + sl_lock_release(&semaphore_data_lock); + /* We want to run someone else here, preferably one of the semaphore holders */ + sl_thd_yield(holder); + /* If the semaphore holder is blocked, we might just get scheduled again + * Optimally we would switch to an unblocked holder, but we aren't storing them all + * And even if we did, what if all of them were blocked? + * Under fprr, in that situation, we'd just spin in this loop forever + * Thus, we use this OS_TaskDelay hack, to get us removed from the runqueue temporarily + */ + OS_TaskDelay(1); + sl_lock_take(&semaphore_data_lock); + } + + if (!semaphores[sem_id].used) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + if (semaphores[sem_id].holder == 0) { semaphores[sem_id].holder = sl_thdid(); } + + semaphores[sem_id].count -= 1; + +exit: + sl_lock_release(&semaphore_data_lock); + return result; +} + +int32 +OS_SemaphoreTimedWait(struct semaphore *semaphores, uint32 max_semaphores, uint32 sem_id, uint32 msecs) +{ + int32 result = OS_SUCCESS; + microsec_t start_time = sl_now(); + microsec_t max_wait = msecs * 1000; + + sl_lock_take(&semaphore_data_lock); + + if (sem_id >= max_semaphores) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + while (semaphores[sem_id].used && semaphores[sem_id].count < 1 && (sl_now_usec() - start_time) < max_wait) { + thdid_t holder = semaphores[sem_id].holder; + sl_lock_release(&semaphore_data_lock); + sl_thd_yield(holder); + sl_lock_take(&semaphore_data_lock); + } + + if (!semaphores[sem_id].used) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + if (semaphores[sem_id].count < 1) { + result = OS_SEM_TIMEOUT; + goto exit; + } + + if (semaphores[sem_id].holder == 0) { semaphores[sem_id].holder = sl_thdid(); } + + semaphores[sem_id].count -= 1; + +exit: + sl_lock_release(&semaphore_data_lock); + + return result; +} + +int32 +OS_SemaphoreDelete(struct semaphore *semaphores, uint32 max_semaphores, uint32 sem_id) +{ + int32 result = OS_SUCCESS; + sl_lock_take(&semaphore_data_lock); + + if (sem_id >= max_semaphores || !semaphores[sem_id].used) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + semaphores[sem_id].used = FALSE; + +exit: + sl_lock_release(&semaphore_data_lock); + + return result; +} + +int32 +OS_SemaphoreGetIdByName(struct semaphore *semaphores, uint32 max_semaphores, uint32 *sem_id, const char *sem_name) +{ + uint32 i; + int32 result = OS_SUCCESS; + + sl_lock_take(&semaphore_data_lock); + + if (sem_id == NULL || sem_name == NULL) { + result = OS_INVALID_POINTER; + goto exit; + } + + if (!is_valid_name(sem_name)) { + result = OS_ERR_NAME_TOO_LONG; + goto exit; + } + + for (i = 0; i < max_semaphores; i++) { + if (semaphores[i].used && (strcmp(semaphores[i].name, (char *)sem_name) == 0)) { + *sem_id = i; + goto exit; + } + } + + /* The name was not found in the table, + * or it was, and the sem_id isn't valid anymore + */ + result = OS_ERR_NAME_NOT_FOUND; +exit: + sl_lock_release(&semaphore_data_lock); + return result; +} + + +/* Binary semaphore methods */ +int32 +OS_BinSemCreate(uint32 *sem_id, const char *sem_name, uint32 sem_initial_value, uint32 options) +{ + return OS_SemaphoreCreate(binary_semaphores, OS_MAX_BIN_SEMAPHORES, sem_id, sem_name, sem_initial_value, + options); +} + +int32 +OS_BinSemFlush(uint32 sem_id) +{ + return OS_SemaphoreFlush(binary_semaphores, OS_MAX_BIN_SEMAPHORES, sem_id); +} + +int32 +OS_BinSemGive(uint32 sem_id) +{ + return OS_SemaphoreGive(binary_semaphores, OS_MAX_BIN_SEMAPHORES, sem_id); +} + +int32 +OS_BinSemTake(uint32 sem_id) +{ + return OS_SemaphoreTake(binary_semaphores, OS_MAX_BIN_SEMAPHORES, sem_id); +} + +int32 +OS_BinSemTimedWait(uint32 sem_id, uint32 msecs) +{ + return OS_SemaphoreTimedWait(binary_semaphores, OS_MAX_BIN_SEMAPHORES, sem_id, msecs); +} + +int32 +OS_BinSemDelete(uint32 sem_id) +{ + return OS_SemaphoreDelete(binary_semaphores, OS_MAX_BIN_SEMAPHORES, sem_id); +} + +int32 +OS_BinSemGetIdByName(uint32 *sem_id, const char *sem_name) +{ + return OS_SemaphoreGetIdByName(binary_semaphores, OS_MAX_BIN_SEMAPHORES, sem_id, sem_name); +} + +int32 +OS_BinSemGetInfo(uint32 sem_id, OS_bin_sem_prop_t *bin_prop) +{ + int32 result = OS_SUCCESS; + sl_lock_take(&semaphore_data_lock); + + if (!bin_prop) { + result = OS_INVALID_POINTER; + goto exit; + } + + if (sem_id >= OS_MAX_BIN_SEMAPHORES || !binary_semaphores[sem_id].used) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + *bin_prop = (OS_bin_sem_prop_t){.creator = binary_semaphores[sem_id].creator, + .value = binary_semaphores[sem_id].count}; + + strcpy(bin_prop->name, binary_semaphores[sem_id].name); + +exit: + sl_lock_release(&semaphore_data_lock); + return result; +} + + +int32 +OS_CountSemCreate(uint32 *sem_id, const char *sem_name, uint32 sem_initial_value, uint32 options) +{ + return OS_SemaphoreCreate(counting_semaphores, OS_MAX_COUNT_SEMAPHORES, sem_id, sem_name, sem_initial_value, + options); +} + +int32 +OS_CountSemGive(uint32 sem_id) +{ + return OS_SemaphoreGive(counting_semaphores, OS_MAX_COUNT_SEMAPHORES, sem_id); +} + +int32 +OS_CountSemTake(uint32 sem_id) +{ + return OS_SemaphoreTake(counting_semaphores, OS_MAX_COUNT_SEMAPHORES, sem_id); +} + +int32 +OS_CountSemTimedWait(uint32 sem_id, uint32 msecs) +{ + return OS_SemaphoreTimedWait(counting_semaphores, OS_MAX_COUNT_SEMAPHORES, sem_id, msecs); +} + +int32 +OS_CountSemDelete(uint32 sem_id) +{ + return OS_SemaphoreDelete(counting_semaphores, OS_MAX_COUNT_SEMAPHORES, sem_id); +} + +int32 +OS_CountSemGetIdByName(uint32 *sem_id, const char *sem_name) +{ + return OS_SemaphoreGetIdByName(counting_semaphores, OS_MAX_COUNT_SEMAPHORES, sem_id, sem_name); +} + +int32 +OS_CountSemGetInfo(uint32 sem_id, OS_count_sem_prop_t *count_prop) +{ + int32 result = OS_SUCCESS; + sl_lock_take(&semaphore_data_lock); + + if (!count_prop) { + result = OS_INVALID_POINTER; + goto exit; + } + + if (sem_id >= OS_MAX_COUNT_SEMAPHORES || !counting_semaphores[sem_id].used) { + result = OS_ERR_INVALID_ID; + goto exit; + } + + *count_prop = (OS_count_sem_prop_t){.creator = counting_semaphores[sem_id].creator, + .value = counting_semaphores[sem_id].count}; + + strcpy(count_prop->name, counting_semaphores[sem_id].name); + +exit: + sl_lock_release(&semaphore_data_lock); + + return result; +} diff --git a/src/components/implementation/no_interface/cFE_booter/ostask.h b/src/components/implementation/no_interface/cFE_booter/ostask.h new file mode 100644 index 0000000000..41df42bb8a --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/ostask.h @@ -0,0 +1,13 @@ +#ifndef OSTASK_H +#define OSTASK_H + +#include + +/* + * ThreadId overrides for apps + */ +extern thdid_t id_overrides[SL_MAX_NUM_THDS]; + +void OS_SchedulerStart(cos_thd_fn_t main_delegate); + +#endif diff --git a/src/components/implementation/no_interface/cFE_booter/ostimer.c b/src/components/implementation/no_interface/cFE_booter/ostimer.c new file mode 100644 index 0000000000..3dfc4b57bb --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/ostimer.c @@ -0,0 +1,89 @@ +#include "cFE_util.h" + +#include "gen/osapi.h" +#include "gen/common_types.h" + +/* +** Timer API +*/ + +struct { + int used; + OS_timer_prop_t props; +} timers[OS_MAX_TIMERS]; + +int32 +OS_TimerAPIInit(void) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +/* TODO: Verify this API really insn't necessary */ +int32 +OS_TimerCreate(uint32 *timer_id, const char *timer_name, uint32 *clock_accuracy, OS_TimerCallback_t callback_ptr) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_TimerAdd(uint32 *timer_id, const char *timer_name, uint32 timebase_id, OS_ArgCallback_t callback_ptr, + void *callback_arg) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_TimerSet(uint32 timer_id, uint32 start_time, uint32 interval_time) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_TimerDelete(uint32 timer_id) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + + +int32 +OS_TimerGetIdByName(uint32 *timer_id, const char *timer_name) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} + +int32 +OS_TimerGetInfo(uint32 timer_id, OS_timer_prop_t *timer_prop) +{ + return OS_ERR_NAME_NOT_FOUND; +} + +/* We don't implement the TimeBase API */ +int32 +OS_TimeBaseCreate(uint32 *timer_id, const char *timebase_name, OS_TimerSync_t external_sync) +{ + return OS_ERR_NOT_IMPLEMENTED; +} + +int32 +OS_TimeBaseSet(uint32 timer_id, uint32 start_time, uint32 interval_time) +{ + return OS_ERR_NOT_IMPLEMENTED; +} + +int32 +OS_TimeBaseDelete(uint32 timer_id) +{ + return OS_ERR_NOT_IMPLEMENTED; +} + +int32 +OS_TimeBaseGetIdByName(uint32 *timer_id, const char *timebase_name) +{ + return OS_ERR_NOT_IMPLEMENTED; +} diff --git a/src/components/implementation/no_interface/cFE_booter/psp.c b/src/components/implementation/no_interface/cFE_booter/psp.c new file mode 100644 index 0000000000..6dfa64e119 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/psp.c @@ -0,0 +1,475 @@ +#include + +#include "cFE_util.h" + +#include "sl.h" +#include "sl_consts.h" + +#include "gen/osapi.h" +#include "gen/cfe_psp.h" + + +#ifdef _ENHANCED_BUILD_ + +#include + +/* + * Define the PSP-supported capacities to be the maximum allowed, + * (since the PC-linux PSP has the advantage of abundant disk space to hold this) + */ +#define CFE_PSP_CDS_SIZE (GLOBAL_CONFIGDATA.CfeConfig->CdsSize) +#define CFE_PSP_RESET_AREA_SIZE (GLOBAL_CONFIGDATA.CfeConfig->ResetAreaSize) +#define CFE_PSP_USER_RESERVED_SIZE (GLOBAL_CONFIGDATA.CfeConfig->UserReservedSize) + +#else + +#include "gen/cfe_es.h" /* For memory sizes */ +#include "gen/cfe_platform_cfg.h" /* for processor ID */ + +#define CFE_PSP_CDS_SIZE (CFE_ES_CDS_SIZE + 1024) +#define CFE_PSP_RESET_AREA_SIZE CFE_ES_RESET_AREA_SIZE +#define CFE_PSP_USER_RESERVED_SIZE CFE_ES_USER_RESERVED_SIZE + +#endif + + +/* + * Function prototypes + */ + +/* + * PSP entry point and reset routines + */ +void +CFE_PSP_Main(uint32 ModeId, char *StartupFilePath) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ +} + +/* CFE_PSP_Main is the entry point that the real time OS calls to start our + * software. This routine will do any BSP/OS specific setup, then call the + * entrypoint of the flight software ( i.e. the cFE main entry point ). + * The flight software (i.e. cFE ) should not call this routine. + */ + +void +CFE_PSP_GetTime(OS_time_t *LocalTime) +{ + OS_GetLocalTime(LocalTime); +} +/* This call gets the local time from the hardware on the Vxworks system + * on the mcp750s + * on the other os/hardware setup, it will get the time the normal way + */ + + +void +CFE_PSP_Restart(uint32 resetType) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ +} +/* CFE_PSP_Restart is the entry point back to the BSP to restart the processor. + * The flight software calls this routine to restart the processor. + */ + + +uint32 +CFE_PSP_GetRestartType(uint32 *restartSubType) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} +/* + * CFE_PSP_GetRestartType returns the last reset type and if a pointer to a valid + * memory space is passed in, it returns the reset sub-type in that memory. + * Right now the reset types are application specific. For the cFE they + * are defined in the cfe_es.h file. + */ + + +void CFE_PSP_FlushCaches(uint32 type, cpuaddr address, uint32 size); +/* + * This is a BSP specific cache flush routine + */ + +uint32 +CFE_PSP_GetProcessorId(void) +{ + return CFE_PSP_CpuId; +} +/* + * CFE_PSP_GetProcessorId returns the CPU ID as defined by the specific board + * and BSP. + */ + + +uint32 +CFE_PSP_GetSpacecraftId(void) +{ + return CFE_PSP_SpacecraftId; +} +/* + * CFE_PSP_GetSpacecraftId retuns the Spacecraft ID (if any ) + */ + + +uint32 +CFE_PSP_Get_Timer_Tick(void) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} +/* + * CFE_PSP_Get_Timer_Tick returns the underlying OS timer tick value + * It is used for the performance monitoring software + */ + +uint32 +CFE_PSP_GetTimerTicksPerSecond(void) +{ + /* (usec / sec) / (usec / tick) */ + return 1000000 / SL_MIN_PERIOD_US; +} + +/* + * CFE_PSP_GetTimerTicksPerSecond provides the resolution of the least significant + * 32 bits of the 64 bit time stamp returned by CFE_PSP_Get_Timebase in timer + * ticks per second. The timer resolution for accuracy should not be any slower + * than 1000000 ticks per second or 1 us per tick + */ + +uint32 +CFE_PSP_GetTimerLow32Rollover(void) +{ + /* This is a pessimistic assumption + * TODO: Figure out if we can be more optimistic + */ + return 1000000; +} +/* CFE_PSP_GetTimerLow32Rollover provides the number that the least significant + * 32 bits of the 64 bit time stamp returned by CFE_PSP_Get_Timebase rolls over. + * If the lower 32 bits rolls at 1 second, then the CFE_PSP_TIMER_LOW32_ROLLOVER + * will be 1000000. if the lower 32 bits rolls at its maximum value (2^32) then + * CFE_PSP_TIMER_LOW32_ROLLOVER will be 0. + */ + +void +CFE_PSP_Get_Timebase(uint32 *Tbu, uint32 *Tbl) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ +} + + +uint32 +CFE_PSP_Get_Dec(void) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} +/* + * CFE_PSP_Get_Dec + */ + + +int32 +CFE_PSP_InitProcessorReservedMemory(uint32 RestartType) +{ + /* Since all operations on reserved memory are unimplemented, it's safe to + * do nothing here + */ + return 0; +} +/* + * CFE_PSP_InitProcessorReservedMemory initializes all of the memory in the + * BSP that is preserved on a processor reset. The memory includes the + * Critical Data Store, the ES Reset Area, the Volatile Disk Memory, and + * the User Reserved Memory. In general, the memory areas will be initialized + * ( cleared ) on a Power On reset, and preserved during a processor reset. + */ + +char CDS_MEMORY[CFE_ES_CDS_SIZE]; + +int32 +CFE_PSP_GetCDSSize(uint32 *SizeOfCDS) +{ + if (!SizeOfCDS) { return CFE_PSP_ERROR; } + *SizeOfCDS = CFE_ES_CDS_SIZE; + return CFE_PSP_SUCCESS; +} +/* + * CFE_PSP_GetCDSSize fetches the size of the OS Critical Data Store area. + */ + +int32 +CFE_PSP_WriteToCDS(void *PtrToDataToWrite, uint32 CDSOffset, uint32 NumBytes) +{ + if (!PtrToDataToWrite) { return CFE_PSP_ERROR; } + sl_cs_enter(); + memcpy(CDS_MEMORY + CDSOffset, PtrToDataToWrite, NumBytes); + sl_cs_exit(); + return CFE_PSP_SUCCESS; +} +/* + * CFE_PSP_WriteToCDS writes to the CDS Block. + */ + +int32 +CFE_PSP_ReadFromCDS(void *PtrToDataToRead, uint32 CDSOffset, uint32 NumBytes) +{ + if (!PtrToDataToRead) { return CFE_PSP_ERROR; } + sl_cs_enter(); + memcpy(PtrToDataToRead, CDS_MEMORY + CDSOffset, NumBytes); + sl_cs_exit(); + return CFE_PSP_SUCCESS; +} +/* + * CFE_PSP_ReadFromCDS reads from the CDS Block + */ + +/* TODO: Make this dynamic based on constants */ +char RESET_AREA[CFE_PSP_CDS_SIZE]; + +int32 +CFE_PSP_GetResetArea(cpuaddr *PtrToResetArea, uint32 *SizeOfResetArea) +{ + if (!PtrToResetArea || !SizeOfResetArea) { return CFE_PSP_ERROR; } + *PtrToResetArea = (cpuaddr)RESET_AREA; + *SizeOfResetArea = CFE_PSP_CDS_SIZE; + return CFE_PSP_SUCCESS; +} +/* + * CFE_PSP_GetResetArea returns the location and size of the ES Reset information area. + * This area is preserved during a processor reset and is used to store the + * ER Log, System Log and reset related variables + */ + +int32 +CFE_PSP_GetUserReservedArea(cpuaddr *PtrToUserArea, uint32 *SizeOfUserArea) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} +/* + * CFE_PSP_GetUserReservedArea returns the location and size of the memory used for the cFE + * User reserved area. + */ + + +int32 +CFE_PSP_GetVolatileDiskMem(cpuaddr *PtrToVolDisk, uint32 *SizeOfVolDisk) +{ + if (!PtrToVolDisk || !SizeOfVolDisk) { return CFE_PSP_ERROR; } + *PtrToVolDisk = 0; + *SizeOfVolDisk = 0; + return CFE_PSP_SUCCESS; +} +/* + * CFE_PSP_GetVolatileDiskMem returns the location and size of the memory used for the cFE + * volatile disk. + */ + +int32 +CFE_PSP_GetKernelTextSegmentInfo(cpuaddr *PtrToKernelSegment, uint32 *SizeOfKernelSegment) +{ + /* TODO: Verify this is ok to remain unimplemented */ + return CFE_PSP_ERROR_NOT_IMPLEMENTED; +} +/* + * CFE_PSP_GetKernelTextSegmentInfo returns the location and size of the kernel memory. + */ + +int32 +CFE_PSP_GetCFETextSegmentInfo(cpuaddr *PtrToCFESegment, uint32 *SizeOfCFESegment) +{ + /* TODO: Verify this is ok to remain unimplemented */ + return CFE_PSP_ERROR_NOT_IMPLEMENTED; +} +/* + * CFE_PSP_GetCFETextSegmentInfo returns the location and size of the kernel memory. + */ + + +/* FIXME: The watchdog never actually triggers */ + +/* +** The watchdog time in milliseconds +*/ +uint32 CFE_PSP_WatchdogValue = CFE_PSP_WATCHDOG_MAX; + +/* Function: CFE_PSP_WatchdogInit() +** +** Purpose: +** To setup the timer resolution and/or other settings custom to this platform. +** +** Arguments: +** +** Return: +*/ +void CFE_PSP_WatchdogInit(void) +{ + + /* + ** Just set it to a value right now + ** The pc-linux desktop platform does not actually implement a watchdog + ** timeout ( but could with a signal ) + */ + CFE_PSP_WatchdogValue = CFE_PSP_WATCHDOG_MAX; + +} + + + /****************************************************************************** + ** Function: CFE_PSP_WatchdogEnable() + ** + ** Purpose: + ** Enable the watchdog timer + ** + ** Arguments: + ** + ** Return: + */ + void CFE_PSP_WatchdogEnable(void) + { + + } + + + /****************************************************************************** + ** Function: CFE_PSP_WatchdogDisable() + ** + ** Purpose: + ** Disable the watchdog timer + ** + ** Arguments: + ** + ** Return: + */ + void CFE_PSP_WatchdogDisable(void) + { + + } + + /****************************************************************************** + ** Function: CFE_PSP_WatchdogService() + ** + ** Purpose: + ** Load the watchdog timer with a count that corresponds to the millisecond + ** time given in the parameter. + ** + ** Arguments: + ** None. + ** + ** Return: + ** None + ** + ** Notes: + ** + */ + void CFE_PSP_WatchdogService(void) + { + + + } + + /****************************************************************************** + ** Function: CFE_PSP_WatchdogGet + ** + ** Purpose: + ** Get the current watchdog value. + ** + ** Arguments: + ** none + ** + ** Return: + ** the current watchdog value + ** + ** Notes: + ** + */ + uint32 CFE_PSP_WatchdogGet(void) + { + return(CFE_PSP_WatchdogValue); + } + + + /****************************************************************************** + ** Function: CFE_PSP_WatchdogSet + ** + ** Purpose: + ** Get the current watchdog value. + ** + ** Arguments: + ** The new watchdog value + ** + ** Return: + ** nothing + ** + ** Notes: + ** + */ + void CFE_PSP_WatchdogSet(uint32 WatchdogValue) + { + + CFE_PSP_WatchdogValue = WatchdogValue; + + } + +void +CFE_PSP_Panic(int32 ErrorCode) +{ + printc("Error code is %d\n", (int)ErrorCode); + PANIC("PANICKING!"); +} +/* + * CFE_PSP_Panic is called by the cFE Core startup code when it needs to abort the + * cFE startup. This should not be called by applications. + */ + +int32 +CFE_PSP_InitSSR(uint32 bus, uint32 device, char *DeviceName) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} +/* + * CFE_PSP_InitSSR will initialize the Solid state recorder memory for a particular platform + */ + +int32 +CFE_PSP_Decompress(char *srcFileName, char *dstFileName) +{ + PANIC("Unimplemented method!"); /* TODO: Implement me! */ + return 0; +} +/* + * CFE_PSP_Decompress will uncompress the source file to the file specified in the + * destination file name. The Decompress uses the "gzip" algorithm. Files can + * be compressed using the "gzip" program available on almost all host platforms. + */ + +void +CFE_PSP_AttachExceptions(void) +{ + /* For now it is safe for this to do nothing + * TODO: Actually implement exception handling + */ +} +/* + * CFE_PSP_AttachExceptions will setup the exception environment for the chosen platform + * On a board, this can be configured to look at a debug flag or switch in order to + * keep the standard OS exeption handlers, rather than restarting the system + */ + + +void +CFE_PSP_SetDefaultExceptionEnvironment(void) +{ + /* TODO: Figure out if it is safe for us to just do nothing here */ +} +/* + * + * CFE_PSP_SetDefaultExceptionEnvironment defines the CPU and FPU exceptions that are enabled for each cFE Task/App + * + * Notes: The exception environment is local to each task Therefore this must be + * called for each task that that wants to do floating point and catch exceptions + */ diff --git a/src/components/implementation/no_interface/cFE_booter/sl_mod_fprr.c b/src/components/implementation/no_interface/cFE_booter/sl_mod_fprr.c new file mode 100644 index 0000000000..8e149fca45 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/sl_mod_fprr.c @@ -0,0 +1,120 @@ +#include + +#include +#include +#include +#include + +#define SL_FPRR_NPRIOS 257 +#define SL_FPRR_PRIO_HIGHEST 0 +#define SL_FPRR_PRIO_LOWEST (SL_FPRR_NPRIOS - 1) + +#define SL_FPRR_PERIOD_US_MIN SL_MIN_PERIOD_US + +struct ps_list_head threads[SL_FPRR_NPRIOS]; + +/* No RR yet */ +void +sl_mod_execution(struct sl_thd_policy *t, cycles_t cycles) +{ +} + +struct sl_thd_policy * +sl_mod_schedule(void) +{ + int i; + struct sl_thd_policy *t; + + for (i = 0; i < SL_FPRR_NPRIOS; i++) { + if (ps_list_head_empty(&threads[i])) continue; + t = ps_list_head_first_d(&threads[i], struct sl_thd_policy); + + struct sl_thd *thd = sl_mod_thd_get(t); + + /* + * We want to move the selected thread to the back of the list. + * Otherwise fprr won't be truly round robin + */ + ps_list_rem_d(t); + ps_list_head_append_d(&threads[i], t); + + return t; + } + + return NULL; +} + +void +sl_mod_block(struct sl_thd_policy *t) +{ + ps_list_rem_d(t); +} + +void +sl_mod_wakeup(struct sl_thd_policy *t) +{ + assert(t->priority <= SL_FPRR_PRIO_LOWEST && ps_list_singleton_d(t)); + + ps_list_head_append_d(&threads[t->priority], t); +} + +void +sl_mod_yield(struct sl_thd_policy *t, struct sl_thd_policy *yield_to) +{ + assert(t->priority <= SL_FPRR_PRIO_LOWEST); + + ps_list_rem_d(t); + ps_list_head_append_d(&threads[t->priority], t); +} + +void +sl_mod_thd_create(struct sl_thd_policy *t) +{ + t->priority = SL_FPRR_PRIO_LOWEST; + t->period = 0; + t->period_usec = 0; + ps_list_init_d(t); +} + +void +sl_mod_thd_delete(struct sl_thd_policy *t) +{ + ps_list_rem_d(t); +} + +void +sl_mod_thd_param_set(struct sl_thd_policy *t, sched_param_type_t type, unsigned int v) +{ + switch (type) { + case SCHEDP_PRIO: { + assert(v < SL_FPRR_NPRIOS); + ps_list_rem_d(t); /* if we're already on a list, and we're updating priority */ + t->priority = v; + ps_list_head_append_d(&threads[t->priority], t); + sl_thd_setprio(sl_mod_thd_get(t), t->priority); + + break; + } + case SCHEDP_WINDOW: { + struct sl_thd *td = sl_mod_thd_get(t); + + assert(v >= SL_FPRR_PERIOD_US_MIN); + t->period_usec = v; + t->period = sl_usec2cyc(v); + /* FIXME: synchronize periods for all tasks */ + + break; + } + default: + assert(0); + } +} + +void +sl_mod_init(void) +{ + int i; + struct sl_thd *t; + + for (i = 0; i < SL_FPRR_NPRIOS; i++) { ps_list_head_init(&threads[i]); } +} diff --git a/src/components/implementation/no_interface/cFE_booter/tar.c b/src/components/implementation/no_interface/cFE_booter/tar.c new file mode 100644 index 0000000000..e18f13dfa8 --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/tar.c @@ -0,0 +1,143 @@ +#include + +#include + +#include "osfilesys.h" +#include "tar.h" + +/* should be overwritten by linking step in build process */ +__attribute__((weak)) char _binary_cFE_fs_tar_size = 0; +__attribute__((weak)) char _binary_cFE_fs_tar_start = 0; +__attribute__((weak)) char _binary_cFE_fs_tar_end = 0; + +/* locations and size of tar */ +char * tar_start; +char * tar_end; +size_t tar_size; + +static uint32 +round_to_blocksize(uint32 offset) +{ + if (offset % TAR_BLOCKSIZE) return offset + (TAR_BLOCKSIZE - (offset % TAR_BLOCKSIZE)); + return offset; +} + +/* used to convert filesize in oct char string to dec, adapted from old fs code by gparmer */ +static uint32 +oct_to_dec(char *oct) +{ + int32 i, base; + int32 tot; + i = strlen(oct) - 1; + for (base = 1, tot = 0; i >= 0; i--, base *= 8) { + char val = oct[i]; + assert(val <= '7' && val >= '0'); + val = val - '0'; + tot = tot + (val * base); + } + return tot; +} + + +/* + * Loads the position in memory of linked tar file system + * Checks for badly linked or no linked tar file. The names given by + * the linker are non-intuitive so a description of error checking is given + * First checks to make sure that symbols have been overwritten by linking + * process. Next checks that the size is greater than 0. Finally checks that + * the end of the tar is after the start + */ +uint32 +tar_load() +{ + /* First make sure that symbols have been overwritten by linking process */ + if (!_binary_cFE_fs_tar_start) return OS_FS_ERR_DRIVE_NOT_CREATED; + /* Next check that file size is greater than 0 */ + if (&_binary_cFE_fs_tar_size == 0) return OS_FS_ERR_DRIVE_NOT_CREATED; + /* Check that the end of the tar is after the start */ + if (&_binary_cFE_fs_tar_end < &_binary_cFE_fs_tar_start) return OS_FS_ERR_DRIVE_NOT_CREATED; + + tar_size = (size_t)&_binary_cFE_fs_tar_size; + tar_start = &_binary_cFE_fs_tar_start; + tar_end = &_binary_cFE_fs_tar_end; + + return OS_FS_SUCCESS; +} + + +/* + * parses a loaded tar into whichever filesystem is mounted + * precondition: tar has been loaded by tar_load and init by newfs_init + * Postcondition: A proper error code is returned OR the tar is represented in memory + * at the currently open filesystem + */ +uint32 +tar_parse() +{ + uint32 offset = 0; + struct fsobj *o; + + assert(tar_start && tar_end); + assert(tar_size < INT32_MAX); + assert(tar_end - tar_start > 0); + assert(tar_size == (size_t)(tar_end - tar_start)); + + while (offset + tar_start < tar_end) { + if (file_get_new(&o)) return OS_FS_ERR_DRIVE_NOT_CREATED; + + /* tar ends after two empty records */ + if (!(offset + tar_start)[0] && !(offset + tar_start)[TAR_BLOCKSIZE]) { + o->ino = 0; + return OS_FS_SUCCESS; + } + if (tar_hdr_read(offset, o)) return OS_FS_ERR_DRIVE_NOT_CREATED; + if (file_insert(o, offset + tar_start) != OS_FS_SUCCESS) return OS_FS_ERR_DRIVE_NOT_CREATED; + + /* + * data is aligned to 512 byte blocks. a header is 500 bytes, and + * the file's data begins exactly after the header + * therefor the next header is 500 + o->size rounded up to a mult of 512 + */ + offset += round_to_blocksize(o->size + 500); + } + /* tar ends before two empty records are found */ + return OS_FS_ERROR; +} + +/* + * Copies information from a tar file header to a fsobj + */ +uint32 +tar_hdr_read(uint32 tar_offset, struct fsobj *file) +{ + char * location; + struct f_part *part; + uint32 file_data_offset; + + assert(tar_offset < tar_size); + assert(file->ino > 0); + + part_get_new(&part); + file->memtype = STATIC; + + location = tar_start; + location += tar_offset; + memmove(location + 1, location, strlen(location)); + location[0] = '/'; + file->name = path_to_name(location); + + file_data_offset = round_to_blocksize(tar_offset + 500); + + PRINT_LOG(PRINT_DEBUG, "Found file in tar: name = %s\n", file->name); + + if (*(location + strlen(location) - 1) == '/') { + file->type = FSOBJ_DIR; + file->size = 0; + } else { + file->type = FSOBJ_FILE; + file->size = oct_to_dec(location + 124); + file->file_part = part; + file->file_part->data = tar_start + file_data_offset; + } + return OS_FS_SUCCESS; +} diff --git a/src/components/implementation/no_interface/cFE_booter/tar.h b/src/components/implementation/no_interface/cFE_booter/tar.h new file mode 100644 index 0000000000..271fde66fc --- /dev/null +++ b/src/components/implementation/no_interface/cFE_booter/tar.h @@ -0,0 +1,29 @@ +#define TAR_BLOCKSIZE 512 +#define INT32_MAX 0x7FFFFFF /* 2^31 - 1 */ + +/*from GNU */ +struct posix_header { /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; + +uint32 tar_load(); + +uint32 tar_parse(); + +uint32 tar_hdr_read(uint32 tar_offset, struct fsobj *file); diff --git a/src/components/implementation/no_interface/ds/Makefile b/src/components/implementation/no_interface/ds/Makefile new file mode 100644 index 0000000000..db9fa3b9dc --- /dev/null +++ b/src/components/implementation/no_interface/ds/Makefile @@ -0,0 +1,10 @@ +# C_OBJS=cFE_entrypoint.o cFE_stub.o osapi.o osfiles.o osloader.o osqueue.o ostask.o ostimer.o osnetwork.o psp.o scheddev/sl.c scheddev/sl_mod_fprr.c +ASM_OBJS= +COMPONENT=ds.o +INTERFACES= +DEPENDENCIES=cFE capmgr +IF_LIB:=./cFE_ds_app.o ./cFE_ds_cmds.o ./cFE_ds_file.o ./cFE_ds_table.o ./cFE_cfs_utils.o +ADDITIONAL_LIBS=-lcos_kernel_api + +include ../../Makefile.subsubdir +MANDITORY_LIB=simple_stklib.o diff --git a/src/components/implementation/no_interface/ds/init.c b/src/components/implementation/no_interface/ds/init.c new file mode 100644 index 0000000000..fe22a95473 --- /dev/null +++ b/src/components/implementation/no_interface/ds/init.c @@ -0,0 +1,16 @@ +#include +#include +#include + +extern void DS_AppMain(); +extern void OS_IdleLoop(); +extern void do_emulation_setup(spdid_t id); + +void cos_init(void) +{ + do_emulation_setup(cos_comp_info.cos_this_spd_id); + printc("Starting DS main\n"); + DS_AppMain(); + printc("Ending DS main\n"); + while(1) OS_IdleLoop(); +} diff --git a/src/components/implementation/no_interface/fm/Makefile b/src/components/implementation/no_interface/fm/Makefile new file mode 100644 index 0000000000..80d96fb94c --- /dev/null +++ b/src/components/implementation/no_interface/fm/Makefile @@ -0,0 +1,10 @@ +# C_OBJS=cFE_entrypoint.o cFE_stub.o osapi.o osfiles.o osloader.o osqueue.o ostask.o ostimer.o osnetwork.o psp.o scheddev/sl.c scheddev/sl_mod_fprr.c +ASM_OBJS= +COMPONENT=fm.o +INTERFACES= +DEPENDENCIES=cFE capmgr +IF_LIB:=./cFE_fm_app.o ./cFE_fm_child.o ./cFE_fm_cmds.o ./cFE_fm_cmd_utils.o cFE_fm_tbl.o ./cFE_cfs_utils.o +ADDITIONAL_LIBS=-lcos_kernel_api + +include ../../Makefile.subsubdir +MANDITORY_LIB=simple_stklib.o diff --git a/src/components/implementation/no_interface/fm/init.c b/src/components/implementation/no_interface/fm/init.c new file mode 100644 index 0000000000..9b120e2b16 --- /dev/null +++ b/src/components/implementation/no_interface/fm/init.c @@ -0,0 +1,16 @@ +#include +#include +#include + +extern void FM_AppMain(); +extern void OS_IdleLoop(); +extern void do_emulation_setup(spdid_t id); + +void cos_init(void) +{ + do_emulation_setup(cos_comp_info.cos_this_spd_id); + printc("Starting FM main\n"); + FM_AppMain(); + printc("Ending FM main\n"); + while(1) OS_IdleLoop(); +} diff --git a/src/components/implementation/no_interface/hs/Makefile b/src/components/implementation/no_interface/hs/Makefile new file mode 100644 index 0000000000..b448701611 --- /dev/null +++ b/src/components/implementation/no_interface/hs/Makefile @@ -0,0 +1,10 @@ +# C_OBJS=cFE_entrypoint.o cFE_stub.o osapi.o osfiles.o osloader.o osqueue.o ostask.o ostimer.o osnetwork.o psp.o scheddev/sl.c scheddev/sl_mod_fprr.c +ASM_OBJS= +COMPONENT=hs.o +INTERFACES= +DEPENDENCIES=cFE capmgr +IF_LIB:=./cFE_hs_app.o ./cFE_hs_cmds.o ./cFE_hs_custom.o ./cFE_hs_monitors.o +ADDITIONAL_LIBS=-lcos_kernel_api + +include ../../Makefile.subsubdir +MANDITORY_LIB=simple_stklib.o diff --git a/src/components/implementation/no_interface/hs/init.c b/src/components/implementation/no_interface/hs/init.c new file mode 100644 index 0000000000..617a615b4c --- /dev/null +++ b/src/components/implementation/no_interface/hs/init.c @@ -0,0 +1,16 @@ +#include +#include +#include + +extern void HS_AppMain(); +extern void OS_IdleLoop(); +extern void do_emulation_setup(spdid_t id); + +void cos_init(void) +{ + do_emulation_setup(cos_comp_info.cos_this_spd_id); + printc("Starting HS main\n"); + HS_AppMain(); + printc("Ending HS main\n"); + while(1) OS_IdleLoop(); +} diff --git a/src/components/implementation/no_interface/llbooter/llbooter.c b/src/components/implementation/no_interface/llbooter/llbooter.c index e60d732370..278436c596 100644 --- a/src/components/implementation/no_interface/llbooter/llbooter.c +++ b/src/components/implementation/no_interface/llbooter/llbooter.c @@ -92,12 +92,12 @@ boot_comp_map_memory(struct cobj_header *h, spdid_t spdid) } else { boot_deps_map_sect(spdid, &map_daddr); } - assert(dest_daddr == map_daddr); prev_map = dest_daddr; dest_daddr += PAGE_SIZE; left -= PAGE_SIZE; } } + boot_deps_map_sect(spdid, &map_daddr); return 0; } @@ -112,7 +112,7 @@ boot_spd_end(struct cobj_header *h) max_sect = h->nsect - 1; sect = cobj_sect_get(h, max_sect); - return sect->vaddr + round_up_to_page(sect->bytes); + return sect->vaddr + round_up_to_page(sect->bytes) + PAGE_SIZE; } int diff --git a/src/components/implementation/no_interface/llbooter/s_stub.S b/src/components/implementation/no_interface/llbooter/s_stub.S index 2b71e454eb..947e35d181 100644 --- a/src/components/implementation/no_interface/llbooter/s_stub.S +++ b/src/components/implementation/no_interface/llbooter/s_stub.S @@ -1,3 +1,5 @@ +#define __ASM__ +#include #include .text diff --git a/src/components/implementation/no_interface/mm/Makefile b/src/components/implementation/no_interface/mm/Makefile new file mode 100644 index 0000000000..a5e068bf4d --- /dev/null +++ b/src/components/implementation/no_interface/mm/Makefile @@ -0,0 +1,10 @@ +# C_OBJS=cFE_entrypoint.o cFE_stub.o osapi.o osfiles.o osloader.o osqueue.o ostask.o ostimer.o osnetwork.o psp.o scheddev/sl.c scheddev/sl_mod_fprr.c +ASM_OBJS= +COMPONENT=mm.o +INTERFACES= +DEPENDENCIES=cFE capmgr +IF_LIB:=./cFE_mm_app.o ./cFE_mm_dump.o ./cFE_mm_load.o ./cFE_mm_mem16.o ./cFE_mm_mem32.o ./cFE_mm_mem8.o ./cFE_mm_utils.o ./cFE_cfs_utils.o +ADDITIONAL_LIBS=-lcos_kernel_api + +include ../../Makefile.subsubdir +MANDITORY_LIB=simple_stklib.o diff --git a/src/components/implementation/no_interface/mm/init.c b/src/components/implementation/no_interface/mm/init.c new file mode 100644 index 0000000000..6252308eb2 --- /dev/null +++ b/src/components/implementation/no_interface/mm/init.c @@ -0,0 +1,16 @@ +#include +#include +#include + +extern void MM_AppMain(); +extern void OS_IdleLoop(); +extern void do_emulation_setup(spdid_t id); + +void cos_init(void) +{ + do_emulation_setup(cos_comp_info.cos_this_spd_id); + printc("Starting MM main\n"); + MM_AppMain(); + printc("Ending MM main\n"); + while(1) OS_IdleLoop(); +} diff --git a/src/components/implementation/no_interface/sc/Makefile b/src/components/implementation/no_interface/sc/Makefile new file mode 100644 index 0000000000..97b8d7617b --- /dev/null +++ b/src/components/implementation/no_interface/sc/Makefile @@ -0,0 +1,10 @@ +# C_OBJS=cFE_entrypoint.o cFE_stub.o osapi.o osfiles.o osloader.o osqueue.o ostask.o ostimer.o osnetwork.o psp.o scheddev/sl.c scheddev/sl_mod_fprr.c +ASM_OBJS= +COMPONENT=sc.o +INTERFACES= +DEPENDENCIES=cFE capmgr +IF_LIB:=./cFE_sc_app.o ./cFE_sc_atsrq.o ./cFE_sc_cmds.o ./cFE_sc_loads.o ./cFE_sc_rtsrq.o ./cFE_sc_state.o ./cFE_sc_utils.o +ADDITIONAL_LIBS=-lcos_kernel_api + +include ../../Makefile.subsubdir +MANDITORY_LIB=simple_stklib.o diff --git a/src/components/implementation/no_interface/sc/init.c b/src/components/implementation/no_interface/sc/init.c new file mode 100644 index 0000000000..298e74ac3a --- /dev/null +++ b/src/components/implementation/no_interface/sc/init.c @@ -0,0 +1,16 @@ +#include +#include +#include + +extern void SC_AppMain(); +extern void OS_IdleLoop(); +extern void do_emulation_setup(spdid_t id); + +void cos_init(void) +{ + do_emulation_setup(cos_comp_info.cos_this_spd_id); + printc("Starting SC main\n"); + SC_AppMain(); + printc("Ending SC main\n"); + while(1) OS_IdleLoop(); +} diff --git a/src/components/implementation/no_interface/sch_lab/Makefile b/src/components/implementation/no_interface/sch_lab/Makefile new file mode 100644 index 0000000000..e149e30b4d --- /dev/null +++ b/src/components/implementation/no_interface/sch_lab/Makefile @@ -0,0 +1,10 @@ +# C_OBJS=cFE_entrypoint.o cFE_stub.o osapi.o osfiles.o osloader.o osqueue.o ostask.o ostimer.o osnetwork.o psp.o scheddev/sl.c scheddev/sl_mod_fprr.c +ASM_OBJS= +COMPONENT=sch_lab.o +INTERFACES= +DEPENDENCIES=cFE capmgr +IF_LIB:=./cFE_sch_lab_app.o +ADDITIONAL_LIBS=-lcos_kernel_api + +include ../../Makefile.subsubdir +MANDITORY_LIB=simple_stklib.o diff --git a/src/components/implementation/no_interface/sch_lab/init.c b/src/components/implementation/no_interface/sch_lab/init.c new file mode 100644 index 0000000000..d530f10959 --- /dev/null +++ b/src/components/implementation/no_interface/sch_lab/init.c @@ -0,0 +1,16 @@ +#include +#include +#include + +extern void SCH_Lab_AppMain(); +extern void OS_IdleLoop(); +extern void do_emulation_setup(spdid_t id); + +void cos_init(void) +{ + do_emulation_setup(cos_comp_info.cos_this_spd_id); + printc("Starting SCH_LAB main\n"); + SCH_Lab_AppMain(); + printc("Ending SCH_LAB main\n"); + while(1) OS_IdleLoop(); +} diff --git a/src/components/include/cos_asm_simple_stacks.h b/src/components/include/cos_asm_simple_stacks.h index b6dd7b9e21..d5bfc26641 100644 --- a/src/components/include/cos_asm_simple_stacks.h +++ b/src/components/include/cos_asm_simple_stacks.h @@ -3,7 +3,6 @@ #define __ASM__ #include -#undefine __ASM__ /* clang-format off */ diff --git a/src/components/include/llprint.h b/src/components/include/llprint.h index 75730369fa..703855ffdb 100644 --- a/src/components/include/llprint.h +++ b/src/components/include/llprint.h @@ -41,13 +41,12 @@ printc(char *fmt, ...) typedef enum { PRINT_ERROR = 0, /* print only error messages */ - PRINT_WARN, /* print errors and warnings */ - PRINT_DEBUG /* print errors, warnings and debug messages */ + PRINT_WARN, /* print errors and warnings */ + PRINT_INFO, /* print info messages, errors, and warnings */ + PRINT_DEBUG /* print errors, warnings, info messsages, and debug messages */ } cos_print_level_t; -#ifndef PRINT_LEVEL_MAX -#define PRINT_LEVEL_MAX 3 -#endif +#define PRINT_LEVEL_COUNT 4 extern cos_print_level_t cos_print_level; extern int cos_print_lvl_str; @@ -55,6 +54,7 @@ extern const char *cos_print_str[]; /* Prints with current (cpuid, thdid, spdid) */ #define PRINTC(format, ...) printc("(%ld,%u,%lu) " format, cos_cpuid(), cos_thdid(), cos_spd_id(), ## __VA_ARGS__) + /* Prints only if @level is <= cos_print_level */ #define PRINTLOG(level, format, ...) \ { \ @@ -64,4 +64,21 @@ extern const char *cos_print_str[]; } \ } +#define PRINT_LOG PRINTLOG + +static void +log_bytes(cos_print_level_t level, char *message, char *bytes, size_t bytes_count) +{ + if (level <= cos_print_level) { + size_t i; + + PRINT_LOG(level, "%s [ ", message); + for (i = 0; i < bytes_count; i++) { + printc("%X ", bytes[i]); + } + printc("]\n"); + } +} + + #endif /* LLPRINT_H */ diff --git a/src/components/interface/cFE/Makefile b/src/components/interface/cFE/Makefile new file mode 100644 index 0000000000..ebb7b41beb --- /dev/null +++ b/src/components/interface/cFE/Makefile @@ -0,0 +1,6 @@ +LIB_OBJS= +LIBS=$(LIB_OBJS:%.o=%.a) +ASM_STUBS=s_stubpg.o + +include ../Makefile.subdir +CINC+=-I$(CDIR)/implementation/no_interface/cFE_booter/gen diff --git a/src/components/interface/cFE/cFE_emu.h b/src/components/interface/cFE/cFE_emu.h new file mode 100644 index 0000000000..3e09e01ea7 --- /dev/null +++ b/src/components/interface/cFE/cFE_emu.h @@ -0,0 +1,330 @@ +#ifndef _CFE_EMU_ +#define _CFE_EMU_ + +#include + +#include + +#include +#include +#include +#include +#include + +#define SHARED_REGION_NUM_PAGES 5 + +#define EMU_BUF_SIZE 1024 +#define EMU_TBL_BUF_SIZE (4 * 4096) + +/* TODO: Alphabetize me! */ +union shared_region { + struct { + CFE_EVS_BinFilter_t filters[CFE_EVS_MAX_EVENT_FILTERS]; + uint16 NumEventFilters; + uint16 FilterScheme; + } cfe_evs_register; + struct { + CFE_SB_PipeId_t PipeId; + uint16 Depth; + char PipeName[OS_MAX_API_NAME]; + } cfe_sb_createPipe; + struct { + char MsgBuffer[EMU_BUF_SIZE]; + CFE_SB_MsgId_t MsgId; + uint16 Length; + boolean Clear; + } cfe_sb_initMsg; + struct { + char Msg[EMU_BUF_SIZE]; + uint16 EventID; + uint16 EventType; + } cfe_evs_sendEvent; + struct { + uint32 RunStatus; + } cfe_es_runLoop; + struct { + CFE_SB_PipeId_t PipeId; + int32 TimeOut; + char Msg[EMU_BUF_SIZE]; + } cfe_sb_rcvMsg; + struct { + CFE_SB_Msg_t Msg; + } cfe_sb_getMsgLen; + struct { + char Msg[EMU_BUF_SIZE]; + } cfe_sb_msg; + CFE_TIME_SysTime_t time; + struct { + char PrintBuffer[CFE_TIME_PRINTED_STRING_SIZE]; + CFE_TIME_SysTime_t TimeToPrint; + } cfe_time_print; + struct { + char Msg[EMU_BUF_SIZE]; + uint16 CmdCode; + } cfe_sb_setCmdCode; + struct { + CFE_TIME_SysTime_t Time1; + CFE_TIME_SysTime_t Time2; + CFE_TIME_SysTime_t Result; + } cfe_time_add; + struct { + CFE_TIME_SysTime_t Time1; + CFE_TIME_SysTime_t Time2; + CFE_TIME_Compare_t Result; + } cfe_time_compare; + struct { + CFE_ES_TaskInfo_t TaskInfo; + uint32 TaskId; + } cfe_es_getTaskInfo; + struct { + uint32 ResetSubtype; + } cfe_es_getResetType; + struct { + uint32 CounterId; + uint32 Count; + } cfe_es_getGenCount; + struct { + uint32 CounterId; + char CounterName[EMU_BUF_SIZE]; + } cfe_es_getGenCounterIDByName; + struct { + int32 FileDes; + CFE_FS_Header_t Hdr; + } cfe_fs_writeHeader; + struct { + char SourceFile[EMU_BUF_SIZE]; + char DestinationFile[EMU_BUF_SIZE]; + } cfe_fs_decompress; + struct { + char path[EMU_BUF_SIZE]; + int32 access; + } os_creat; + struct { + int32 filedes; + char buffer[EMU_BUF_SIZE]; + uint32 nbytes; + } os_write; + struct { + cpuaddr symbol_address; + char symbol_name[EMU_BUF_SIZE]; + } os_symbolLookup; + struct { + uint32 sem_id; + char sem_name[EMU_BUF_SIZE]; + uint32 sem_initial_value; + uint32 options; + } os_semCreate; + struct { + char src[EMU_BUF_SIZE]; + char dest[EMU_BUF_SIZE]; + } os_cp; + struct { + int32 filedes; + OS_FDTableEntry fd_prop; + } os_FDGetInfo; + struct { + char name[EMU_BUF_SIZE]; + uint64 bytes_free; + } os_fsBytesFree; + struct { + char path[EMU_BUF_SIZE]; + uint32 access; + } os_mkdir; + struct { + uint32 sem_id; + char sem_name[EMU_BUF_SIZE]; + uint32 options; + } os_mutSemCreate; + struct { + char src[EMU_BUF_SIZE]; + char dest[EMU_BUF_SIZE]; + } os_mv; + struct { + char path[EMU_BUF_SIZE]; + } os_opendir; + struct { + int32 filedes; + char buffer[EMU_BUF_SIZE]; + uint32 nbytes; + } os_read; + struct { + char path[EMU_BUF_SIZE]; + } os_remove; + struct { + char old_filename[EMU_BUF_SIZE]; + char new_filename[EMU_BUF_SIZE]; + } os_rename; + struct { + char path[EMU_BUF_SIZE]; + } os_rmdir; + struct { + char path[EMU_BUF_SIZE]; + os_fstat_t filestats; + } os_stat; + struct { + os_dirp_t directory; + os_dirent_t dirent; + } os_readdir; + struct { + uint32 task_id; + char task_name[EMU_BUF_SIZE]; + } os_taskGetIdByName; + struct { + char String[EMU_BUF_SIZE]; + } cfe_es_writeToSysLog; + struct { + char path[EMU_BUF_SIZE]; + int32 access; + uint32 mode; + } os_open; + struct { + char Data[EMU_BUF_SIZE]; + uint32 DataLength; + uint32 InputCRC; + uint32 TypeCRC; + } cfe_es_calculateCRC; + struct { + uint32 AppId; + char AppName[EMU_BUF_SIZE]; + } cfe_es_getAppIDByName; + struct { + CFE_ES_AppInfo_t AppInfo; + uint32 AppId; + } cfe_es_getAppInfo; + struct { + CFE_SB_MsgId_t MsgId; + CFE_SB_PipeId_t PipeId; + CFE_SB_Qos_t Quality; + uint16 MsgLim; + } cfe_sb_subscribeEx; + struct { + CFE_ES_CDSHandle_t CDS_Handle; + int32 BlockSize; + char Name[EMU_BUF_SIZE]; + } cfe_es_registerCDS; + struct { + CFE_ES_CDSHandle_t CDSHandle; + char DataToCopy[EMU_BUF_SIZE]; + } cfe_es_copyToCDS; + struct { + CFE_ES_CDSHandle_t CDSHandle; + char RestoreToMemory[EMU_BUF_SIZE]; + } cfe_es_restoreFromCDS; + struct { + uint32 TaskId; + char TaskName[EMU_BUF_SIZE]; + CFE_ES_ChildTaskMainFuncPtr_t FunctionPtr; + uint32 Priority; + uint32 Flags; + } cfe_es_createChildTask; + struct { + CFE_TBL_Handle_t TblHandle; + char Name[EMU_BUF_SIZE]; + uint32 TblSize; + uint16 TblOptionFlags; + } cfe_tbl_register; + struct { + CFE_TBL_Handle_t TblHandle; + char Buffer[EMU_TBL_BUF_SIZE]; + } cfe_tbl_getAddress; + struct { + CFE_TBL_Handle_t TblHandle; + char Buffer[EMU_TBL_BUF_SIZE]; + } cfe_tbl_modified; + struct { + CFE_TBL_Handle_t TblHandle; + CFE_TBL_SrcEnum_t SrcType; + char SrcData[EMU_TBL_BUF_SIZE]; + } cfe_tbl_load; + struct { + CFE_TBL_Info_t TblInfo; + char TblName[EMU_BUF_SIZE]; + } cfe_tbl_getInfo; + struct { + int32 FileDes; + CFE_FS_Header_t Hdr; + } cfe_fs_readHeader; +}; + +int emu_request_memory(spdid_t client); +arcvcap_t emu_create_aep_thread(spdid_t client, thdclosure_index_t idx, cos_channelkey_t key); + +#define STASH_MAGIC_VALUE ((void *)0xBEAFBEAF) + +void emu_stash(thdclosure_index_t idx, spdid_t spdid); +thdclosure_index_t emu_stash_retrieve_thdclosure(); +spdid_t emu_stash_retrieve_spdid(); +void emu_stash_clear(); + +int emu_is_printf_enabled(); + +int32 emu_CFE_ES_CalculateCRC(spdid_t client); +int32 emu_CFE_ES_CopyToCDS(spdid_t client); +int32 emu_CFE_ES_CreateChildTask(spdid_t client); +int32 emu_CFE_ES_GetAppIDByName(spdid_t client); +int32 emu_CFE_ES_GetAppInfo(spdid_t client); +int32 emu_CFE_ES_GetGenCount(spdid_t client); +int32 emu_CFE_ES_GetGenCounterIDByName(spdid_t client); +int32 emu_CFE_ES_GetResetType(spdid_t client); +int32 emu_CFE_ES_GetTaskInfo(spdid_t client); +int32 emu_CFE_ES_RegisterCDS(spdid_t client); +int32 emu_CFE_ES_RestoreFromCDS(spdid_t client); +int32 emu_CFE_ES_RunLoop(spdid_t client); +int32 emu_CFE_ES_WriteToSysLog(spdid_t client); + +int32 emu_CFE_EVS_Register(spdid_t sp); +int32 emu_CFE_EVS_SendEvent(spdid_t client); + +int32 emu_CFE_FS_Decompress(spdid_t client); +int32 emu_CFE_FS_ReadHeader(spdid_t client); +int32 emu_CFE_FS_WriteHeader(spdid_t client); + +int32 emu_CFE_SB_CreatePipe(spdid_t client); +uint16 emu_CFE_SB_GetCmdCode(spdid_t client); +CFE_SB_MsgId_t emu_CFE_SB_GetMsgId(spdid_t client); +void emu_CFE_SB_GetMsgTime(spdid_t client); +uint16 emu_CFE_SB_GetTotalMsgLength(spdid_t client); +void emu_CFE_SB_InitMsg(spdid_t client); +int32 emu_CFE_SB_RcvMsg(spdid_t client); +int32 emu_CFE_SB_SetCmdCode(spdid_t client); +int32 emu_CFE_SB_SendMsg(spdid_t client); +int32 emu_CFE_SB_SubscribeEx(spdid_t client); +void emu_CFE_SB_TimeStampMsg(spdid_t client); +boolean emu_CFE_SB_ValidateChecksum(spdid_t client); + +int32 emu_CFE_TBL_GetAddress(spdid_t client); +int32 emu_CFE_TBL_GetInfo(spdid_t client); +int32 emu_CFE_TBL_Load(spdid_t client); +int32 emu_CFE_TBL_Modified(spdid_t client); +int32 emu_CFE_TBL_Register(spdid_t client); + +void emu_CFE_TIME_Add(spdid_t client); +void emu_CFE_TIME_Compare(spdid_t client); +void emu_CFE_TIME_GetTime(spdid_t client); +void emu_CFE_TIME_Print(spdid_t client); +int32 emu_CFE_TIME_RegisterSynchCallback(cos_channelkey_t key); + +int32 emu_OS_cp(spdid_t client); +int32 emu_OS_creat(spdid_t client); +int32 emu_OS_FDGetInfo(spdid_t client); +int32 emu_OS_fsBytesFree(spdid_t client); +int32 emu_OS_mkdir(spdid_t client); +int32 emu_OS_mv(spdid_t client); +int32 emu_OS_open(spdid_t client); +os_dirp_t emu_OS_opendir(spdid_t client); +int32 emu_OS_read(spdid_t client); +void emu_OS_readdir(spdid_t client); +int32 emu_OS_remove(spdid_t client); +int32 emu_OS_rename(spdid_t client); +int32 emu_OS_rmdir(spdid_t client); +int32 emu_OS_stat(spdid_t client); +int32 emu_OS_write(spdid_t client); + +int32 emu_OS_BinSemCreate(spdid_t client); +int32 emu_OS_CountSemCreate(spdid_t client); +int32 emu_OS_MutSemCreate(spdid_t client); +int32 emu_OS_TaskGetIdByName(spdid_t client); + +int32 emu_OS_SymbolLookup(spdid_t client); + +#endif diff --git a/src/components/interface/cFE/stubs/c_stub.c b/src/components/interface/cFE/stubs/c_stub.c new file mode 100644 index 0000000000..3ffe69d512 --- /dev/null +++ b/src/components/interface/cFE/stubs/c_stub.c @@ -0,0 +1,988 @@ +#include + +#include +#include +#include +#include +#include +#include +#include "../interface/capmgr/memmgr.h" + +#include + +#define BASE_AEP_KEY 0xBEAFCAFE + +union shared_region *shared_region; +spdid_t spdid; +cos_channelkey_t time_sync_key; + +/* We could copy this from the cFE, but it's zero intialized there + * Also it's totally unused (according to cFE documentation) + */ +CFE_SB_Qos_t CFE_SB_Default_Qos = {0}; + +size_t CDS_sizes[CFE_ES_CDS_MAX_NUM_ENTRIES] = {0}; + +int sync_callbacks_are_setup = 0; +arcvcap_t sync_callback_rcv = 0; +CFE_TIME_SynchCallbackPtr_t sync_callbacks[CFE_TIME_MAX_NUM_SYNCH_FUNCS]; + +void +do_emulation_setup(spdid_t id) +{ + vaddr_t client_addr; + int region_id = emu_request_memory(id); + + spdid = id; + + memmgr_shared_page_map(region_id, &client_addr); + assert(client_addr); + shared_region = (void *)client_addr; + + time_sync_key = BASE_AEP_KEY + id; + + /* End with a quick consistency check */ + assert(sizeof(union shared_region) <= SHARED_REGION_NUM_PAGES * PAGE_SIZE); +} + +void +handle_sync_callbacks(void *data) +{ + int pending; + + while (1) { + assert(sync_callback_rcv); + pending = cos_rcv(sync_callback_rcv, 0, NULL); + if (pending) { + int i; + for (i = 0; i < CFE_TIME_MAX_NUM_SYNCH_FUNCS; i++) { + if (sync_callbacks[i]) { sync_callbacks[i](); } + } + } + } +} + +void +ensure_sync_callbacks_are_setup() +{ + if (!sync_callbacks_are_setup) { + int32 result; + thdclosure_index_t idx = cos_thd_init_alloc(handle_sync_callbacks, NULL); + sync_callback_rcv = emu_create_aep_thread(spdid, idx, time_sync_key); + + result = emu_CFE_TIME_RegisterSynchCallback(time_sync_key); + assert(result == CFE_SUCCESS); + sync_callbacks_are_setup = 1; + } +} + + +/* FIXME: Be more careful about user supplied pointers + * FIXME: Take a lock in each function, so shared memory can't be corrupted + * FIXME: Don't pass spdid, use the builtin functionality instead + */ +uint32 +CFE_ES_CalculateCRC(const void *DataPtr, uint32 DataLength, uint32 InputCRC, uint32 TypeCRC) +{ + assert(DataLength < EMU_BUF_SIZE); + memcpy(shared_region->cfe_es_calculateCRC.Data, DataPtr, DataLength); + shared_region->cfe_es_calculateCRC.InputCRC = InputCRC; + shared_region->cfe_es_calculateCRC.TypeCRC = TypeCRC; + return emu_CFE_ES_CalculateCRC(spdid); +} + +int32 +CFE_ES_CopyToCDS(CFE_ES_CDSHandle_t CDSHandle, void *DataToCopy) +{ + size_t data_size; + + /* CDSHandle is unsigned, so it can't be invalid by being negative */ + assert(CDSHandle < CFE_ES_CDS_MAX_NUM_ENTRIES); + + shared_region->cfe_es_copyToCDS.CDSHandle = CDSHandle; + + data_size = CDS_sizes[CDSHandle]; + assert(data_size <= EMU_BUF_SIZE); + memcpy(shared_region->cfe_es_copyToCDS.DataToCopy, DataToCopy, data_size); + return emu_CFE_ES_CopyToCDS(spdid); +} + +int32 +CFE_ES_CreateChildTask(uint32 *TaskIdPtr, const char *TaskName, CFE_ES_ChildTaskMainFuncPtr_t FunctionPtr, + uint32 *StackPtr, uint32 StackSize, uint32 Priority, uint32 Flags) +{ + int32 result; + thdclosure_index_t idx = cos_thd_init_alloc(FunctionPtr, NULL); + + assert(strlen(TaskName) < EMU_BUF_SIZE); + strcpy(shared_region->cfe_es_createChildTask.TaskName, TaskName); + + emu_stash(idx, spdid); + + shared_region->cfe_es_createChildTask.FunctionPtr = STASH_MAGIC_VALUE; + shared_region->cfe_es_createChildTask.Priority = Priority; + shared_region->cfe_es_createChildTask.Flags = Flags; + + result = emu_CFE_ES_CreateChildTask(spdid); + *TaskIdPtr = shared_region->cfe_es_createChildTask.TaskId; + + emu_stash_clear(); + + return result; +} + +int32 +CFE_ES_GetAppIDByName(uint32 *AppIdPtr, const char *AppName) +{ + int32 result; + + assert(strlen(AppName) < EMU_BUF_SIZE); + + strcpy(shared_region->cfe_es_getAppIDByName.AppName, AppName); + result = emu_CFE_ES_GetAppIDByName(spdid); + *AppIdPtr = shared_region->cfe_es_getAppIDByName.AppId; + + return result; +} + +int32 +CFE_ES_GetAppInfo(CFE_ES_AppInfo_t *AppInfo, uint32 AppId) +{ + int32 result; + + shared_region->cfe_es_getAppInfo.AppId = AppId; + result = emu_CFE_ES_GetAppInfo(spdid); + *AppInfo = shared_region->cfe_es_getAppInfo.AppInfo; + + return result; +} + +int32 +CFE_ES_GetGenCount(uint32 CounterId, uint32 *Count) +{ + int32 result; + + shared_region->cfe_es_getGenCount.CounterId = CounterId; + result = emu_CFE_ES_GetGenCount(spdid); + *Count = shared_region->cfe_es_getGenCount.Count; + + return result; +} + +int32 +CFE_ES_GetGenCounterIDByName(uint32 *CounterIdPtr, const char *CounterName) +{ + int32 result; + + strcpy(shared_region->cfe_es_getGenCounterIDByName.CounterName, CounterName); + result = emu_CFE_ES_GetGenCounterIDByName(spdid); + *CounterIdPtr = shared_region->cfe_es_getGenCounterIDByName.CounterId; + + return result; +} + +int32 +CFE_ES_GetResetType(uint32 *ResetSubtypePtr) +{ + int32 result; + + result = emu_CFE_ES_GetResetType(spdid); + + if (ResetSubtypePtr) { + *ResetSubtypePtr = shared_region->cfe_es_getResetType.ResetSubtype; + } + + return result; +} + +int32 +CFE_ES_GetTaskInfo(CFE_ES_TaskInfo_t *TaskInfo, uint32 TaskId) +{ + int32 result; + + shared_region->cfe_es_getTaskInfo.TaskId = TaskId; + result = emu_CFE_ES_GetTaskInfo(spdid); + *TaskInfo = shared_region->cfe_es_getTaskInfo.TaskInfo; + return result; +} + +int32 +CFE_ES_RegisterCDS(CFE_ES_CDSHandle_t *HandlePtr, int32 BlockSize, const char *Name) +{ + int32 result; + + assert(strlen(Name) < EMU_BUF_SIZE); + + shared_region->cfe_es_registerCDS.BlockSize = BlockSize; + strcpy(shared_region->cfe_es_registerCDS.Name, Name); + + result = emu_CFE_ES_RegisterCDS(spdid); + if (result == CFE_SUCCESS) { + CFE_ES_CDSHandle_t handle = shared_region->cfe_es_registerCDS.CDS_Handle; + CDS_sizes[handle] = BlockSize; + *HandlePtr = handle; + } + return result; +} + +int32 +CFE_ES_RestoreFromCDS(void *RestoreToMemory, CFE_ES_CDSHandle_t CDSHandle) +{ + int32 result; + size_t data_size; + + shared_region->cfe_es_restoreFromCDS.CDSHandle = CDSHandle; + + result = emu_CFE_ES_RestoreFromCDS(spdid); + + if (result == CFE_SUCCESS) { + /* CDSHandle is unsigned, so it can't be invalid by being negative */ + assert(CDSHandle < CFE_ES_CDS_MAX_NUM_ENTRIES); + data_size = CDS_sizes[CDSHandle]; + assert(data_size <= EMU_BUF_SIZE); + + memcpy(RestoreToMemory, shared_region->cfe_es_restoreFromCDS.RestoreToMemory, data_size); + } + + return result; +} + +int32 +CFE_ES_RunLoop(uint32 *RunStatus) +{ + int32 result; + + shared_region->cfe_es_runLoop.RunStatus = *RunStatus; + result = emu_CFE_ES_RunLoop(spdid); + *RunStatus = shared_region->cfe_es_runLoop.RunStatus; + return result; +} + +int32 +CFE_ES_WriteToSysLog(const char *SpecStringPtr, ...) +{ + va_list arg_ptr; + int ret, len = OS_BUFFER_SIZE; + + va_start(arg_ptr, SpecStringPtr); + vsnprintf(shared_region->cfe_es_writeToSysLog.String, len, SpecStringPtr, arg_ptr); + va_end(arg_ptr); + return emu_CFE_ES_WriteToSysLog(spdid); +} + +int32 CFE_EVS_Register(void * Filters, /* Pointer to an array of filters */ + uint16 NumFilteredEvents, /* How many elements in the array? */ + uint16 FilterScheme) /* Filtering Algorithm to be implemented */ +{ + int i; + CFE_EVS_BinFilter_t *bin_filters; + + if (FilterScheme != CFE_EVS_BINARY_FILTER) { return CFE_EVS_UNKNOWN_FILTER; } + bin_filters = Filters; + + for (i = 0; i < NumFilteredEvents; i++) { shared_region->cfe_evs_register.filters[i] = bin_filters[i]; } + + shared_region->cfe_evs_register.NumEventFilters = NumFilteredEvents; + shared_region->cfe_evs_register.FilterScheme = FilterScheme; + + return emu_CFE_EVS_Register(spdid); +} + + +int32 +CFE_EVS_SendEvent(uint16 EventID, uint16 EventType, const char *Spec, ...) +{ + va_list Ptr; + va_start(Ptr, Spec); + vsnprintf(shared_region->cfe_evs_sendEvent.Msg, sizeof(shared_region->cfe_evs_sendEvent.Msg), Spec, Ptr); + va_end(Ptr); + + shared_region->cfe_evs_sendEvent.EventID = EventID; + shared_region->cfe_evs_sendEvent.EventType = EventType; + + return emu_CFE_EVS_SendEvent(spdid); +} + +int32 +CFE_FS_Decompress(const char *SourceFile, const char *DestinationFile) +{ + assert(strlen(SourceFile) < EMU_BUF_SIZE); + assert(strlen(DestinationFile) < EMU_BUF_SIZE); + + strcpy(shared_region->cfe_fs_decompress.SourceFile, SourceFile); + strcpy(shared_region->cfe_fs_decompress.DestinationFile, DestinationFile); + return emu_CFE_FS_Decompress(spdid); +} + +int32 +CFE_FS_ReadHeader(CFE_FS_Header_t *Hdr, int32 FileDes) +{ + int32 result; + + shared_region->cfe_fs_readHeader.FileDes = FileDes; + + result = emu_CFE_FS_ReadHeader(spdid); + *Hdr = shared_region->cfe_fs_readHeader.Hdr; + + return result; +} + +int32 +CFE_FS_WriteHeader(int32 FileDes, CFE_FS_Header_t *Hdr) +{ + int32 result; + shared_region->cfe_fs_writeHeader.FileDes = FileDes; + result = emu_CFE_FS_WriteHeader(spdid); + *Hdr = shared_region->cfe_fs_writeHeader.Hdr; + return result; +} + +int32 +CFE_PSP_MemCpy(void *dest, void *src, uint32 n) +{ + memcpy(dest, src, n); + return CFE_PSP_SUCCESS; +} + +int32 +CFE_PSP_MemRead8(cpuaddr MemoryAddress, uint8 *ByteValue) +{ + + *ByteValue = *((uint8 *)MemoryAddress) ; + + return CFE_PSP_SUCCESS; +} + +int32 +CFE_PSP_MemRead16(cpuaddr MemoryAddress, uint16 *uint16Value) +{ + /* check 16 bit alignment */ + if (MemoryAddress & 0x00000001) { + return CFE_PSP_ERROR_ADDRESS_MISALIGNED; + } + *uint16Value = *((uint16 *)MemoryAddress) ; + return CFE_PSP_SUCCESS; +} + +int32 +CFE_PSP_MemRead32(cpuaddr MemoryAddress, uint32 *uint32Value) +{ + /* check 32 bit alignment */ + if (MemoryAddress & 0x00000003) { + return CFE_PSP_ERROR_ADDRESS_MISALIGNED; + } + *uint32Value = *((uint32 *)MemoryAddress); + + return CFE_PSP_SUCCESS; +} + +int32 +CFE_PSP_MemSet(void *dest, uint8 value, uint32 n) +{ + memset(dest, value, n); + return CFE_PSP_SUCCESS; +} + + +int32 +CFE_PSP_MemWrite8(cpuaddr MemoryAddress, uint8 ByteValue) +{ + *((uint8 *)MemoryAddress) = ByteValue; + return CFE_PSP_SUCCESS; + +} + +int32 +CFE_PSP_MemWrite16(cpuaddr MemoryAddress, uint16 uint16Value ) +{ + /* check 16 bit alignment , check the 1st lsb */ + if (MemoryAddress & 0x00000001) { + return CFE_PSP_ERROR_ADDRESS_MISALIGNED; + } + *((uint16 *)MemoryAddress) = uint16Value; + return CFE_PSP_SUCCESS; +} + +int32 +CFE_PSP_MemWrite32(cpuaddr MemoryAddress, uint32 uint32Value) +{ + /* check 32 bit alignment */ + if (MemoryAddress & 0x00000003) { + return CFE_PSP_ERROR_ADDRESS_MISALIGNED; + } + + *((uint32 *)MemoryAddress) = uint32Value; + + return CFE_PSP_SUCCESS; +} + +int32 +CFE_SB_CreatePipe(CFE_SB_PipeId_t *PipeIdPtr, uint16 Depth, const char *PipeName) +{ + int32 result; + + shared_region->cfe_sb_createPipe.Depth = Depth; + strncpy(shared_region->cfe_sb_createPipe.PipeName, PipeName, OS_MAX_API_NAME); + result = emu_CFE_SB_CreatePipe(spdid); + *PipeIdPtr = shared_region->cfe_sb_createPipe.PipeId; + return result; +} + +uint16 +CFE_SB_GetCmdCode(CFE_SB_MsgPtr_t MsgPtr) +{ + char * msg_ptr; + uint16 msg_len = CFE_SB_GetTotalMsgLength(MsgPtr); + + assert(msg_len <= EMU_BUF_SIZE); + msg_ptr = (char *)MsgPtr; + memcpy(shared_region->cfe_sb_msg.Msg, msg_ptr, (size_t)msg_len); + return emu_CFE_SB_GetCmdCode(spdid); +} + +CFE_SB_MsgId_t +CFE_SB_GetMsgId(CFE_SB_MsgPtr_t MsgPtr) +{ + char * msg_ptr; + uint16 msg_len = CFE_SB_GetTotalMsgLength(MsgPtr); + + assert(msg_len <= EMU_BUF_SIZE); + msg_ptr = (char *)MsgPtr; + memcpy(shared_region->cfe_sb_msg.Msg, msg_ptr, (size_t)msg_len); + return emu_CFE_SB_GetMsgId(spdid); +} + + +CFE_TIME_SysTime_t +CFE_SB_GetMsgTime(CFE_SB_MsgPtr_t MsgPtr) +{ + char * msg_ptr; + uint16 msg_len = CFE_SB_GetTotalMsgLength(MsgPtr); + + assert(msg_len <= EMU_BUF_SIZE); + msg_ptr = (char *)MsgPtr; + memcpy(shared_region->cfe_sb_msg.Msg, msg_ptr, (size_t)msg_len); + emu_CFE_SB_GetMsgTime(spdid); + return shared_region->time; +} + +uint16 +CFE_SB_GetTotalMsgLength(CFE_SB_MsgPtr_t MsgPtr) +{ + shared_region->cfe_sb_getMsgLen.Msg = *MsgPtr; + return emu_CFE_SB_GetTotalMsgLength(spdid); +} + +void +CFE_SB_InitMsg(void *MsgPtr, CFE_SB_MsgId_t MsgId, uint16 Length, boolean Clear) +{ + char *source = MsgPtr; + assert(Length <= EMU_BUF_SIZE); + memcpy(shared_region->cfe_sb_initMsg.MsgBuffer, source, Length); + shared_region->cfe_sb_initMsg.MsgId = MsgId; + shared_region->cfe_sb_initMsg.Length = Length; + shared_region->cfe_sb_initMsg.Clear = Clear; + emu_CFE_SB_InitMsg(spdid); + memcpy(source, shared_region->cfe_sb_initMsg.MsgBuffer, Length); +} + +/* + * We want the msg to live in this app, not the cFE component + * But the message is stored in a buffer on the cFE side + * The slution is to copy it into a buffer here + * According to the cFE spec, this buffer only needs to last till the pipe is used again + * Therefore one buffer per pipe is acceptable + */ +struct { + char buf[EMU_BUF_SIZE]; +} pipe_buffers[CFE_SB_MAX_PIPES]; + +int32 +CFE_SB_RcvMsg(CFE_SB_MsgPtr_t *BufPtr, CFE_SB_PipeId_t PipeId, int32 TimeOut) +{ + int32 result; + + shared_region->cfe_sb_rcvMsg.PipeId = PipeId; + shared_region->cfe_sb_rcvMsg.TimeOut = TimeOut; + result = emu_CFE_SB_RcvMsg(spdid); + + if (result == CFE_SUCCESS) { + memcpy(pipe_buffers[PipeId].buf, shared_region->cfe_sb_rcvMsg.Msg, EMU_BUF_SIZE); + *BufPtr = (CFE_SB_MsgPtr_t)pipe_buffers[PipeId].buf; + } + + return result; +} + +int32 +CFE_SB_SetCmdCode(CFE_SB_MsgPtr_t MsgPtr, uint16 CmdCode) +{ + int32 result; + char * msg_ptr; + uint16 msg_len = CFE_SB_GetTotalMsgLength(MsgPtr); + + assert(msg_len <= EMU_BUF_SIZE); + msg_ptr = (char *)MsgPtr; + + memcpy(shared_region->cfe_sb_setCmdCode.Msg, msg_ptr, (size_t)msg_len); + shared_region->cfe_sb_setCmdCode.CmdCode = CmdCode; + + result = emu_CFE_SB_SetCmdCode(spdid); + /* TODO: Verify we can assume the msg_len won't change */ + memcpy(msg_ptr, shared_region->cfe_sb_setCmdCode.Msg, msg_len); + return result; +} + +int32 +CFE_SB_SendMsg(CFE_SB_Msg_t *MsgPtr) +{ + char * msg_ptr; + uint16 msg_len = CFE_SB_GetTotalMsgLength(MsgPtr); + + assert(msg_len <= EMU_BUF_SIZE); + msg_ptr = (char *)MsgPtr; + memcpy(shared_region->cfe_sb_msg.Msg, msg_ptr, (size_t)msg_len); + + return emu_CFE_SB_SendMsg(spdid); +} + +int32 +CFE_SB_SubscribeEx(CFE_SB_MsgId_t MsgId, CFE_SB_PipeId_t PipeId, CFE_SB_Qos_t Quality, uint16 MsgLim) +{ + shared_region->cfe_sb_subscribeEx.MsgId = MsgId; + shared_region->cfe_sb_subscribeEx.PipeId = PipeId; + shared_region->cfe_sb_subscribeEx.Quality = Quality; + shared_region->cfe_sb_subscribeEx.MsgLim = MsgLim; + return emu_CFE_SB_SubscribeEx(spdid); +} + +void +CFE_SB_TimeStampMsg(CFE_SB_MsgPtr_t MsgPtr) +{ + char * msg_ptr; + uint16 msg_len = CFE_SB_GetTotalMsgLength(MsgPtr); + + assert(msg_len <= EMU_BUF_SIZE); + msg_ptr = (char *)MsgPtr; + memcpy(shared_region->cfe_sb_msg.Msg, msg_ptr, (size_t)msg_len); + emu_CFE_SB_TimeStampMsg(spdid); + memcpy(msg_ptr, shared_region->cfe_sb_msg.Msg, (size_t)msg_len); +} + +boolean +CFE_SB_ValidateChecksum(CFE_SB_MsgPtr_t MsgPtr) +{ + char * msg_ptr; + uint16 msg_len = CFE_SB_GetTotalMsgLength(MsgPtr); + + assert(msg_len <= EMU_BUF_SIZE); + msg_ptr = (char *)MsgPtr; + memcpy(shared_region->cfe_sb_msg.Msg, msg_ptr, (size_t)msg_len); + + return emu_CFE_SB_ValidateChecksum(spdid); +} + +struct { + size_t size; + char buffer[EMU_TBL_BUF_SIZE]; +} table_info[CFE_TBL_MAX_NUM_HANDLES]; + +int32 +CFE_TBL_GetAddress(void **TblPtr, CFE_TBL_Handle_t TblHandle) +{ + int32 result; + + shared_region->cfe_tbl_getAddress.TblHandle = TblHandle; + + result = emu_CFE_TBL_GetAddress(spdid); + + if (result == CFE_SUCCESS || result == CFE_TBL_INFO_UPDATED) { + memcpy(table_info[TblHandle].buffer, shared_region->cfe_tbl_getAddress.Buffer, + table_info[TblHandle].size); + + *TblPtr = table_info[TblHandle].buffer; + } + + return result; +} + +int32 +CFE_TBL_GetInfo(CFE_TBL_Info_t *TblInfoPtr, const char *TblName) +{ + int32 result; + + assert(strlen(TblName) < EMU_BUF_SIZE); + strcpy(shared_region->cfe_tbl_getInfo.TblName, TblName); + + result = emu_CFE_TBL_GetInfo(spdid); + if (result == CFE_SUCCESS) { *TblInfoPtr = shared_region->cfe_tbl_getInfo.TblInfo; } + return result; +} + +int32 +CFE_TBL_Load(CFE_TBL_Handle_t TblHandle, CFE_TBL_SrcEnum_t SrcType, const void *SrcDataPtr) +{ + shared_region->cfe_tbl_load.TblHandle = TblHandle; + shared_region->cfe_tbl_load.SrcType = SrcType; + + if (SrcType == CFE_TBL_SRC_FILE) { + assert(strlen(SrcDataPtr) < EMU_TBL_BUF_SIZE); + strcpy(shared_region->cfe_tbl_load.SrcData, SrcDataPtr); + } else if (SrcType == CFE_TBL_SRC_ADDRESS) { + assert(TblHandle < CFE_TBL_MAX_NUM_HANDLES); + memcpy(shared_region->cfe_tbl_load.SrcData, SrcDataPtr, table_info[TblHandle].size); + } else { + return CFE_TBL_ERR_ILLEGAL_SRC_TYPE; + } + return emu_CFE_TBL_Load(spdid); +} + +int32 +CFE_TBL_Modified(CFE_TBL_Handle_t TblHandle) +{ + assert(TblHandle < CFE_TBL_MAX_NUM_HANDLES); + memcpy(shared_region->cfe_tbl_modified.Buffer, table_info[TblHandle].buffer, table_info[TblHandle].size); + + shared_region->cfe_tbl_modified.TblHandle = TblHandle; + + return emu_CFE_TBL_Modified(spdid); +} + +int32 +CFE_TBL_Register(CFE_TBL_Handle_t *TblHandlePtr, const char *Name, uint32 TblSize, uint16 TblOptionFlags, + CFE_TBL_CallbackFuncPtr_t TblValidationFuncPtr) +{ + int32 result; + + assert(strlen(Name) < EMU_BUF_SIZE); + + strcpy(shared_region->cfe_tbl_register.Name, Name); + shared_region->cfe_tbl_register.TblSize = TblSize; + shared_region->cfe_tbl_register.TblOptionFlags = TblOptionFlags; + /* FIXME: Validation callbacks barely matter, implement them later */ + + result = emu_CFE_TBL_Register(spdid); + if (result == CFE_SUCCESS || result == CFE_TBL_INFO_RECOVERED_TBL) { + assert(TblSize <= EMU_TBL_BUF_SIZE); + + table_info[shared_region->cfe_tbl_register.TblHandle].size = TblSize; + *TblHandlePtr = shared_region->cfe_tbl_register.TblHandle; + } + + return result; +} + +CFE_TIME_SysTime_t +CFE_TIME_Add(CFE_TIME_SysTime_t Time1, CFE_TIME_SysTime_t Time2) +{ + shared_region->cfe_time_add.Time1 = Time1; + shared_region->cfe_time_add.Time2 = Time2; + emu_CFE_TIME_Add(spdid); + return shared_region->cfe_time_add.Result; +} + +CFE_TIME_Compare_t +CFE_TIME_Compare(CFE_TIME_SysTime_t Time1, CFE_TIME_SysTime_t Time2) +{ + shared_region->cfe_time_compare.Time1 = Time1; + shared_region->cfe_time_compare.Time2 = Time2; + emu_CFE_TIME_Compare(spdid); + return shared_region->cfe_time_compare.Result; +} + +CFE_TIME_SysTime_t +CFE_TIME_GetTime(void) +{ + emu_CFE_TIME_GetTime(spdid); + return shared_region->time; +} + +void +CFE_TIME_Print(char *PrintBuffer, CFE_TIME_SysTime_t TimeToPrint) +{ + shared_region->cfe_time_print.TimeToPrint = TimeToPrint; + emu_CFE_TIME_Print(spdid); + memcpy(PrintBuffer, shared_region->cfe_time_print.PrintBuffer, CFE_TIME_PRINTED_STRING_SIZE); +} + +int32 +CFE_TIME_RegisterSynchCallback(CFE_TIME_SynchCallbackPtr_t CallbackFuncPtr) +{ + int i; + + ensure_sync_callbacks_are_setup(); + + for (i = 0; i < CFE_TIME_MAX_NUM_SYNCH_FUNCS; i++) { + if (!sync_callbacks[i]) { + sync_callbacks[i] = CallbackFuncPtr; + return CFE_SUCCESS; + } + } + return CFE_TIME_TOO_MANY_SYNCH_CALLBACKS; +} + +int32 +CFE_TIME_UnregisterSynchCallback(CFE_TIME_SynchCallbackPtr_t CallbackFuncPtr) +{ + int i; + for (i = 0; i < CFE_TIME_MAX_NUM_SYNCH_FUNCS; i++) { + if (sync_callbacks[i] == CallbackFuncPtr) { + sync_callbacks[i] = NULL; + return CFE_SUCCESS; + } + } + return CFE_TIME_CALLBACK_NOT_REGISTERED; +} + +int32 +OS_cp(const char *src, const char *dest) +{ + assert(strlen(src) < EMU_BUF_SIZE); + assert(strlen(dest) < EMU_BUF_SIZE); + strcpy(shared_region->os_cp.src, src); + strcpy(shared_region->os_cp.dest, dest); + return emu_OS_cp(spdid); +} + +int32 +OS_creat(const char *path, int32 access) +{ + assert(strlen(path) < EMU_BUF_SIZE); + + strcpy(shared_region->os_creat.path, path); + shared_region->os_creat.access = access; + return emu_OS_creat(spdid); +} + +int32 +OS_FDGetInfo(int32 filedes, OS_FDTableEntry *fd_prop) +{ + int32 result; + + shared_region->os_FDGetInfo.filedes = filedes; + result = emu_OS_FDGetInfo(spdid); + *fd_prop = shared_region->os_FDGetInfo.fd_prop; + return result; +} + +int32 +OS_fsBytesFree(const char *name, uint64 *bytes_free) +{ + int32 result; + + assert(strlen(name) < EMU_BUF_SIZE); + + strcpy(shared_region->os_fsBytesFree.name, name); + result = emu_OS_fsBytesFree(spdid); + *bytes_free = shared_region->os_fsBytesFree.bytes_free; + + return result; +} + +int32 +OS_mkdir(const char *path, uint32 access) +{ + assert(strlen(path) < EMU_BUF_SIZE); + + strcpy(shared_region->os_mkdir.path, path); + shared_region->os_mkdir.access = access; + return emu_OS_mkdir(spdid); +} + +int32 +OS_mv(const char *src, const char *dest) +{ + assert(strlen(src) < EMU_BUF_SIZE); + assert(strlen(dest) < EMU_BUF_SIZE); + + strcpy(shared_region->os_mv.src, src); + strcpy(shared_region->os_mv.dest, dest); + return emu_OS_mv(spdid); +} + +int32 +OS_open(const char *path, int32 access, uint32 mode) +{ + assert(strlen(path) < EMU_BUF_SIZE); + + strcpy(shared_region->os_open.path, path); + shared_region->os_open.access = access; + shared_region->os_open.mode = mode; + + return emu_OS_open(spdid); +} + +os_dirp_t +OS_opendir(const char *path) +{ + assert(strlen(path) < EMU_BUF_SIZE); + + strcpy(shared_region->os_opendir.path, path); + return emu_OS_opendir(spdid); +} + +int32 +OS_read(int32 filedes, void *buffer, uint32 nbytes) +{ + int32 result; + + assert(nbytes <= EMU_BUF_SIZE); + + shared_region->os_read.filedes = filedes; + shared_region->os_read.nbytes = nbytes; + result = emu_OS_read(spdid); + memcpy(buffer, shared_region->os_read.buffer, nbytes); + return result; +} + +int32 +OS_remove(const char *path) +{ + assert(strlen(path) < EMU_BUF_SIZE); + + strcpy(shared_region->os_remove.path, path); + return emu_OS_remove(spdid); +} + + +os_dirent_t buffered_dirent; + +os_dirent_t * +OS_readdir(os_dirp_t directory) +{ + shared_region->os_readdir.directory = directory; + emu_OS_readdir(spdid); + buffered_dirent = shared_region->os_readdir.dirent; + return &buffered_dirent; +} + +int32 +OS_rename(const char *old_filename, const char *new_filename) +{ + assert(strlen(old_filename) < EMU_BUF_SIZE); + assert(strlen(new_filename) < EMU_BUF_SIZE); + + strcpy(shared_region->os_rename.old_filename, old_filename); + strcpy(shared_region->os_rename.new_filename, new_filename); + return emu_OS_rename(spdid); +} + +int32 +OS_rmdir(const char *path) +{ + assert(strlen(path) < EMU_BUF_SIZE); + + strcpy(shared_region->os_rmdir.path, path); + return emu_OS_rmdir(spdid); +} + +int32 +OS_stat(const char *path, os_fstat_t *filestats) +{ + int32 result; + + assert(strlen(path) < EMU_BUF_SIZE); + + strcpy(shared_region->os_stat.path, path); + result = emu_OS_stat(spdid); + *filestats = shared_region->os_stat.filestats; + return result; +} + +int32 +OS_write(int32 filedes, void *buffer, uint32 nbytes) +{ + assert(nbytes < EMU_BUF_SIZE); + shared_region->os_write.filedes = filedes; + memcpy(shared_region->os_write.buffer, buffer, nbytes); + shared_region->os_write.nbytes = nbytes; + return emu_OS_write(spdid); +} + +int32 +OS_BinSemCreate(uint32 *sem_id, const char *sem_name, uint32 sem_initial_value, uint32 options) +{ + int32 result; + + assert(strlen(sem_name) < EMU_BUF_SIZE); + + strcpy(shared_region->os_semCreate.sem_name, sem_name); + shared_region->os_semCreate.sem_initial_value = sem_initial_value; + shared_region->os_semCreate.options = options; + result = emu_OS_BinSemCreate(spdid); + *sem_id = shared_region->os_semCreate.sem_id; + return result; +} + +int32 +OS_CountSemCreate(uint32 *sem_id, const char *sem_name, uint32 sem_initial_value, uint32 options) +{ + int32 result; + + assert(strlen(sem_name) < EMU_BUF_SIZE); + + strcpy(shared_region->os_semCreate.sem_name, sem_name); + shared_region->os_semCreate.sem_initial_value = sem_initial_value; + shared_region->os_semCreate.options = options; + result = emu_OS_CountSemCreate(spdid); + *sem_id = shared_region->os_semCreate.sem_id; + return result; +} + +int32 +OS_MutSemCreate(uint32 *sem_id, const char *sem_name, uint32 options) +{ + int32 result; + + assert(strlen(sem_name) < EMU_BUF_SIZE); + + strcpy(shared_region->os_mutSemCreate.sem_name, sem_name); + shared_region->os_mutSemCreate.options = options; + result = emu_OS_MutSemCreate(spdid); + *sem_id = shared_region->os_mutSemCreate.sem_id; + + return result; +} + +int32 +OS_TaskGetIdByName(uint32 *task_id, const char *task_name) +{ + int32 result; + + assert(strlen(task_name) < EMU_BUF_SIZE); + + strcpy(shared_region->os_taskGetIdByName.task_name, task_name); + result = emu_OS_TaskGetIdByName(spdid); + *task_id = shared_region->os_taskGetIdByName.task_id; + return result; +} + +int32 +OS_SymbolLookup(cpuaddr *symbol_address, const char *symbol_name) +{ + int32 result; + + assert(strlen(symbol_name) < EMU_BUF_SIZE); + + strcpy(shared_region->os_symbolLookup.symbol_name, symbol_name); + result = emu_OS_SymbolLookup(spdid); + *symbol_address = shared_region->os_symbolLookup.symbol_address; + return result; +} + +/* Methods that are completly emulated */ + +void +OS_printf(const char *string, ...) +{ + if (emu_is_printf_enabled()) { + char s[OS_BUFFER_SIZE]; + va_list arg_ptr; + int ret, len = OS_BUFFER_SIZE; + + va_start(arg_ptr, string); + ret = vsnprintf(s, len, string, arg_ptr); + va_end(arg_ptr); + cos_llprint(s, ret); + } +} diff --git a/src/components/interface/cFE/stubs/s_stub.S b/src/components/interface/cFE/stubs/s_stub.S new file mode 100644 index 0000000000..f1def0cce7 --- /dev/null +++ b/src/components/interface/cFE/stubs/s_stub.S @@ -0,0 +1,141 @@ +/** + * Copyright 2009 by Gabriel Parmer, gabep1@cs.bu.edu + * + * Redistribution of this file is permitted under the GNU General + * Public License v2. + */ + +#define __ASM__ +#include +#include + +.text + +cos_asm_server_stub(CFE_ES_DeleteApp) +cos_asm_server_stub(CFE_ES_ExitApp) +cos_asm_server_stub(CFE_ES_ExitChildTask) +cos_asm_server_stub(CFE_ES_PerfLogAdd) +cos_asm_server_stub(CFE_ES_RegisterApp) +cos_asm_server_stub(CFE_ES_RegisterChildTask) +cos_asm_server_stub(CFE_ES_ResetCFE) +cos_asm_server_stub(CFE_ES_RestartApp) +cos_asm_server_stub(CFE_ES_WaitForStartupSync) + +cos_asm_server_stub(CFE_PSP_EepromWriteEnable) +cos_asm_server_stub(CFE_PSP_EepromWriteDisable) +cos_asm_server_stub(CFE_PSP_EepromWrite8) +cos_asm_server_stub(CFE_PSP_EepromWrite16) +cos_asm_server_stub(CFE_PSP_EepromWrite32) +cos_asm_server_stub(CFE_PSP_MemValidateRange) +cos_asm_server_stub(CFE_PSP_WatchdogDisable) +cos_asm_server_stub(CFE_PSP_WatchdogEnable) +cos_asm_server_stub(CFE_PSP_WatchdogSet) +cos_asm_server_stub(CFE_PSP_WatchdogService) + +cos_asm_server_stub(CFE_SB_Subscribe) +cos_asm_server_stub(CFE_SB_Unsubscribe) +cos_asm_server_stub(CFE_SB_UnsubscribeLocal) + +cos_asm_server_stub(CFE_TBL_DumpToBuffer) +cos_asm_server_stub(CFE_TBL_GetStatus) +cos_asm_server_stub(CFE_TBL_Manage) +cos_asm_server_stub(CFE_TBL_NotifyByMessage) +cos_asm_server_stub(CFE_TBL_ReleaseAddress) +cos_asm_server_stub(CFE_TBL_Update) +cos_asm_server_stub(CFE_TBL_Validate) + +cos_asm_server_stub(CFE_TIME_FS2CFESeconds) + +cos_asm_server_stub(OS_CountSemGive) +cos_asm_server_stub(OS_CountSemTake) +cos_asm_server_stub(OS_IdleLoop) +cos_asm_server_stub(OS_IntLock) +cos_asm_server_stub(OS_IntUnlock) +cos_asm_server_stub(OS_MutSemGive) +cos_asm_server_stub(OS_MutSemTake) +cos_asm_server_stub(OS_SymbolTableDump) +cos_asm_server_stub(OS_TaskDelay) + +// FS methods +// Relies on the assumption that dirp_t are never dereferenced outside the cFE +cos_asm_server_stub(OS_closedir) +cos_asm_server_stub(OS_close) +cos_asm_server_stub(OS_lseek) +cos_asm_server_stub(OS_rewinddir) + +// Emulated methods +cos_asm_server_stub(emu_request_memory) +cos_asm_server_stub(emu_create_aep_thread) +cos_asm_server_stub(emu_is_printf_enabled) + +cos_asm_server_stub(emu_stash) +cos_asm_server_stub(emu_stash_clear) + +cos_asm_server_stub(emu_CFE_ES_CalculateCRC) +cos_asm_server_stub(emu_CFE_ES_CopyToCDS) +cos_asm_server_stub(emu_CFE_ES_CreateChildTask) +cos_asm_server_stub(emu_CFE_ES_GetAppIDByName) +cos_asm_server_stub(emu_CFE_ES_GetAppInfo) +cos_asm_server_stub(emu_CFE_ES_GetGenCount) +cos_asm_server_stub(emu_CFE_ES_GetGenCounterIDByName) +cos_asm_server_stub(emu_CFE_ES_GetResetType) +cos_asm_server_stub(emu_CFE_ES_GetTaskInfo) +cos_asm_server_stub(emu_CFE_ES_RegisterCDS) +cos_asm_server_stub(emu_CFE_ES_RestoreFromCDS) +cos_asm_server_stub(emu_CFE_ES_RunLoop) +cos_asm_server_stub(emu_CFE_ES_WriteToSysLog) + +cos_asm_server_stub(emu_CFE_EVS_Register) +cos_asm_server_stub(emu_CFE_EVS_SendEvent) + +cos_asm_server_stub(emu_CFE_FS_Decompress) +cos_asm_server_stub(emu_CFE_FS_ReadHeader) +cos_asm_server_stub(emu_CFE_FS_WriteHeader) + +cos_asm_server_stub(emu_CFE_SB_CreatePipe) +cos_asm_server_stub(emu_CFE_SB_GetCmdCode) +cos_asm_server_stub(emu_CFE_SB_GetMsgId) +cos_asm_server_stub(emu_CFE_SB_GetMsgTime) +cos_asm_server_stub(emu_CFE_SB_GetTotalMsgLength) +cos_asm_server_stub(emu_CFE_SB_InitMsg) +cos_asm_server_stub(emu_CFE_SB_RcvMsg) +cos_asm_server_stub(emu_CFE_SB_SetCmdCode) +cos_asm_server_stub(emu_CFE_SB_SendMsg) +cos_asm_server_stub(emu_CFE_SB_SubscribeEx) +cos_asm_server_stub(emu_CFE_SB_TimeStampMsg) +cos_asm_server_stub(emu_CFE_SB_ValidateChecksum) + +cos_asm_server_stub(emu_CFE_TBL_GetInfo) +cos_asm_server_stub(emu_CFE_TBL_GetAddress) +cos_asm_server_stub(emu_CFE_TBL_Modified) +cos_asm_server_stub(emu_CFE_TBL_Register) +cos_asm_server_stub(emu_CFE_TBL_Load) + +cos_asm_server_stub(emu_CFE_TIME_Add) +cos_asm_server_stub(emu_CFE_TIME_Compare) +cos_asm_server_stub(emu_CFE_TIME_GetTime) +cos_asm_server_stub(emu_CFE_TIME_Print) +cos_asm_server_stub(emu_CFE_TIME_RegisterSynchCallback) + +cos_asm_server_stub(emu_OS_cp) +cos_asm_server_stub(emu_OS_creat) +cos_asm_server_stub(emu_OS_FDGetInfo) +cos_asm_server_stub(emu_OS_fsBytesFree) +cos_asm_server_stub(emu_OS_mkdir) +cos_asm_server_stub(emu_OS_open) +cos_asm_server_stub(emu_OS_opendir) +cos_asm_server_stub(emu_OS_mv) +cos_asm_server_stub(emu_OS_read) +cos_asm_server_stub(emu_OS_readdir) +cos_asm_server_stub(emu_OS_remove) +cos_asm_server_stub(emu_OS_rename) +cos_asm_server_stub(emu_OS_rmdir) +cos_asm_server_stub(emu_OS_stat) +cos_asm_server_stub(emu_OS_write) + +cos_asm_server_stub(emu_OS_BinSemCreate) +cos_asm_server_stub(emu_OS_CountSemCreate) +cos_asm_server_stub(emu_OS_MutSemCreate) +cos_asm_server_stub(emu_OS_TaskGetIdByName) + +cos_asm_server_stub(emu_OS_SymbolLookup) diff --git a/src/components/interface/capmgr/stubs/s_stub.S b/src/components/interface/capmgr/stubs/s_stub.S index a7dfb0be87..e53cff35e6 100644 --- a/src/components/interface/capmgr/stubs/s_stub.S +++ b/src/components/interface/capmgr/stubs/s_stub.S @@ -5,6 +5,9 @@ * Author: Phani Gadepalli, phanikishoreg@gwu.edu */ +#define __ASM__ +#include + #include .text diff --git a/src/components/interface/pong/stubs/s_stub.S b/src/components/interface/pong/stubs/s_stub.S index 7d1e1d821f..bc8aa0d9c5 100644 --- a/src/components/interface/pong/stubs/s_stub.S +++ b/src/components/interface/pong/stubs/s_stub.S @@ -4,6 +4,9 @@ * Redistribution of this file is permitted under the GNU General * Public License v2. */ + + #define __ASM__ + #include #include diff --git a/src/components/interface/sched/stubs/s_stub.S b/src/components/interface/sched/stubs/s_stub.S index 1a0010382b..3f657544d9 100644 --- a/src/components/interface/sched/stubs/s_stub.S +++ b/src/components/interface/sched/stubs/s_stub.S @@ -5,6 +5,9 @@ * Author: Phani Gadepalli, phanikishoreg@gwu.edu */ +#define __ASM__ +#include + #include .text diff --git a/src/components/interface/schedinit/stubs/s_stub.S b/src/components/interface/schedinit/stubs/s_stub.S index 4de8c22732..541b613bf0 100644 --- a/src/components/interface/schedinit/stubs/s_stub.S +++ b/src/components/interface/schedinit/stubs/s_stub.S @@ -1,3 +1,5 @@ +#define __ASM__ +#include #include .text diff --git a/src/components/lib/cos_asm_upcall.S b/src/components/lib/cos_asm_upcall.S index f9360174e6..e064d85b58 100644 --- a/src/components/lib/cos_asm_upcall.S +++ b/src/components/lib/cos_asm_upcall.S @@ -8,10 +8,10 @@ */ #define __ASM__ +#include #include "../../kernel/include/asm_ipc_defs.h" #include -#include #define IPRETURN 4 @@ -38,7 +38,7 @@ stkmgr_stack_space: .rep ALL_TMP_STACKS_SZ .long 0 .endr - + .text .globl cos_upcall_entry .type cos_upcall_entry, @function @@ -50,7 +50,7 @@ cos_upcall_entry: pushl %esi pushl %edi pushl %ebx - pushl %ecx /* option */ + pushl %ecx /* option */ call cos_upcall_fn addl $16, %esp @@ -74,7 +74,7 @@ cos_atomic_cmpxchg: movl %ecx, %edx /* XXX */ movl %ecx, (%ebx) .weak cos_atomic_cmpxchg_end -cos_atomic_cmpxchg_end: +cos_atomic_cmpxchg_end: ret /* @@ -103,4 +103,3 @@ cos_atomic_user4_end: /* crash out as something's wrong */ movl $0, %eax movl (%eax), %eax - diff --git a/src/components/lib/cos_component.c b/src/components/lib/cos_component.c index 15f5ab3122..60a7bdb6b1 100644 --- a/src/components/lib/cos_component.c +++ b/src/components/lib/cos_component.c @@ -118,10 +118,11 @@ cos_thd_entry_static(u32_t idx) return 0; } -const char *cos_print_str[PRINT_LEVEL_MAX] = { - "ERR:", - "WARN:", - "DBG:", +const char *cos_print_str[PRINT_LEVEL_COUNT] = { + "ERR: ", + "WARN: ", + "INFO: ", + "DBG: ", }; cos_print_level_t cos_print_level = PRINT_ERROR; diff --git a/src/extern/Makefile b/src/extern/Makefile new file mode 100644 index 0000000000..06e35ba22d --- /dev/null +++ b/src/extern/Makefile @@ -0,0 +1,21 @@ +.PHONY: build, init + +default: build + +init: + $(info ) + $(info ***********************************************) + $(info ********** Setting up External Libs ***********) + $(info ***********************************************) + $(info ) + bash -c 'cd cFE/ && source setvars.sh && make -C build/cpu1 config' + $(shell cd cFE/ && python make.py -p >&2) + + +build: + $(info ) + $(info ***********************************************) + $(info *********** Building External Libs ************) + $(info ***********************************************) + $(info ) + $(shell cd cFE && python make.py >&2) diff --git a/src/extern/cFE b/src/extern/cFE new file mode 160000 index 0000000000..6e6febcde8 --- /dev/null +++ b/src/extern/cFE @@ -0,0 +1 @@ +Subproject commit 6e6febcde8788f900e3d308161ed2bab3e973962 diff --git a/src/kernel/include/shared/consts.h b/src/kernel/include/shared/consts.h index e059c507a7..a6211d65d3 100644 --- a/src/kernel/include/shared/consts.h +++ b/src/kernel/include/shared/consts.h @@ -48,10 +48,10 @@ struct pt_regs { #endif #define MAX_SERVICE_DEPTH 31 -#define MAX_NUM_THREADS (64 * NUM_CPU) +#define MAX_NUM_THREADS (128 * NUM_CPU) /* Stacks are 2 * page_size (expressed in words) */ -#define MAX_STACK_SZ_BYTE_ORDER 12 +#define MAX_STACK_SZ_BYTE_ORDER 13 /* Stack size in bytes */ #define COS_STACK_SZ (1 << MAX_STACK_SZ_BYTE_ORDER) /* Stack size in words */ diff --git a/src/kernel/include/shared/cos_types.h b/src/kernel/include/shared/cos_types.h index f3714097e2..cc6dd4c50a 100644 --- a/src/kernel/include/shared/cos_types.h +++ b/src/kernel/include/shared/cos_types.h @@ -471,7 +471,7 @@ typedef enum { #define IL_INV (~0) typedef unsigned int isolation_level_t; -#define INTERFACE_UNDEF_SYMBS 64 /* maxiumum undefined symbols in a cobj */ +#define INTERFACE_UNDEF_SYMBS 128 /* maxiumum undefined symbols in a cobj */ #define LLBOOT_ROOTSCHED_PRIO 1 /* root scheduler priority for llbooter dispatch */ #define LLBOOT_NEWCOMP_UNTYPED_SZ (1<<24) /* 16 MB = untyped size per component if there is no capability manager */ #define LLBOOT_RESERVED_UNTYPED_SZ (1<<24) /* 16 MB = reserved untyped size with booter if there is a capability manager */ diff --git a/src/platform/i386/runscripts/cFE_booter.sh b/src/platform/i386/runscripts/cFE_booter.sh new file mode 100644 index 0000000000..8d9dd4dff1 --- /dev/null +++ b/src/platform/i386/runscripts/cFE_booter.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cp cFE_booter.o llboot.o +./cos_linker 'llboot.o, ;sample_lib.o, ;sample_app.o, ;sch_lab.o, :sample_app.o-llboot.o;sample_lib.o-llboot.o;sch_lab.o-llboot.o' ./gen_client_stub diff --git a/src/platform/i386/runscripts/llboot_cFE.sh b/src/platform/i386/runscripts/llboot_cFE.sh new file mode 100644 index 0000000000..1c731f431f --- /dev/null +++ b/src/platform/i386/runscripts/llboot_cFE.sh @@ -0,0 +1,8 @@ +# cp llboot_comp.o llboot.o +# cp resmgr.o mm.o +# ./cos_linker 'llboot.o, ;mm.o, ;*cFE_booter.o, ;sample_lib.o, ;sample_app.o, ;sch_lab.o, :cFE_booter.o-mm.o;sample_app.o-cFE_booter.o;sample_lib.o-cFE_booter.o;sch_lab.o-cFE_booter.o' ./gen_client_stub + +cp llboot_comp.o llboot.o +cp cFE_booter.o boot.o +# ds fm sc hs mm +./cos_linker 'llboot.o, ;ds.o, ;capmgr.o, ;fm.o, ;*boot.o, ;sc.o, ;hs.o, ;mm.o, ;sch_lab.o, :boot.o-capmgr.o;ds.o-boot.o;fm.o-boot.o;sc.o-boot.o;hs.o-boot.o;mm.o-boot.o;sch_lab.o-boot.o;ds.o-capmgr.o;fm.o-capmgr.o;sc.o-capmgr.o;hs.o-capmgr.o;mm.o-capmgr.o;sch_lab.o-capmgr.o' ./gen_client_stub diff --git a/tools/Vagrantfile b/tools/Vagrantfile index eb4cdda103..c1b2590ccc 100644 --- a/tools/Vagrantfile +++ b/tools/Vagrantfile @@ -5,8 +5,7 @@ Vagrant.configure(2) do |config| config.vm.box = "ubuntu/trusty32" config.vm.provider "virtualbox" do |v| - v.name = "composite_dev" - v.memory = 1024 + v.memory = 2048 v.cpus = 2 v.customize ["modifyvm", :id, "--paravirtprovider", "kvm"] end @@ -24,6 +23,7 @@ Vagrant.configure(2) do |config| sudo apt-get -y install bc sudo apt-get -y install gcc-multilib sudo apt-get -y install binutils-dev + sudo apt-get -y install binutils-dev sudo apt-get -y install build-essential sudo apt-get -y install qemu-kvm SHELL