Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-dev by
Diff: platform/mbed_retarget.cpp
- Revision:
- 167:e84263d55307
- Parent:
- 163:74e0ce7f98e8
- Child:
- 168: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