mbed library sources
Fork of mbed-src 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 #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 17:14:56 by 1.7.2