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-2013 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 <errno.h> 00023 00024 #if defined(__ARMCC_VERSION) 00025 # include <rt_sys.h> 00026 # define PREFIX(x) _sys##x 00027 # define OPEN_MAX _SYS_OPEN 00028 # ifdef __MICROLIB 00029 # pragma import(__use_full_stdio) 00030 # endif 00031 00032 #elif defined(__ICCARM__) 00033 # include <yfuns.h> 00034 # define PREFIX(x) _##x 00035 # define OPEN_MAX 16 00036 00037 # define STDIN_FILENO 0 00038 # define STDOUT_FILENO 1 00039 # define STDERR_FILENO 2 00040 00041 #else 00042 # include <sys/stat.h> 00043 # include <sys/unistd.h> 00044 # include <sys/syslimits.h> 00045 # define PREFIX(x) x 00046 #endif 00047 00048 using namespace mbed; 00049 00050 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) 00051 // Before version 5.03, we were using a patched version of microlib with proper names 00052 extern const char __stdin_name[] = ":tt"; 00053 extern const char __stdout_name[] = ":tt"; 00054 extern const char __stderr_name[] = ":tt"; 00055 00056 #else 00057 extern const char __stdin_name[] = "/stdin"; 00058 extern const char __stdout_name[] = "/stdout"; 00059 extern const char __stderr_name[] = "/stderr"; 00060 #endif 00061 00062 /* newlib has the filehandle field in the FILE struct as a short, so 00063 * we can't just return a Filehandle* from _open and instead have to 00064 * put it in a filehandles array and return the index into that array 00065 * (or rather index+3, as filehandles 0-2 are stdin/out/err). 00066 */ 00067 static FileHandle *filehandles[OPEN_MAX]; 00068 00069 FileHandle::~FileHandle() { 00070 /* Remove all open filehandles for this */ 00071 for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { 00072 if (filehandles[fh_i] == this) { 00073 filehandles[fh_i] = NULL; 00074 } 00075 } 00076 } 00077 00078 #if DEVICE_SERIAL 00079 extern int stdio_uart_inited; 00080 extern serial_t stdio_uart; 00081 #endif 00082 00083 static void init_serial() { 00084 #if DEVICE_SERIAL 00085 if (stdio_uart_inited) return; 00086 serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); 00087 #endif 00088 } 00089 00090 static inline int openmode_to_posix(int openmode) { 00091 int posix = openmode; 00092 #ifdef __ARMCC_VERSION 00093 if (openmode & OPEN_PLUS) { 00094 posix = O_RDWR; 00095 } else if(openmode & OPEN_W) { 00096 posix = O_WRONLY; 00097 } else if(openmode & OPEN_A) { 00098 posix = O_WRONLY|O_APPEND; 00099 } else { 00100 posix = O_RDONLY; 00101 } 00102 /* a, w, a+, w+ all create if file does not already exist */ 00103 if (openmode & (OPEN_A|OPEN_W)) { 00104 posix |= O_CREAT; 00105 } 00106 /* w and w+ truncate */ 00107 if (openmode & OPEN_W) { 00108 posix |= O_TRUNC; 00109 } 00110 #elif defined(__ICCARM__) 00111 switch (openmode & _LLIO_RDWRMASK) { 00112 case _LLIO_RDONLY: posix = O_RDONLY; break; 00113 case _LLIO_WRONLY: posix = O_WRONLY; break; 00114 case _LLIO_RDWR : posix = O_RDWR ; break; 00115 } 00116 if (openmode & _LLIO_CREAT ) posix |= O_CREAT; 00117 if (openmode & _LLIO_APPEND) posix |= O_APPEND; 00118 if (openmode & _LLIO_TRUNC ) posix |= O_TRUNC; 00119 #endif 00120 return posix; 00121 } 00122 00123 extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) { 00124 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) 00125 // Before version 5.03, we were using a patched version of microlib with proper names 00126 // This is the workaround that the microlib author suggested us 00127 static int n = 0; 00128 if (!std::strcmp(name, ":tt")) return n++; 00129 00130 #else 00131 /* Use the posix convention that stdin,out,err are filehandles 0,1,2. 00132 */ 00133 if (std::strcmp(name, __stdin_name) == 0) { 00134 init_serial(); 00135 return 0; 00136 } else if (std::strcmp(name, __stdout_name) == 0) { 00137 init_serial(); 00138 return 1; 00139 } else if (std::strcmp(name, __stderr_name) == 0) { 00140 init_serial(); 00141 return 2; 00142 } 00143 #endif 00144 00145 // find the first empty slot in filehandles 00146 unsigned int fh_i; 00147 for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { 00148 if (filehandles[fh_i] == NULL) break; 00149 } 00150 if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) { 00151 return -1; 00152 } 00153 00154 FileHandle *res; 00155 00156 /* FILENAME: ":0x12345678" describes a FileLike* */ 00157 if (name[0] == ':') { 00158 void *p; 00159 sscanf(name, ":%p", &p); 00160 res = (FileHandle*)p; 00161 00162 /* FILENAME: "/file_system/file_name" */ 00163 } else { 00164 FilePath path(name); 00165 00166 if (!path.exists()) 00167 return -1; 00168 else if (path.isFile()) { 00169 res = path.file(); 00170 } else { 00171 FileSystemLike *fs = path.fileSystem(); 00172 if (fs == NULL) return -1; 00173 int posix_mode = openmode_to_posix(openmode); 00174 res = fs->open(path.fileName(), posix_mode); /* NULL if fails */ 00175 } 00176 } 00177 00178 if (res == NULL) return -1; 00179 filehandles[fh_i] = res; 00180 00181 return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err 00182 } 00183 00184 extern "C" int PREFIX(_close)(FILEHANDLE fh) { 00185 if (fh < 3) return 0; 00186 00187 FileHandle* fhc = filehandles[fh-3]; 00188 filehandles[fh-3] = NULL; 00189 if (fhc == NULL) return -1; 00190 00191 return fhc->close(); 00192 } 00193 00194 #if defined(__ICCARM__) 00195 extern "C" size_t __write (int fh, const unsigned char *buffer, size_t length) { 00196 #else 00197 extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) { 00198 #endif 00199 int n; // n is the number of bytes written 00200 if (fh < 3) { 00201 #if DEVICE_SERIAL 00202 if (!stdio_uart_inited) init_serial(); 00203 for (unsigned int i = 0; i < length; i++) { 00204 serial_putc(&stdio_uart, buffer[i]); 00205 } 00206 #endif 00207 n = length; 00208 } else { 00209 FileHandle* fhc = filehandles[fh-3]; 00210 if (fhc == NULL) return -1; 00211 00212 n = fhc->write(buffer, length); 00213 } 00214 #ifdef __ARMCC_VERSION 00215 return length-n; 00216 #else 00217 return n; 00218 #endif 00219 } 00220 00221 #if defined(__ICCARM__) 00222 extern "C" size_t __read (int fh, unsigned char *buffer, size_t length) { 00223 #else 00224 extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) { 00225 #endif 00226 int n; // n is the number of bytes read 00227 if (fh < 3) { 00228 // only read a character at a time from stdin 00229 #if DEVICE_SERIAL 00230 *buffer = serial_getc(&stdio_uart); 00231 #endif 00232 n = 1; 00233 } else { 00234 FileHandle* fhc = filehandles[fh-3]; 00235 if (fhc == NULL) return -1; 00236 00237 n = fhc->read(buffer, length); 00238 } 00239 #ifdef __ARMCC_VERSION 00240 return length-n; 00241 #else 00242 return n; 00243 #endif 00244 } 00245 00246 #ifdef __ARMCC_VERSION 00247 extern "C" int PREFIX(_istty)(FILEHANDLE fh) 00248 #else 00249 extern "C" int _isatty(FILEHANDLE fh) 00250 #endif 00251 { 00252 /* stdin, stdout and stderr should be tty */ 00253 if (fh < 3) return 1; 00254 00255 FileHandle* fhc = filehandles[fh-3]; 00256 if (fhc == NULL) return -1; 00257 00258 return fhc->isatty(); 00259 } 00260 00261 extern "C" 00262 #if defined(__ARMCC_VERSION) 00263 int _sys_seek(FILEHANDLE fh, long position) 00264 #elif defined(__ICCARM__) 00265 long __lseek(int fh, long offset, int whence) 00266 #else 00267 int _lseek(FILEHANDLE fh, int offset, int whence) 00268 #endif 00269 { 00270 if (fh < 3) return 0; 00271 00272 FileHandle* fhc = filehandles[fh-3]; 00273 if (fhc == NULL) return -1; 00274 00275 #if defined(__ARMCC_VERSION) 00276 return fhc->lseek(position, SEEK_SET); 00277 #else 00278 return fhc->lseek(offset, whence); 00279 #endif 00280 } 00281 00282 #ifdef __ARMCC_VERSION 00283 extern "C" int PREFIX(_ensure)(FILEHANDLE fh) { 00284 if (fh < 3) return 0; 00285 00286 FileHandle* fhc = filehandles[fh-3]; 00287 if (fhc == NULL) return -1; 00288 00289 return fhc->fsync(); 00290 } 00291 00292 extern "C" long PREFIX(_flen)(FILEHANDLE fh) { 00293 if (fh < 3) return 0; 00294 00295 FileHandle* fhc = filehandles[fh-3]; 00296 if (fhc == NULL) return -1; 00297 00298 return fhc->flen(); 00299 } 00300 #endif 00301 00302 00303 #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__) 00304 extern "C" int _fstat(int fd, struct stat *st) { 00305 if ((STDOUT_FILENO == fd) || (STDERR_FILENO == fd) || (STDIN_FILENO == fd)) { 00306 st->st_mode = S_IFCHR; 00307 return 0; 00308 } 00309 00310 errno = EBADF; 00311 return -1; 00312 } 00313 #endif 00314 00315 namespace std { 00316 extern "C" int remove(const char *path) { 00317 FilePath fp(path); 00318 FileSystemLike *fs = fp.fileSystem(); 00319 if (fs == NULL) return -1; 00320 00321 return fs->remove(fp.fileName()); 00322 } 00323 00324 extern "C" int rename(const char *oldname, const char *newname) { 00325 return -1; 00326 } 00327 00328 extern "C" char *tmpnam(char *s) { 00329 return NULL; 00330 } 00331 00332 extern "C" FILE *tmpfile() { 00333 return NULL; 00334 } 00335 } // namespace std 00336 00337 #ifdef __ARMCC_VERSION 00338 extern "C" char *_sys_command_string(char *cmd, int len) { 00339 return NULL; 00340 } 00341 #endif 00342 00343 extern "C" DIR *opendir(const char *path) { 00344 /* root dir is FileSystemLike */ 00345 if (path[0] == '/' && path[1] == 0) { 00346 return FileSystemLike::opendir(); 00347 } 00348 00349 FilePath fp(path); 00350 FileSystemLike* fs = fp.fileSystem(); 00351 if (fs == NULL) return NULL; 00352 00353 return fs->opendir(fp.fileName()); 00354 } 00355 00356 extern "C" struct dirent *readdir(DIR *dir) { 00357 return dir->readdir(); 00358 } 00359 00360 extern "C" int closedir(DIR *dir) { 00361 return dir->closedir(); 00362 } 00363 00364 extern "C" void rewinddir(DIR *dir) { 00365 dir->rewinddir(); 00366 } 00367 00368 extern "C" off_t telldir(DIR *dir) { 00369 return dir->telldir(); 00370 } 00371 00372 extern "C" void seekdir(DIR *dir, off_t off) { 00373 dir->seekdir(off); 00374 } 00375 00376 extern "C" int mkdir(const char *path, mode_t mode) { 00377 FilePath fp(path); 00378 FileSystemLike *fs = fp.fileSystem(); 00379 if (fs == NULL) return -1; 00380 00381 return fs->mkdir(fp.fileName(), mode); 00382 } 00383 00384 #if defined(TOOLCHAIN_GCC) 00385 /* prevents the exception handling name demangling code getting pulled in */ 00386 #include "error.h" 00387 namespace __gnu_cxx { 00388 void __verbose_terminate_handler() { 00389 error("Exception"); 00390 } 00391 } 00392 extern "C" WEAK void __cxa_pure_virtual(void); 00393 extern "C" WEAK void __cxa_pure_virtual(void) { 00394 exit(1); 00395 } 00396 00397 #endif 00398 00399 // **************************************************************************** 00400 // mbed_main is a function that is called before main() 00401 // mbed_sdk_init() is also a function that is called before main(), but unlike 00402 // mbed_main(), it is not meant for user code, but for the SDK itself to perform 00403 // initializations before main() is called. 00404 00405 extern "C" WEAK void mbed_main(void); 00406 extern "C" WEAK void mbed_main(void) { 00407 } 00408 00409 extern "C" WEAK void mbed_sdk_init(void); 00410 extern "C" WEAK void mbed_sdk_init(void) { 00411 } 00412 00413 #if defined(TOOLCHAIN_ARM) 00414 extern "C" int $Super$$main(void); 00415 00416 extern "C" int $Sub$$main(void) { 00417 mbed_sdk_init(); 00418 mbed_main(); 00419 return $Super$$main(); 00420 } 00421 #elif defined(TOOLCHAIN_GCC) 00422 extern "C" int __real_main(void); 00423 00424 extern "C" int __wrap_main(void) { 00425 mbed_sdk_init(); 00426 mbed_main(); 00427 return __real_main(); 00428 } 00429 #elif defined(TOOLCHAIN_IAR) 00430 // IAR doesn't have the $Super/$Sub mechanism of armcc, nor something equivalent 00431 // to ld's --wrap. It does have a --redirect, but that doesn't help, since redirecting 00432 // 'main' to another symbol looses the original 'main' symbol. However, its startup 00433 // code will call a function to setup argc and argv (__iar_argc_argv) if it is defined. 00434 // Since mbed doesn't use argc/argv, we use this function to call our mbed_main. 00435 extern "C" void __iar_argc_argv() { 00436 mbed_sdk_init(); 00437 mbed_main(); 00438 } 00439 #endif 00440 00441 // Provide implementation of _sbrk (low-level dynamic memory allocation 00442 // routine) for GCC_ARM which compares new heap pointer with MSP instead of 00443 // SP. This make it compatible with RTX RTOS thread stacks. 00444 #if defined(TOOLCHAIN_GCC_ARM) 00445 // Linker defined symbol used by _sbrk to indicate where heap should start. 00446 extern "C" int __end__; 00447 00448 // Turn off the errno macro and use actual global variable instead. 00449 #undef errno 00450 extern "C" int errno; 00451 00452 // For ARM7 only 00453 register unsigned char * stack_ptr __asm ("sp"); 00454 00455 // Dynamic memory allocation related syscall. 00456 extern "C" caddr_t _sbrk(int incr) { 00457 static unsigned char* heap = (unsigned char*)&__end__; 00458 unsigned char* prev_heap = heap; 00459 unsigned char* new_heap = heap + incr; 00460 00461 #if defined(TARGET_ARM7) 00462 if (new_heap >= stack_ptr) { 00463 #else 00464 if (new_heap >= (unsigned char*)__get_MSP()) { 00465 #endif 00466 errno = ENOMEM; 00467 return (caddr_t)-1; 00468 } 00469 00470 heap = new_heap; 00471 return (caddr_t) prev_heap; 00472 } 00473 #endif
Generated on Tue Jul 12 2022 21:21:33 by
