mbed library sources. Supersedes mbed-src.
Fork of mbed-dev by
Embed:
(wiki syntax)
Show/hide line numbers
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 20:02:09 by 1.7.2