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
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
Generated on Tue Jul 12 2022 18:56:14 by
