mbed library sources. Supersedes mbed-src.

Fork of mbed-dev by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers retarget.cpp Source File

retarget.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "platform.h"
00017 #include "FileHandle.h"
00018 #include "FileSystemLike.h"
00019 #include "FilePath.h"
00020 #include "serial_api.h"
00021 #include "toolchain.h"
00022 #include "semihost_api.h"
00023 #include "mbed_interface.h"
00024 #if DEVICE_STDIO_MESSAGES
00025 #include <stdio.h>
00026 #endif
00027 #include <errno.h>
00028 
00029 #if defined(__ARMCC_VERSION)
00030 #   include <rt_sys.h>
00031 #   define PREFIX(x)    _sys##x
00032 #   define OPEN_MAX     _SYS_OPEN
00033 #   ifdef __MICROLIB
00034 #       pragma import(__use_full_stdio)
00035 #   endif
00036 
00037 #elif defined(__ICCARM__)
00038 #   include <yfuns.h>
00039 #   define PREFIX(x)        _##x
00040 #   define OPEN_MAX         16
00041 
00042 #   define STDIN_FILENO     0
00043 #   define STDOUT_FILENO    1
00044 #   define STDERR_FILENO    2
00045 
00046 #else
00047 #   include <sys/stat.h>
00048 #   include <sys/unistd.h>
00049 #   include <sys/syslimits.h>
00050 #   define PREFIX(x)    x
00051 #endif
00052 
00053 using namespace mbed;
00054 
00055 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000)
00056 // Before version 5.03, we were using a patched version of microlib with proper names
00057 extern const char __stdin_name[]  = ":tt";
00058 extern const char __stdout_name[] = ":tt";
00059 extern const char __stderr_name[] = ":tt";
00060 
00061 #else
00062 extern const char __stdin_name[]  = "/stdin";
00063 extern const char __stdout_name[] = "/stdout";
00064 extern const char __stderr_name[] = "/stderr";
00065 #endif
00066 
00067 /* newlib has the filehandle field in the FILE struct as a short, so
00068  * we can't just return a Filehandle* from _open and instead have to
00069  * put it in a filehandles array and return the index into that array
00070  * (or rather index+3, as filehandles 0-2 are stdin/out/err).
00071  */
00072 static FileHandle *filehandles[OPEN_MAX];
00073 
00074 FileHandle::~FileHandle() {
00075     /* Remove all open filehandles for this */
00076     for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
00077         if (filehandles[fh_i] == this) {
00078             filehandles[fh_i] = NULL;
00079         }
00080     }
00081 }
00082 
00083 #if DEVICE_SERIAL
00084 extern int stdio_uart_inited;
00085 extern serial_t stdio_uart;
00086 #endif
00087 
00088 static void init_serial() {
00089 #if DEVICE_SERIAL
00090     if (stdio_uart_inited) return;
00091     serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
00092 #endif
00093 }
00094 
00095 static inline int openmode_to_posix(int openmode) {
00096     int posix = openmode;
00097 #ifdef __ARMCC_VERSION
00098     if (openmode & OPEN_PLUS) {
00099         posix = O_RDWR;
00100     } else if(openmode & OPEN_W) {
00101         posix = O_WRONLY;
00102     } else if(openmode & OPEN_A) {
00103         posix = O_WRONLY|O_APPEND;
00104     } else {
00105         posix = O_RDONLY;
00106     }
00107     /* a, w, a+, w+ all create if file does not already exist */
00108     if (openmode & (OPEN_A|OPEN_W)) {
00109         posix |= O_CREAT;
00110     }
00111     /* w and w+ truncate */
00112     if (openmode & OPEN_W) {
00113         posix |= O_TRUNC;
00114     }
00115 #elif defined(__ICCARM__)
00116     switch (openmode & _LLIO_RDWRMASK) {
00117         case _LLIO_RDONLY: posix = O_RDONLY; break;
00118         case _LLIO_WRONLY: posix = O_WRONLY; break;
00119         case _LLIO_RDWR  : posix = O_RDWR  ; break;
00120     }
00121     if (openmode & _LLIO_CREAT ) posix |= O_CREAT;
00122     if (openmode & _LLIO_APPEND) posix |= O_APPEND;
00123     if (openmode & _LLIO_TRUNC ) posix |= O_TRUNC;
00124 #elif defined(TOOLCHAIN_GCC)
00125     posix &= ~O_BINARY;
00126 #endif
00127     return posix;
00128 }
00129 
00130 extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
00131     #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000)
00132     // Before version 5.03, we were using a patched version of microlib with proper names
00133     // This is the workaround that the microlib author suggested us
00134     static int n = 0;
00135     if (!std::strcmp(name, ":tt")) return n++;
00136 
00137     #else
00138     /* Use the posix convention that stdin,out,err are filehandles 0,1,2.
00139      */
00140     if (std::strcmp(name, __stdin_name) == 0) {
00141         init_serial();
00142         return 0;
00143     } else if (std::strcmp(name, __stdout_name) == 0) {
00144         init_serial();
00145         return 1;
00146     } else if (std::strcmp(name, __stderr_name) == 0) {
00147         init_serial();
00148         return 2;
00149     }
00150     #endif
00151 
00152     // find the first empty slot in filehandles
00153     unsigned int fh_i;
00154     for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
00155         if (filehandles[fh_i] == NULL) break;
00156     }
00157     if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) {
00158         return -1;
00159     }
00160 
00161     FileHandle *res;
00162 
00163     /* FILENAME: ":0x12345678" describes a FileLike* */
00164     if (name[0] == ':') {
00165         void *p;
00166         sscanf(name, ":%p", &p);
00167         res = (FileHandle*)p;
00168 
00169     /* FILENAME: "/file_system/file_name" */
00170     } else {
00171         FilePath path(name);
00172 
00173         if (!path.exists())
00174             return -1;
00175         else if (path.isFile()) {
00176             res = path.file();
00177         } else {
00178             FileSystemLike *fs = path.fileSystem();
00179             if (fs == NULL) return -1;
00180             int posix_mode = openmode_to_posix(openmode);
00181             res = fs->open(path.fileName(), posix_mode); /* NULL if fails */
00182         }
00183     }
00184 
00185     if (res == NULL) return -1;
00186     filehandles[fh_i] = res;
00187 
00188     return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err
00189 }
00190 
00191 extern "C" int PREFIX(_close)(FILEHANDLE fh) {
00192     if (fh < 3) return 0;
00193 
00194     FileHandle* fhc = filehandles[fh-3];
00195     filehandles[fh-3] = NULL;
00196     if (fhc == NULL) return -1;
00197 
00198     return fhc->close();
00199 }
00200 
00201 #if defined(__ICCARM__)
00202 extern "C" size_t    __write (int        fh, const unsigned char *buffer, size_t length) {
00203 #else
00204 extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) {
00205 #endif
00206     int n; // n is the number of bytes written
00207     if (fh < 3) {
00208 #if DEVICE_SERIAL
00209         if (!stdio_uart_inited) init_serial();
00210         for (unsigned int i = 0; i < length; i++) {
00211             serial_putc(&stdio_uart, buffer[i]);
00212         }
00213 #endif
00214         n = length;
00215     } else {
00216         FileHandle* fhc = filehandles[fh-3];
00217         if (fhc == NULL) return -1;
00218 
00219         n = fhc->write(buffer, length);
00220     }
00221 #ifdef __ARMCC_VERSION
00222     return length-n;
00223 #else
00224     return n;
00225 #endif
00226 }
00227 
00228 #if defined(__ICCARM__)
00229 extern "C" size_t    __read (int        fh, unsigned char *buffer, size_t       length) {
00230 #else
00231 extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) {
00232 #endif
00233     int n; // n is the number of bytes read
00234     if (fh < 3) {
00235         // only read a character at a time from stdin
00236 #if DEVICE_SERIAL
00237         if (!stdio_uart_inited) init_serial();
00238         *buffer = serial_getc(&stdio_uart);
00239 #endif
00240         n = 1;
00241     } else {
00242         FileHandle* fhc = filehandles[fh-3];
00243         if (fhc == NULL) return -1;
00244 
00245         n = fhc->read(buffer, length);
00246     }
00247 #ifdef __ARMCC_VERSION
00248     return length-n;
00249 #else
00250     return n;
00251 #endif
00252 }
00253 
00254 #ifdef __ARMCC_VERSION
00255 extern "C" int PREFIX(_istty)(FILEHANDLE fh)
00256 #else
00257 extern "C" int _isatty(FILEHANDLE fh)
00258 #endif
00259 {
00260     /* stdin, stdout and stderr should be tty */
00261     if (fh < 3) return 1;
00262 
00263     FileHandle* fhc = filehandles[fh-3];
00264     if (fhc == NULL) return -1;
00265 
00266     return fhc->isatty();
00267 }
00268 
00269 extern "C"
00270 #if defined(__ARMCC_VERSION)
00271 int _sys_seek(FILEHANDLE fh, long position)
00272 #elif defined(__ICCARM__)
00273 long __lseek(int fh, long offset, int whence)
00274 #else
00275 int _lseek(FILEHANDLE fh, int offset, int whence)
00276 #endif
00277 {
00278     if (fh < 3) return 0;
00279 
00280     FileHandle* fhc = filehandles[fh-3];
00281     if (fhc == NULL) return -1;
00282 
00283 #if defined(__ARMCC_VERSION)
00284     return fhc->lseek(position, SEEK_SET);
00285 #else
00286     return fhc->lseek(offset, whence);
00287 #endif
00288 }
00289 
00290 #ifdef __ARMCC_VERSION
00291 extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
00292     if (fh < 3) return 0;
00293 
00294     FileHandle* fhc = filehandles[fh-3];
00295     if (fhc == NULL) return -1;
00296 
00297     return fhc->fsync();
00298 }
00299 
00300 extern "C" long PREFIX(_flen)(FILEHANDLE fh) {
00301     if (fh < 3) return 0;
00302 
00303     FileHandle* fhc = filehandles[fh-3];
00304     if (fhc == NULL) return -1;
00305 
00306     return fhc->flen();
00307 }
00308 #endif
00309 
00310 
00311 #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__)
00312 extern "C" int _fstat(int fd, struct stat *st) {
00313     if ((STDOUT_FILENO == fd) || (STDERR_FILENO == fd) || (STDIN_FILENO == fd)) {
00314         st->st_mode = S_IFCHR;
00315         return  0;
00316     }
00317 
00318     errno = EBADF;
00319     return -1;
00320 }
00321 #endif
00322 
00323 namespace std {
00324 extern "C" int remove(const char *path) {
00325     FilePath fp(path);
00326     FileSystemLike *fs = fp.fileSystem();
00327     if (fs == NULL) return -1;
00328 
00329     return fs->remove(fp.fileName());
00330 }
00331 
00332 extern "C" int rename(const char *oldname, const char *newname) {
00333     FilePath fpOld(oldname);
00334     FilePath fpNew(newname);
00335     FileSystemLike *fsOld = fpOld.fileSystem();
00336     FileSystemLike *fsNew = fpNew.fileSystem();
00337 
00338     /* rename only if both files are on the same FS */
00339     if (fsOld != fsNew || fsOld == NULL) return -1;
00340 
00341     return fsOld->rename(fpOld.fileName(), fpNew.fileName());
00342 }
00343 
00344 extern "C" char *tmpnam(char *s) {
00345     return NULL;
00346 }
00347 
00348 extern "C" FILE *tmpfile() {
00349     return NULL;
00350 }
00351 } // namespace std
00352 
00353 #ifdef __ARMCC_VERSION
00354 extern "C" char *_sys_command_string(char *cmd, int len) {
00355     return NULL;
00356 }
00357 #endif
00358 
00359 extern "C" DIR *opendir(const char *path) {
00360     /* root dir is FileSystemLike */
00361     if (path[0] == '/' && path[1] == 0) {
00362         return FileSystemLike::opendir();
00363     }
00364 
00365     FilePath fp(path);
00366     FileSystemLike* fs = fp.fileSystem();
00367     if (fs == NULL) return NULL;
00368 
00369     return fs->opendir(fp.fileName());
00370 }
00371 
00372 extern "C" struct dirent *readdir(DIR *dir) {
00373     return dir->readdir();
00374 }
00375 
00376 extern "C" int closedir(DIR *dir) {
00377     return dir->closedir();
00378 }
00379 
00380 extern "C" void rewinddir(DIR *dir) {
00381     dir->rewinddir();
00382 }
00383 
00384 extern "C" off_t telldir(DIR *dir) {
00385     return dir->telldir();
00386 }
00387 
00388 extern "C" void seekdir(DIR *dir, off_t off) {
00389     dir->seekdir(off);
00390 }
00391 
00392 extern "C" int mkdir(const char *path, mode_t mode) {
00393     FilePath fp(path);
00394     FileSystemLike *fs = fp.fileSystem();
00395     if (fs == NULL) return -1;
00396 
00397     return fs->mkdir(fp.fileName(), mode);
00398 }
00399 
00400 #if defined(TOOLCHAIN_GCC)
00401 /* prevents the exception handling name demangling code getting pulled in */
00402 #include "mbed_error.h"
00403 namespace __gnu_cxx {
00404     void __verbose_terminate_handler() {
00405         error("Exception");
00406     }
00407 }
00408 extern "C" WEAK void __cxa_pure_virtual(void);
00409 extern "C" WEAK void __cxa_pure_virtual(void) {
00410     exit(1);
00411 }
00412 
00413 #endif
00414 
00415 // ****************************************************************************
00416 // mbed_main is a function that is called before main()
00417 // mbed_sdk_init() is also a function that is called before main(), but unlike
00418 // mbed_main(), it is not meant for user code, but for the SDK itself to perform
00419 // initializations before main() is called.
00420 
00421 extern "C" WEAK void mbed_main(void);
00422 extern "C" WEAK void mbed_main(void) {
00423 }
00424 
00425 extern "C" WEAK void mbed_sdk_init(void);
00426 extern "C" WEAK void mbed_sdk_init(void) {
00427 }
00428 
00429 #if defined(TOOLCHAIN_ARM)
00430 extern "C" int $Super$$main(void);
00431 
00432 extern "C" int $Sub$$main(void) {
00433     mbed_sdk_init();
00434     mbed_main();
00435     return $Super$$main();
00436 }
00437 #elif defined(TOOLCHAIN_GCC)
00438 extern "C" int __real_main(void);
00439 
00440 extern "C" int __wrap_main(void) {
00441     mbed_sdk_init();
00442     mbed_main();
00443     return __real_main();
00444 }
00445 #elif defined(TOOLCHAIN_IAR)
00446 // IAR doesn't have the $Super/$Sub mechanism of armcc, nor something equivalent
00447 // to ld's --wrap. It does have a --redirect, but that doesn't help, since redirecting
00448 // 'main' to another symbol looses the original 'main' symbol. However, its startup
00449 // code will call a function to setup argc and argv (__iar_argc_argv) if it is defined.
00450 // Since mbed doesn't use argc/argv, we use this function to call our mbed_main.
00451 extern "C" void __iar_argc_argv() {
00452     mbed_sdk_init();
00453     mbed_main();
00454 }
00455 #endif
00456 
00457 // Provide implementation of _sbrk (low-level dynamic memory allocation
00458 // routine) for GCC_ARM which compares new heap pointer with MSP instead of
00459 // SP.  This make it compatible with RTX RTOS thread stacks.
00460 #if defined(TOOLCHAIN_GCC_ARM)
00461 // Linker defined symbol used by _sbrk to indicate where heap should start.
00462 extern "C" int __end__;
00463 
00464 #if defined(TARGET_CORTEX_A)
00465 extern "C" uint32_t  __HeapLimit;
00466 #endif
00467 
00468 // Turn off the errno macro and use actual global variable instead.
00469 #undef errno
00470 extern "C" int errno;
00471 
00472 // For ARM7 only
00473 register unsigned char * stack_ptr __asm ("sp");
00474 
00475 // Dynamic memory allocation related syscall.
00476 extern "C" caddr_t _sbrk(int incr) {
00477     static unsigned char* heap = (unsigned char*)&__end__;
00478     unsigned char*        prev_heap = heap;
00479     unsigned char*        new_heap = heap + incr;
00480 
00481 #if defined(TARGET_ARM7)
00482     if (new_heap >= stack_ptr) {
00483 #elif defined(TARGET_CORTEX_A)
00484     if (new_heap >= (unsigned char*)&__HeapLimit) {     /* __HeapLimit is end of heap section */
00485 #else
00486     if (new_heap >= (unsigned char*)__get_MSP()) {
00487 #endif
00488         errno = ENOMEM;
00489         return (caddr_t)-1;
00490     }
00491 
00492     heap = new_heap;
00493     return (caddr_t) prev_heap;
00494 }
00495 #endif
00496 
00497 
00498 #if defined TOOLCHAIN_GCC_ARM
00499 extern "C" void _exit(int return_code) {
00500 #else
00501 namespace std {
00502 extern "C" void exit(int return_code) {
00503 #endif
00504 
00505 #if DEVICE_STDIO_MESSAGES
00506     fflush(stdout);
00507     fflush(stderr);
00508 #endif
00509 
00510 #if DEVICE_SEMIHOST
00511     if (mbed_interface_connected()) {
00512         semihost_exit();
00513     }
00514 #endif
00515     if (return_code) {
00516         mbed_die();
00517     }
00518 
00519     while (1);
00520 }
00521 
00522 #if !defined(TOOLCHAIN_GCC_ARM)
00523 } //namespace std
00524 #endif
00525 
00526 
00527 namespace mbed {
00528 
00529 void mbed_set_unbuffered_stream(FILE *_file) {
00530 #if defined (__ICCARM__)
00531     char buf[2];
00532     std::setvbuf(_file,buf,_IONBF,NULL);    
00533 #else
00534     setbuf(_file, NULL);
00535 #endif
00536 }
00537 
00538 int mbed_getc(FILE *_file){
00539 #if defined (__ICCARM__)
00540     /*This is only valid for unbuffered streams*/
00541     int res = std::fgetc(_file);
00542     if (res>=0){
00543         _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
00544         _file->_Rend = _file->_Wend;
00545         _file->_Next = _file->_Wend;
00546     }    
00547     return res;
00548 #else    
00549     return std::fgetc(_file);
00550 #endif   
00551 }
00552 
00553 char* mbed_gets(char*s, int size, FILE *_file){
00554 #if defined (__ICCARM__)
00555     /*This is only valid for unbuffered streams*/
00556     char *str = fgets(s,size,_file);
00557     if (str!=NULL){
00558         _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
00559         _file->_Rend = _file->_Wend;
00560         _file->_Next = _file->_Wend;
00561     }
00562     return str;
00563 #else    
00564     return std::fgets(s,size,_file);
00565 #endif
00566 }
00567 
00568 } // namespace mbed