mbed library sources

Fork of mbed-src 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 #endif
00125     return posix;
00126 }
00127 
00128 extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
00129     #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000)
00130     // Before version 5.03, we were using a patched version of microlib with proper names
00131     // This is the workaround that the microlib author suggested us
00132     static int n = 0;
00133     if (!std::strcmp(name, ":tt")) return n++;
00134 
00135     #else
00136     /* Use the posix convention that stdin,out,err are filehandles 0,1,2.
00137      */
00138     if (std::strcmp(name, __stdin_name) == 0) {
00139         init_serial();
00140         return 0;
00141     } else if (std::strcmp(name, __stdout_name) == 0) {
00142         init_serial();
00143         return 1;
00144     } else if (std::strcmp(name, __stderr_name) == 0) {
00145         init_serial();
00146         return 2;
00147     }
00148     #endif
00149 
00150     // find the first empty slot in filehandles
00151     unsigned int fh_i;
00152     for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
00153         if (filehandles[fh_i] == NULL) break;
00154     }
00155     if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) {
00156         return -1;
00157     }
00158 
00159     FileHandle *res;
00160 
00161     /* FILENAME: ":0x12345678" describes a FileLike* */
00162     if (name[0] == ':') {
00163         void *p;
00164         sscanf(name, ":%p", &p);
00165         res = (FileHandle*)p;
00166 
00167     /* FILENAME: "/file_system/file_name" */
00168     } else {
00169         FilePath path(name);
00170 
00171         if (!path.exists())
00172             return -1;
00173         else if (path.isFile()) {
00174             res = path.file();
00175         } else {
00176             FileSystemLike *fs = path.fileSystem();
00177             if (fs == NULL) return -1;
00178             int posix_mode = openmode_to_posix(openmode);
00179             res = fs->open(path.fileName(), posix_mode); /* NULL if fails */
00180         }
00181     }
00182 
00183     if (res == NULL) return -1;
00184     filehandles[fh_i] = res;
00185 
00186     return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err
00187 }
00188 
00189 extern "C" int PREFIX(_close)(FILEHANDLE fh) {
00190     if (fh < 3) return 0;
00191 
00192     FileHandle* fhc = filehandles[fh-3];
00193     filehandles[fh-3] = NULL;
00194     if (fhc == NULL) return -1;
00195 
00196     return fhc->close();
00197 }
00198 
00199 #if defined(__ICCARM__)
00200 extern "C" size_t    __write (int        fh, const unsigned char *buffer, size_t length) {
00201 #else
00202 extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) {
00203 #endif
00204     int n; // n is the number of bytes written
00205     if (fh < 3) {
00206 #if DEVICE_SERIAL
00207         if (!stdio_uart_inited) init_serial();
00208         for (unsigned int i = 0; i < length; i++) {
00209             serial_putc(&stdio_uart, buffer[i]);
00210         }
00211 #endif
00212         n = length;
00213     } else {
00214         FileHandle* fhc = filehandles[fh-3];
00215         if (fhc == NULL) return -1;
00216 
00217         n = fhc->write(buffer, length);
00218     }
00219 #ifdef __ARMCC_VERSION
00220     return length-n;
00221 #else
00222     return n;
00223 #endif
00224 }
00225 
00226 #if defined(__ICCARM__)
00227 extern "C" size_t    __read (int        fh, unsigned char *buffer, size_t       length) {
00228 #else
00229 extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) {
00230 #endif
00231     int n; // n is the number of bytes read
00232     if (fh < 3) {
00233         // only read a character at a time from stdin
00234 #if DEVICE_SERIAL
00235         if (!stdio_uart_inited) init_serial();
00236         *buffer = serial_getc(&stdio_uart);
00237 #endif
00238         n = 1;
00239     } else {
00240         FileHandle* fhc = filehandles[fh-3];
00241         if (fhc == NULL) return -1;
00242 
00243         n = fhc->read(buffer, length);
00244     }
00245 #ifdef __ARMCC_VERSION
00246     return length-n;
00247 #else
00248     return n;
00249 #endif
00250 }
00251 
00252 #ifdef __ARMCC_VERSION
00253 extern "C" int PREFIX(_istty)(FILEHANDLE fh)
00254 #else
00255 extern "C" int _isatty(FILEHANDLE fh)
00256 #endif
00257 {
00258     /* stdin, stdout and stderr should be tty */
00259     if (fh < 3) return 1;
00260 
00261     FileHandle* fhc = filehandles[fh-3];
00262     if (fhc == NULL) return -1;
00263 
00264     return fhc->isatty();
00265 }
00266 
00267 extern "C"
00268 #if defined(__ARMCC_VERSION)
00269 int _sys_seek(FILEHANDLE fh, long position)
00270 #elif defined(__ICCARM__)
00271 long __lseek(int fh, long offset, int whence)
00272 #else
00273 int _lseek(FILEHANDLE fh, int offset, int whence)
00274 #endif
00275 {
00276     if (fh < 3) return 0;
00277 
00278     FileHandle* fhc = filehandles[fh-3];
00279     if (fhc == NULL) return -1;
00280 
00281 #if defined(__ARMCC_VERSION)
00282     return fhc->lseek(position, SEEK_SET);
00283 #else
00284     return fhc->lseek(offset, whence);
00285 #endif
00286 }
00287 
00288 #ifdef __ARMCC_VERSION
00289 extern "C" int PREFIX(_ensure)(FILEHANDLE fh) {
00290     if (fh < 3) return 0;
00291 
00292     FileHandle* fhc = filehandles[fh-3];
00293     if (fhc == NULL) return -1;
00294 
00295     return fhc->fsync();
00296 }
00297 
00298 extern "C" long PREFIX(_flen)(FILEHANDLE fh) {
00299     if (fh < 3) return 0;
00300 
00301     FileHandle* fhc = filehandles[fh-3];
00302     if (fhc == NULL) return -1;
00303 
00304     return fhc->flen();
00305 }
00306 #endif
00307 
00308 
00309 #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__)
00310 extern "C" int _fstat(int fd, struct stat *st) {
00311     if ((STDOUT_FILENO == fd) || (STDERR_FILENO == fd) || (STDIN_FILENO == fd)) {
00312         st->st_mode = S_IFCHR;
00313         return  0;
00314     }
00315 
00316     errno = EBADF;
00317     return -1;
00318 }
00319 #endif
00320 
00321 namespace std {
00322 extern "C" int remove(const char *path) {
00323     FilePath fp(path);
00324     FileSystemLike *fs = fp.fileSystem();
00325     if (fs == NULL) return -1;
00326 
00327     return fs->remove(fp.fileName());
00328 }
00329 
00330 extern "C" int rename(const char *oldname, const char *newname) {
00331     FilePath fpOld(oldname);
00332     FilePath fpNew(newname);
00333     FileSystemLike *fsOld = fpOld.fileSystem();
00334     FileSystemLike *fsNew = fpNew.fileSystem();
00335 
00336     /* rename only if both files are on the same FS */
00337     if (fsOld != fsNew || fsOld == NULL) return -1;
00338 
00339     return fsOld->rename(fpOld.fileName(), fpNew.fileName());
00340 }
00341 
00342 extern "C" char *tmpnam(char *s) {
00343     return NULL;
00344 }
00345 
00346 extern "C" FILE *tmpfile() {
00347     return NULL;
00348 }
00349 } // namespace std
00350 
00351 #ifdef __ARMCC_VERSION
00352 extern "C" char *_sys_command_string(char *cmd, int len) {
00353     return NULL;
00354 }
00355 #endif
00356 
00357 extern "C" DIR *opendir(const char *path) {
00358     /* root dir is FileSystemLike */
00359     if (path[0] == '/' && path[1] == 0) {
00360         return FileSystemLike::opendir();
00361     }
00362 
00363     FilePath fp(path);
00364     FileSystemLike* fs = fp.fileSystem();
00365     if (fs == NULL) return NULL;
00366 
00367     return fs->opendir(fp.fileName());
00368 }
00369 
00370 extern "C" struct dirent *readdir(DIR *dir) {
00371     return dir->readdir();
00372 }
00373 
00374 extern "C" int closedir(DIR *dir) {
00375     return dir->closedir();
00376 }
00377 
00378 extern "C" void rewinddir(DIR *dir) {
00379     dir->rewinddir();
00380 }
00381 
00382 extern "C" off_t telldir(DIR *dir) {
00383     return dir->telldir();
00384 }
00385 
00386 extern "C" void seekdir(DIR *dir, off_t off) {
00387     dir->seekdir(off);
00388 }
00389 
00390 extern "C" int mkdir(const char *path, mode_t mode) {
00391     FilePath fp(path);
00392     FileSystemLike *fs = fp.fileSystem();
00393     if (fs == NULL) return -1;
00394 
00395     return fs->mkdir(fp.fileName(), mode);
00396 }
00397 
00398 #if defined(TOOLCHAIN_GCC)
00399 /* prevents the exception handling name demangling code getting pulled in */
00400 #include "mbed_error.h"
00401 namespace __gnu_cxx {
00402     void __verbose_terminate_handler() {
00403         error("Exception");
00404     }
00405 }
00406 extern "C" WEAK void __cxa_pure_virtual(void);
00407 extern "C" WEAK void __cxa_pure_virtual(void) {
00408     exit(1);
00409 }
00410 
00411 #endif
00412 
00413 // ****************************************************************************
00414 // mbed_main is a function that is called before main()
00415 // mbed_sdk_init() is also a function that is called before main(), but unlike
00416 // mbed_main(), it is not meant for user code, but for the SDK itself to perform
00417 // initializations before main() is called.
00418 
00419 extern "C" WEAK void mbed_main(void);
00420 extern "C" WEAK void mbed_main(void) {
00421 }
00422 
00423 extern "C" WEAK void mbed_sdk_init(void);
00424 extern "C" WEAK void mbed_sdk_init(void) {
00425 }
00426 
00427 #if defined(TOOLCHAIN_ARM)
00428 extern "C" int $Super$$main(void);
00429 
00430 extern "C" int $Sub$$main(void) {
00431     mbed_sdk_init();
00432     mbed_main();
00433     return $Super$$main();
00434 }
00435 #elif defined(TOOLCHAIN_GCC)
00436 extern "C" int __real_main(void);
00437 
00438 extern "C" int __wrap_main(void) {
00439     mbed_sdk_init();
00440     mbed_main();
00441     return __real_main();
00442 }
00443 #elif defined(TOOLCHAIN_IAR)
00444 // IAR doesn't have the $Super/$Sub mechanism of armcc, nor something equivalent
00445 // to ld's --wrap. It does have a --redirect, but that doesn't help, since redirecting
00446 // 'main' to another symbol looses the original 'main' symbol. However, its startup
00447 // code will call a function to setup argc and argv (__iar_argc_argv) if it is defined.
00448 // Since mbed doesn't use argc/argv, we use this function to call our mbed_main.
00449 extern "C" void __iar_argc_argv() {
00450     mbed_sdk_init();
00451     mbed_main();
00452 }
00453 #endif
00454 
00455 // Provide implementation of _sbrk (low-level dynamic memory allocation
00456 // routine) for GCC_ARM which compares new heap pointer with MSP instead of
00457 // SP.  This make it compatible with RTX RTOS thread stacks.
00458 #if defined(TOOLCHAIN_GCC_ARM)
00459 // Linker defined symbol used by _sbrk to indicate where heap should start.
00460 extern "C" int __end__;
00461 
00462 #if defined(TARGET_CORTEX_A)
00463 extern "C" uint32_t  __HeapLimit;
00464 #endif
00465 
00466 // Turn off the errno macro and use actual global variable instead.
00467 #undef errno
00468 extern "C" int errno;
00469 
00470 // For ARM7 only
00471 register unsigned char * stack_ptr __asm ("sp");
00472 
00473 // Dynamic memory allocation related syscall.
00474 extern "C" caddr_t _sbrk(int incr) {
00475     static unsigned char* heap = (unsigned char*)&__end__;
00476     unsigned char*        prev_heap = heap;
00477     unsigned char*        new_heap = heap + incr;
00478 
00479 #if defined(TARGET_ARM7)
00480     if (new_heap >= stack_ptr) {
00481 #elif defined(TARGET_CORTEX_A)
00482     if (new_heap >= (unsigned char*)&__HeapLimit) {     /* __HeapLimit is end of heap section */
00483 #else
00484     if (new_heap >= (unsigned char*)__get_MSP()) {
00485 #endif
00486         errno = ENOMEM;
00487         return (caddr_t)-1;
00488     }
00489 
00490     heap = new_heap;
00491     return (caddr_t) prev_heap;
00492 }
00493 #endif
00494 
00495 
00496 #ifdef TOOLCHAIN_GCC_CW
00497 // TODO: Ideally, we would like to define directly "_ExitProcess"
00498 extern "C" void mbed_exit(int return_code) {
00499 #elif defined TOOLCHAIN_GCC_ARM
00500 extern "C" void _exit(int return_code) {
00501 #else
00502 namespace std {
00503 extern "C" void exit(int return_code) {
00504 #endif
00505 
00506 #if DEVICE_STDIO_MESSAGES
00507     fflush(stdout);
00508     fflush(stderr);
00509 #endif
00510 
00511 #if DEVICE_SEMIHOST
00512     if (mbed_interface_connected()) {
00513         semihost_exit();
00514     }
00515 #endif
00516     if (return_code) {
00517         mbed_die();
00518     }
00519 
00520     while (1);
00521 }
00522 
00523 #if !defined(TOOLCHAIN_GCC_ARM) && !defined(TOOLCHAIN_GCC_CW)
00524 } //namespace std
00525 #endif
00526 
00527 
00528 namespace mbed {
00529 
00530 void mbed_set_unbuffered_stream(FILE *_file) {
00531 #if defined (__ICCARM__)
00532     char buf[2];
00533     std::setvbuf(_file,buf,_IONBF,NULL);    
00534 #else
00535     setbuf(_file, NULL);
00536 #endif
00537 }
00538 
00539 int mbed_getc(FILE *_file){
00540 #if defined (__ICCARM__)
00541     /*This is only valid for unbuffered streams*/
00542     int res = std::fgetc(_file);
00543     if (res>=0){
00544         _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
00545         _file->_Rend = _file->_Wend;
00546         _file->_Next = _file->_Wend;
00547     }    
00548     return res;
00549 #else    
00550     return std::fgetc(_file);
00551 #endif   
00552 }
00553 
00554 char* mbed_gets(char*s, int size, FILE *_file){
00555 #if defined (__ICCARM__)
00556     /*This is only valid for unbuffered streams*/
00557     char *str = fgets(s,size,_file);
00558     if (str!=NULL){
00559         _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
00560         _file->_Rend = _file->_Wend;
00561         _file->_Next = _file->_Wend;
00562     }
00563     return str;
00564 #else    
00565     return std::fgets(s,size,_file);
00566 #endif
00567 }
00568 
00569 } // namespace mbed