t
Fork of mbed-dev by
Diff: platform/mbed_retarget.cpp
- Revision:
- 168:e84263d55307
- Parent:
- 163:74e0ce7f98e8
- Child:
- 169:9672193075cf
--- a/platform/mbed_retarget.cpp Thu Jun 08 15:02:37 2017 +0100 +++ b/platform/mbed_retarget.cpp Wed Jun 21 17:46:44 2017 +0100 @@ -14,7 +14,7 @@ * limitations under the License. */ #include "platform/platform.h" -#include "drivers/FilePath.h" +#include "platform/FilePath.h" #include "hal/serial_api.h" #include "platform/mbed_toolchain.h" #include "platform/mbed_semihost_api.h" @@ -23,20 +23,16 @@ #include "platform/PlatformMutex.h" #include "platform/mbed_error.h" #include "platform/mbed_stats.h" -#if MBED_CONF_FILESYSTEM_PRESENT -#include "filesystem/FileSystem.h" -#include "filesystem/File.h" -#include "filesystem/Dir.h" -#endif +#include "platform/mbed_critical.h" #include <stdlib.h> #include <string.h> +#include <limits.h> #if DEVICE_STDIO_MESSAGES #include <stdio.h> #endif #include <errno.h> #include "platform/mbed_retarget.h" - #if defined(__ARMCC_VERSION) # include <rt_sys.h> # define PREFIX(x) _sys##x @@ -76,7 +72,6 @@ extern const char __stderr_name[] = "/stderr"; #endif -// Heap limits - only used if set unsigned char *mbed_heap_start = 0; uint32_t mbed_heap_size = 0; @@ -85,11 +80,11 @@ * put it in a filehandles array and return the index into that array * (or rather index+3, as filehandles 0-2 are stdin/out/err). */ -static FileLike *filehandles[OPEN_MAX]; +static FileHandle *filehandles[OPEN_MAX]; static SingletonPtr<PlatformMutex> filehandle_mutex; namespace mbed { -void remove_filehandle(FileLike *file) { +void remove_filehandle(FileHandle *file) { filehandle_mutex->lock(); /* Remove all open filehandles for this */ for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { @@ -120,7 +115,20 @@ #endif } -#if MBED_CONF_FILESYSTEM_PRESENT +/** + * Sets errno when file opening fails. + * Wipes out the filehandle too. + * + * @param error is a negative error code returned from an mbed function and + * will be negated to store a positive error code in errno + */ +static int handle_open_errors(int error, unsigned filehandle_idx) { + errno = -error; + // Free file handle + filehandles[filehandle_idx] = NULL; + return -1; +} + static inline int openmode_to_posix(int openmode) { int posix = openmode; #ifdef __ARMCC_VERSION @@ -155,32 +163,6 @@ #endif return posix; } -#endif - -extern "C" WEAK void mbed_sdk_init(void); -extern "C" WEAK void mbed_sdk_init(void) { -} - -#if MBED_CONF_FILESYSTEM_PRESENT -// Internally used file objects with managed memory on close -class ManagedFile : public File { -public: - virtual int close() { - int err = File::close(); - delete this; - return err; - } -}; - -class ManagedDir : public Dir { -public: - virtual int close() { - int err = Dir::close(); - delete this; - return err; - } -}; -#endif /* @brief standard c library fopen() retargeting function. * @@ -189,7 +171,7 @@ * @return * On success, a valid FILEHANDLE is returned. * On failure, -1 is returned and errno is set to an appropriate value e.g. - * EBADF a bad file descriptor was found (default errno setting) + * ENOENT file not found (default errno setting) * EMFILE the maximum number of open files was exceeded. * * */ @@ -198,11 +180,6 @@ // Before version 5.03, we were using a patched version of microlib with proper names // This is the workaround that the microlib author suggested us static int n = 0; - static int mbed_sdk_inited = 0; - if (!mbed_sdk_inited) { - mbed_sdk_inited = 1; - mbed_sdk_init(); - } if (!std::strcmp(name, ":tt")) return n++; #else /* Use the posix convention that stdin,out,err are filehandles 0,1,2. @@ -219,9 +196,6 @@ } #endif - /* if something goes wrong and errno is not explicly set, errno will be set to EBADF */ - errno = EBADF; - // find the first empty slot in filehandles filehandle_mutex->lock(); unsigned int fh_i; @@ -235,16 +209,16 @@ filehandle_mutex->unlock(); return -1; } - filehandles[fh_i] = (FileLike*)FILE_HANDLE_RESERVED; + filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED; filehandle_mutex->unlock(); - FileLike *res = NULL; + FileHandle *res = NULL; - /* FILENAME: ":0x12345678" describes a FileLike* */ + /* FILENAME: ":0x12345678" describes a FileHandle* */ if (name[0] == ':') { void *p; - sscanf(name, ":%p", &p); - res = (FileLike*)p; + std::sscanf(name, ":%p", &p); + res = (FileHandle*)p; /* FILENAME: "/file_system/file_name" */ } else { @@ -253,41 +227,25 @@ if (!path.exists()) { /* The first part of the filename (between first 2 '/') is not a * registered mount point in the namespace. - * Free file handle. */ - filehandles[fh_i] = NULL; - errno = ENOENT; - return -1; - } else if (path.isFile()) { + return handle_open_errors(-ENOENT, fh_i); + } + + if (path.isFile()) { res = path.file(); -#if MBED_CONF_FILESYSTEM_PRESENT } else { - FileSystem *fs = path.fileSystem(); + FileSystemHandle *fs = path.fileSystem(); if (fs == NULL) { - /* The filesystem instance managing the namespace under the mount point - * has not been found. Free file handle */ - errno = ENOENT; - filehandles[fh_i] = NULL; - return -1; + return handle_open_errors(-ENOENT, fh_i); } int posix_mode = openmode_to_posix(openmode); - File *file = new ManagedFile; - int err = file->open(fs, path.fileName(), posix_mode); - if (err < 0) { - errno = -err; - delete file; - } else { - res = file; + int err = fs->open(&res, path.fileName(), posix_mode); + if (err) { + return handle_open_errors(err, fh_i); } -#endif } } - if (res == NULL) { - // Free file handle - filehandles[fh_i] = NULL; - return -1; - } filehandles[fh_i] = res; return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err @@ -296,10 +254,12 @@ extern "C" int PREFIX(_close)(FILEHANDLE fh) { if (fh < 3) return 0; - errno = EBADF; - FileLike* fhc = filehandles[fh-3]; + FileHandle* fhc = filehandles[fh-3]; filehandles[fh-3] = NULL; - if (fhc == NULL) return -1; + if (fhc == NULL) { + errno = EBADF; + return -1; + } int err = fhc->close(); if (err < 0) { @@ -317,7 +277,12 @@ #endif int n; // n is the number of bytes written - errno = EBADF; +#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) + if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { + error("Error - writing to a file in an ISR or critical section\r\n"); + } +#endif + if (fh < 3) { #if DEVICE_SERIAL if (!stdio_uart_inited) init_serial(); @@ -337,8 +302,11 @@ #endif n = length; } else { - FileLike* fhc = filehandles[fh-3]; - if (fhc == NULL) return -1; + FileHandle* fhc = filehandles[fh-3]; + if (fhc == NULL) { + errno = EBADF; + return -1; + } n = fhc->write(buffer, length); if (n < 0) { @@ -359,7 +327,12 @@ #endif int n; // n is the number of bytes read - errno = EBADF; +#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) + if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { + error("Error - reading from a file in an ISR or critical section\r\n"); + } +#endif + if (fh < 3) { // only read a character at a time from stdin #if DEVICE_SERIAL @@ -389,8 +362,11 @@ #endif n = 1; } else { - FileLike* fhc = filehandles[fh-3]; - if (fhc == NULL) return -1; + FileHandle* fhc = filehandles[fh-3]; + if (fhc == NULL) { + errno = EBADF; + return -1; + } n = fhc->read(buffer, length); if (n < 0) { @@ -404,57 +380,76 @@ #endif } + #ifdef __ARMCC_VERSION extern "C" int PREFIX(_istty)(FILEHANDLE fh) #else extern "C" int _isatty(FILEHANDLE fh) #endif { - errno = EBADF; /* stdin, stdout and stderr should be tty */ if (fh < 3) return 1; - FileLike* fhc = filehandles[fh-3]; - if (fhc == NULL) return -1; + FileHandle* fhc = filehandles[fh-3]; + if (fhc == NULL) { + errno = EBADF; + return 0; + } - int err = fhc->isatty(); - if (err < 0) { - errno = -err; - return -1; + int tty = fhc->isatty(); + if (tty < 0) { + errno = -tty; + return 0; } else { - return 0; + return tty; } } extern "C" #if defined(__ARMCC_VERSION) -int _sys_seek(FILEHANDLE fh, long position) +int _sys_seek(FILEHANDLE fh, long offset) #elif defined(__ICCARM__) long __lseek(int fh, long offset, int whence) #else int _lseek(FILEHANDLE fh, int offset, int whence) #endif { - errno = EBADF; - if (fh < 3) return 0; - - FileLike* fhc = filehandles[fh-3]; - if (fhc == NULL) return -1; +#if defined(__ARMCC_VERSION) + int whence = SEEK_SET; +#endif + if (fh < 3) { + errno = ESPIPE; + return -1; + } -#if defined(__ARMCC_VERSION) - return fhc->seek(position, SEEK_SET); -#else - return fhc->seek(offset, whence); -#endif + FileHandle* fhc = filehandles[fh-3]; + if (fhc == NULL) { + errno = EBADF; + return -1; + } + + off_t off = fhc->seek(offset, whence); + if (off < 0) { + errno = -off; + return -1; + } + // Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference + if (off > INT_MAX) { + errno = EOVERFLOW; + return -1; + } + return off; } #ifdef __ARMCC_VERSION extern "C" int PREFIX(_ensure)(FILEHANDLE fh) { - errno = EBADF; if (fh < 3) return 0; - FileLike* fhc = filehandles[fh-3]; - if (fhc == NULL) return -1; + FileHandle* fhc = filehandles[fh-3]; + if (fhc == NULL) { + errno = EBADF; + return -1; + } int err = fhc->sync(); if (err < 0) { @@ -466,13 +461,27 @@ } extern "C" long PREFIX(_flen)(FILEHANDLE fh) { - errno = EBADF; - if (fh < 3) return 0; + if (fh < 3) { + errno = EINVAL; + return -1; + } + + FileHandle* fhc = filehandles[fh-3]; + if (fhc == NULL) { + errno = EBADF; + return -1; + } - FileLike* fhc = filehandles[fh-3]; - if (fhc == NULL) return -1; - - return fhc->size(); + off_t size = fhc->size(); + if (size < 0) { + errno = -size; + return -1; + } + if (size > LONG_MAX) { + errno = EOVERFLOW; + return -1; + } + return size; } #endif @@ -490,11 +499,12 @@ namespace std { extern "C" int remove(const char *path) { -#if MBED_CONF_FILESYSTEM_PRESENT - errno = EBADF; FilePath fp(path); - FileSystem *fs = fp.fileSystem(); - if (fs == NULL) return -1; + FileSystemHandle *fs = fp.fileSystem(); + if (fs == NULL) { + errno = ENOENT; + return -1; + } int err = fs->remove(fp.fileName()); if (err < 0) { @@ -503,22 +513,24 @@ } else { return 0; } -#else - errno = ENOSYS; - return -1; -#endif } extern "C" int rename(const char *oldname, const char *newname) { -#if MBED_CONF_FILESYSTEM_PRESENT - errno = EBADF; FilePath fpOld(oldname); FilePath fpNew(newname); - FileSystem *fsOld = fpOld.fileSystem(); - FileSystem *fsNew = fpNew.fileSystem(); + FileSystemHandle *fsOld = fpOld.fileSystem(); + FileSystemHandle *fsNew = fpNew.fileSystem(); + + if (fsOld == NULL) { + errno = ENOENT; + return -1; + } /* rename only if both files are on the same FS */ - if (fsOld != fsNew || fsOld == NULL) return -1; + if (fsOld != fsNew) { + errno = EXDEV; + return -1; + } int err = fsOld->rename(fpOld.fileName(), fpNew.fileName()); if (err < 0) { @@ -527,10 +539,6 @@ } else { return 0; } -#else - errno = ENOSYS; - return -1; -#endif } extern "C" char *tmpnam(char *s) { @@ -551,30 +559,24 @@ #endif extern "C" DIR *opendir(const char *path) { -#if MBED_CONF_FILESYSTEM_PRESENT - errno = EBADF; + FilePath fp(path); + FileSystemHandle* fs = fp.fileSystem(); + if (fs == NULL) { + errno = ENOENT; + return NULL; + } - FilePath fp(path); - FileSystem* fs = fp.fileSystem(); - if (fs == NULL) return NULL; - - Dir *dir = new ManagedDir; - int err = dir->open(fs, fp.fileName()); + DirHandle *dir; + int err = fs->open(&dir, fp.fileName()); if (err < 0) { errno = -err; - delete dir; - dir = NULL; + return NULL; } return dir; -#else - errno = ENOSYS; - return 0; -#endif } extern "C" struct dirent *readdir(DIR *dir) { -#if MBED_CONF_FILESYSTEM_PRESENT static struct dirent ent; int err = dir->read(&ent); if (err < 1) { @@ -585,14 +587,9 @@ } return &ent; -#else - errno = ENOSYS; - return 0; -#endif } extern "C" int closedir(DIR *dir) { -#if MBED_CONF_FILESYSTEM_PRESENT int err = dir->close(); if (err < 0) { errno = -err; @@ -600,41 +597,23 @@ } else { return 0; } -#else - errno = ENOSYS; - return -1; -#endif } extern "C" void rewinddir(DIR *dir) { -#if MBED_CONF_FILESYSTEM_PRESENT dir->rewind(); -#else - errno = ENOSYS; -#endif } extern "C" off_t telldir(DIR *dir) { -#if MBED_CONF_FILESYSTEM_PRESENT return dir->tell(); -#else - errno = ENOSYS; - return 0; -#endif } extern "C" void seekdir(DIR *dir, off_t off) { -#if MBED_CONF_FILESYSTEM_PRESENT dir->seek(off); -#else - errno = ENOSYS; -#endif } extern "C" int mkdir(const char *path, mode_t mode) { -#if MBED_CONF_FILESYSTEM_PRESENT FilePath fp(path); - FileSystem *fs = fp.fileSystem(); + FileSystemHandle *fs = fp.fileSystem(); if (fs == NULL) return -1; int err = fs->mkdir(fp.fileName(), mode); @@ -644,16 +623,11 @@ } else { return 0; } -#else - errno = ENOSYS; - return -1; -#endif } extern "C" int stat(const char *path, struct stat *st) { -#if MBED_CONF_FILESYSTEM_PRESENT FilePath fp(path); - FileSystem *fs = fp.fileSystem(); + FileSystemHandle *fs = fp.fileSystem(); if (fs == NULL) return -1; int err = fs->stat(fp.fileName(), st); @@ -663,10 +637,6 @@ } else { return 0; } -#else - errno = ENOSYS; - return -1; -#endif } #if defined(TOOLCHAIN_GCC) @@ -684,79 +654,10 @@ #endif -#if defined(TOOLCHAIN_GCC) - -#ifdef FEATURE_UVISOR -#include "uvisor-lib/uvisor-lib.h" -#endif/* FEATURE_UVISOR */ - - -extern "C" WEAK void software_init_hook_rtos(void) -{ - // Do nothing by default. -} - -extern "C" void software_init_hook(void) -{ -#ifdef FEATURE_UVISOR - int return_code; - - return_code = uvisor_lib_init(); - if (return_code) { - mbed_die(); - } -#endif/* FEATURE_UVISOR */ - mbed_sdk_init(); - software_init_hook_rtos(); -} -#endif - -// **************************************************************************** -// mbed_main is a function that is called before main() -// mbed_sdk_init() is also a function that is called before main(), but unlike -// mbed_main(), it is not meant for user code, but for the SDK itself to perform -// initializations before main() is called. - -extern "C" WEAK void mbed_main(void); -extern "C" WEAK void mbed_main(void) { -} - -#if defined(TOOLCHAIN_ARM) -extern "C" int $Super$$main(void); - -extern "C" int $Sub$$main(void) { - mbed_main(); - return $Super$$main(); -} - -extern "C" void _platform_post_stackheap_init (void) { - mbed_sdk_init(); -} - -#elif defined(TOOLCHAIN_GCC) -extern "C" int __real_main(void); - -extern "C" int __wrap_main(void) { - mbed_main(); - return __real_main(); -} -#elif defined(TOOLCHAIN_IAR) -// IAR doesn't have the $Super/$Sub mechanism of armcc, nor something equivalent -// to ld's --wrap. It does have a --redirect, but that doesn't help, since redirecting -// 'main' to another symbol looses the original 'main' symbol. However, its startup -// code will call a function to setup argc and argv (__iar_argc_argv) if it is defined. -// Since mbed doesn't use argc/argv, we use this function to call our mbed_main. -extern "C" void __iar_argc_argv() { - mbed_main(); -} -#endif - // Provide implementation of _sbrk (low-level dynamic memory allocation // routine) for GCC_ARM which compares new heap pointer with MSP instead of // SP. This make it compatible with RTX RTOS thread stacks. #if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_GCC_CR) -// Linker defined symbol used by _sbrk to indicate where heap should start. -extern "C" int __end__; #if defined(TARGET_CORTEX_A) extern "C" uint32_t __HeapLimit; @@ -766,9 +667,6 @@ #undef errno extern "C" int errno; -// For ARM7 only -register unsigned char * stack_ptr __asm ("sp"); - // Dynamic memory allocation related syscall. #if defined(TARGET_NUMAKER_PFM_NUC472) || defined(TARGET_NUMAKER_PFM_M453) // Overwrite _sbrk() to support two region model (heap and stack are two distinct regions). @@ -780,14 +678,14 @@ return (caddr_t) __wrap__sbrk(incr); } #else +// Linker defined symbol used by _sbrk to indicate where heap should start. +extern "C" uint32_t __end__; extern "C" caddr_t _sbrk(int incr) { static unsigned char* heap = (unsigned char*)&__end__; unsigned char* prev_heap = heap; unsigned char* new_heap = heap + incr; -#if defined(TARGET_ARM7) - if (new_heap >= stack_ptr) { -#elif defined(TARGET_CORTEX_A) +#if defined(TARGET_CORTEX_A) if (new_heap >= (unsigned char*)&__HeapLimit) { /* __HeapLimit is end of heap section */ #else if (new_heap >= (unsigned char*)__get_MSP()) { @@ -899,16 +797,34 @@ namespace mbed { -void mbed_set_unbuffered_stream(FILE *_file) { +void mbed_set_unbuffered_stream(std::FILE *_file) { #if defined (__ICCARM__) char buf[2]; - std::setvbuf(_file,buf,_IONBF,NULL); + std::setvbuf(_file,buf,_IONBF,NULL); #else setbuf(_file, NULL); #endif } -int mbed_getc(FILE *_file){ +/* Applications are expected to use fdopen() + * not this function directly. This code had to live here because FILE and FileHandle + * processes are all linked together here. + */ +std::FILE *mbed_fdopen(FileHandle *fh, const char *mode) +{ + char buf[12]; /* :0x12345678 + null byte */ + std::sprintf(buf, ":%p", fh); + std::FILE *stream = std::fopen(buf, mode); + /* newlib-nano doesn't appear to ever call _isatty itself, so + * happily fully buffers an interactive stream. Deal with that here. + */ + if (stream && fh->isatty()) { + mbed_set_unbuffered_stream(stream); + } + return stream; +} + +int mbed_getc(std::FILE *_file){ #if defined (__ICCARM__) /*This is only valid for unbuffered streams*/ int res = std::fgetc(_file); @@ -916,14 +832,14 @@ _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */ _file->_Rend = _file->_Wend; _file->_Next = _file->_Wend; - } + } return res; -#else +#else return std::fgetc(_file); -#endif +#endif } -char* mbed_gets(char*s, int size, FILE *_file){ +char* mbed_gets(char*s, int size, std::FILE *_file){ #if defined (__ICCARM__) /*This is only valid for unbuffered streams*/ char *str = fgets(s,size,_file); @@ -933,7 +849,7 @@ _file->_Next = _file->_Wend; } return str; -#else +#else return std::fgets(s,size,_file); #endif } @@ -1048,3 +964,72 @@ free(ptr); } } + +#if defined(MBED_CONF_RTOS_PRESENT) && defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED + +static const char* error_msg(int32_t status) +{ + switch (status) { + case osError: + return "Unspecified RTOS error"; + case osErrorTimeout: + return "Operation not completed within the timeout period"; + case osErrorResource: + return "Resource not available"; + case osErrorParameter: + return "Parameter error"; + case osErrorNoMemory: + return "System is out of memory"; + case osErrorISR: + return "Not allowed in ISR context"; + default: + return "Unknown"; + } +} + +extern "C" void EvrRtxKernelError (int32_t status) +{ + error("Kernel error %i: %s\r\n", status, error_msg(status)); +} + +extern "C" void EvrRtxThreadError (osThreadId_t thread_id, int32_t status) +{ + error("Thread %p error %i: %s\r\n", thread_id, status, error_msg(status)); +} + +extern "C" void EvrRtxTimerError (osTimerId_t timer_id, int32_t status) +{ + error("Timer %p error %i: %s\r\n", timer_id, status, error_msg(status)); +} + +extern "C" void EvrRtxEventFlagsError (osEventFlagsId_t ef_id, int32_t status) +{ + error("Event %p error %i: %s\r\n", ef_id, status, error_msg(status)); +} + +extern "C" void EvrRtxMutexError (osMutexId_t mutex_id, int32_t status) +{ + error("Mutex %p error %i: %s\r\n", mutex_id, status, error_msg(status)); +} + +extern "C" void EvrRtxSemaphoreError (osSemaphoreId_t semaphore_id, int32_t status) +{ + // Ignore semaphore overflow, the count will saturate with a returned error + if (status == osRtxErrorSemaphoreCountLimit) { + return; + } + + error("Semaphore %p error %i\r\n", semaphore_id, status); +} + +extern "C" void EvrRtxMemoryPoolError (osMemoryPoolId_t mp_id, int32_t status) +{ + error("Memory Pool %p error %i\r\n", mp_id, status); +} + +extern "C" void EvrRtxMessageQueueError (osMessageQueueId_t mq_id, int32_t status) +{ + error("Message Queue %p error %i\r\n", mq_id, status); +} + +#endif