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-src 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 #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
Generated on Tue Jul 12 2022 18:13:06 by
