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
mbed_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 <time.h> 00017 #include "platform/platform.h" 00018 #include "platform/FilePath.h" 00019 #include "hal/serial_api.h" 00020 #include "hal/us_ticker_api.h" 00021 #include "platform/mbed_toolchain.h" 00022 #include "platform/mbed_semihost_api.h" 00023 #include "platform/mbed_interface.h" 00024 #include "platform/SingletonPtr.h" 00025 #include "platform/PlatformMutex.h" 00026 #include "platform/mbed_error.h" 00027 #include "platform/mbed_stats.h" 00028 #include "platform/mbed_critical.h" 00029 #include "platform/PlatformMutex.h" 00030 #include "us_ticker_api.h" 00031 #include "lp_ticker_api.h" 00032 #include <stdlib.h> 00033 #include <string.h> 00034 #include <limits.h> 00035 #if DEVICE_STDIO_MESSAGES 00036 #include <stdio.h> 00037 #endif 00038 #include <errno.h> 00039 #include "platform/mbed_retarget.h" 00040 00041 static SingletonPtr<PlatformMutex> _mutex; 00042 00043 #if defined(__ARMCC_VERSION) 00044 # if __ARMCC_VERSION >= 6010050 00045 # include <arm_compat.h> 00046 # endif 00047 # include <rt_sys.h> 00048 # include <rt_misc.h> 00049 # include <stdint.h> 00050 # define PREFIX(x) _sys##x 00051 # define OPEN_MAX _SYS_OPEN 00052 # ifdef __MICROLIB 00053 # pragma import(__use_full_stdio) 00054 # endif 00055 00056 #elif defined(__ICCARM__) 00057 # include <yfuns.h> 00058 # define PREFIX(x) _##x 00059 # define OPEN_MAX 16 00060 00061 # define STDIN_FILENO 0 00062 # define STDOUT_FILENO 1 00063 # define STDERR_FILENO 2 00064 00065 #else 00066 # include <sys/syslimits.h> 00067 # define PREFIX(x) x 00068 #endif 00069 00070 #define FILE_HANDLE_RESERVED 0xFFFFFFFF 00071 00072 using namespace mbed; 00073 00074 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) 00075 // Before version 5.03, we were using a patched version of microlib with proper names 00076 extern const char __stdin_name[] = ":tt"; 00077 extern const char __stdout_name[] = ":tt"; 00078 extern const char __stderr_name[] = ":tt"; 00079 00080 #else 00081 extern const char __stdin_name[] = "/stdin"; 00082 extern const char __stdout_name[] = "/stdout"; 00083 extern const char __stderr_name[] = "/stderr"; 00084 #endif 00085 00086 unsigned char *mbed_heap_start = 0; 00087 uint32_t mbed_heap_size = 0; 00088 00089 /* newlib has the filehandle field in the FILE struct as a short, so 00090 * we can't just return a Filehandle* from _open and instead have to 00091 * put it in a filehandles array and return the index into that array 00092 * (or rather index+3, as filehandles 0-2 are stdin/out/err). 00093 */ 00094 static FileHandle *filehandles[OPEN_MAX]; 00095 static SingletonPtr<PlatformMutex> filehandle_mutex; 00096 00097 namespace mbed { 00098 void remove_filehandle(FileHandle *file) { 00099 filehandle_mutex->lock(); 00100 /* Remove all open filehandles for this */ 00101 for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { 00102 if (filehandles[fh_i] == file) { 00103 filehandles[fh_i] = NULL; 00104 } 00105 } 00106 filehandle_mutex->unlock(); 00107 } 00108 } 00109 00110 #if DEVICE_SERIAL 00111 extern int stdio_uart_inited; 00112 extern serial_t stdio_uart; 00113 #if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES 00114 static char stdio_in_prev; 00115 static char stdio_out_prev; 00116 #endif 00117 #endif 00118 00119 static void init_serial() { 00120 #if DEVICE_SERIAL 00121 if (stdio_uart_inited) return; 00122 serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); 00123 #if MBED_CONF_PLATFORM_STDIO_BAUD_RATE 00124 serial_baud(&stdio_uart, MBED_CONF_PLATFORM_STDIO_BAUD_RATE); 00125 #endif 00126 #endif 00127 } 00128 00129 /** 00130 * Sets errno when file opening fails. 00131 * Wipes out the filehandle too. 00132 * 00133 * @param error is a negative error code returned from an mbed function and 00134 * will be negated to store a positive error code in errno 00135 */ 00136 static int handle_open_errors(int error, unsigned filehandle_idx) { 00137 errno = -error; 00138 // Free file handle 00139 filehandles[filehandle_idx] = NULL; 00140 return -1; 00141 } 00142 00143 static inline int openmode_to_posix(int openmode) { 00144 int posix = openmode; 00145 #ifdef __ARMCC_VERSION 00146 if (openmode & OPEN_PLUS) { 00147 posix = O_RDWR; 00148 } else if(openmode & OPEN_W) { 00149 posix = O_WRONLY; 00150 } else if(openmode & OPEN_A) { 00151 posix = O_WRONLY|O_APPEND; 00152 } else { 00153 posix = O_RDONLY; 00154 } 00155 /* a, w, a+, w+ all create if file does not already exist */ 00156 if (openmode & (OPEN_A|OPEN_W)) { 00157 posix |= O_CREAT; 00158 } 00159 /* w and w+ truncate */ 00160 if (openmode & OPEN_W) { 00161 posix |= O_TRUNC; 00162 } 00163 #elif defined(__ICCARM__) 00164 switch (openmode & _LLIO_RDWRMASK) { 00165 case _LLIO_RDONLY: posix = O_RDONLY; break; 00166 case _LLIO_WRONLY: posix = O_WRONLY; break; 00167 case _LLIO_RDWR : posix = O_RDWR ; break; 00168 } 00169 if (openmode & _LLIO_CREAT ) posix |= O_CREAT; 00170 if (openmode & _LLIO_APPEND) posix |= O_APPEND; 00171 if (openmode & _LLIO_TRUNC ) posix |= O_TRUNC; 00172 #elif defined(TOOLCHAIN_GCC) 00173 posix &= ~O_BINARY; 00174 #endif 00175 return posix; 00176 } 00177 00178 /* @brief standard c library fopen() retargeting function. 00179 * 00180 * This function is invoked by the standard c library retargeting to handle fopen() 00181 * 00182 * @return 00183 * On success, a valid FILEHANDLE is returned. 00184 * On failure, -1 is returned and errno is set to an appropriate value e.g. 00185 * ENOENT file not found (default errno setting) 00186 * EMFILE the maximum number of open files was exceeded. 00187 * 00188 * */ 00189 extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) { 00190 #if defined(__MICROLIB) && (__ARMCC_VERSION>5030000) 00191 #if !defined(MBED_CONF_RTOS_PRESENT) 00192 // valid only for mbed 2 00193 // for ulib, this is invoked after RAM init, prior c++ 00194 // used as hook, as post stack/heap is not active there 00195 extern void mbed_copy_nvic(void); 00196 extern void mbed_sdk_init(void); 00197 00198 static int mbed_sdk_inited = 0; 00199 if (!mbed_sdk_inited) { 00200 mbed_copy_nvic(); 00201 mbed_sdk_init(); 00202 mbed_sdk_inited = 1; 00203 } 00204 #endif 00205 // Before version 5.03, we were using a patched version of microlib with proper names 00206 // This is the workaround that the microlib author suggested us 00207 static int n = 0; 00208 if (!std::strcmp(name, ":tt")) return n++; 00209 #else 00210 /* Use the posix convention that stdin,out,err are filehandles 0,1,2. 00211 */ 00212 if (std::strcmp(name, __stdin_name) == 0) { 00213 init_serial(); 00214 return 0; 00215 } else if (std::strcmp(name, __stdout_name) == 0) { 00216 init_serial(); 00217 return 1; 00218 } else if (std::strcmp(name, __stderr_name) == 0) { 00219 init_serial(); 00220 return 2; 00221 } 00222 #endif 00223 00224 // find the first empty slot in filehandles 00225 filehandle_mutex->lock(); 00226 unsigned int fh_i; 00227 for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) { 00228 /* Take a next free filehandle slot available. */ 00229 if (filehandles[fh_i] == NULL) break; 00230 } 00231 if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) { 00232 /* Too many file handles have been opened */ 00233 errno = EMFILE; 00234 filehandle_mutex->unlock(); 00235 return -1; 00236 } 00237 filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED; 00238 filehandle_mutex->unlock(); 00239 00240 FileHandle *res = NULL; 00241 00242 /* FILENAME: ":(pointer)" describes a FileHandle* */ 00243 if (name[0] == ':') { 00244 void *p; 00245 memcpy(&p, name + 1, sizeof(p)); 00246 res = (FileHandle*)p; 00247 00248 /* FILENAME: "/file_system/file_name" */ 00249 } else { 00250 FilePath path(name); 00251 00252 if (!path.exists()) { 00253 /* The first part of the filename (between first 2 '/') is not a 00254 * registered mount point in the namespace. 00255 */ 00256 return handle_open_errors(-ENODEV, fh_i); 00257 } 00258 00259 if (path.isFile()) { 00260 res = path.file(); 00261 } else { 00262 FileSystemHandle *fs = path.fileSystem(); 00263 if (fs == NULL) { 00264 return handle_open_errors(-ENODEV, fh_i); 00265 } 00266 int posix_mode = openmode_to_posix(openmode); 00267 int err = fs->open(&res, path.fileName(), posix_mode); 00268 if (err) { 00269 return handle_open_errors(err, fh_i); 00270 } 00271 } 00272 } 00273 00274 filehandles[fh_i] = res; 00275 00276 return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err 00277 } 00278 00279 extern "C" int PREFIX(_close)(FILEHANDLE fh) { 00280 if (fh < 3) return 0; 00281 00282 FileHandle* fhc = filehandles[fh-3]; 00283 filehandles[fh-3] = NULL; 00284 if (fhc == NULL) { 00285 errno = EBADF; 00286 return -1; 00287 } 00288 00289 int err = fhc->close(); 00290 if (err < 0) { 00291 errno = -err; 00292 return -1; 00293 } else { 00294 return 0; 00295 } 00296 } 00297 00298 #if defined(__ICCARM__) 00299 extern "C" size_t __write (int fh, const unsigned char *buffer, size_t length) { 00300 #else 00301 extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsigned int length, int mode) { 00302 #endif 00303 int n; // n is the number of bytes written 00304 00305 #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00306 if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { 00307 error("Error - writing to a file in an ISR or critical section\r\n"); 00308 } 00309 #endif 00310 00311 if (fh < 3) { 00312 #if DEVICE_SERIAL 00313 if (!stdio_uart_inited) init_serial(); 00314 #if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES 00315 for (unsigned int i = 0; i < length; i++) { 00316 if (buffer[i] == '\n' && stdio_out_prev != '\r') { 00317 serial_putc(&stdio_uart, '\r'); 00318 } 00319 serial_putc(&stdio_uart, buffer[i]); 00320 stdio_out_prev = buffer[i]; 00321 } 00322 #else 00323 for (unsigned int i = 0; i < length; i++) { 00324 serial_putc(&stdio_uart, buffer[i]); 00325 } 00326 #endif 00327 #endif 00328 n = length; 00329 } else { 00330 FileHandle* fhc = filehandles[fh-3]; 00331 if (fhc == NULL) { 00332 errno = EBADF; 00333 return -1; 00334 } 00335 00336 n = fhc->write(buffer, length); 00337 if (n < 0) { 00338 errno = -n; 00339 } 00340 } 00341 #ifdef __ARMCC_VERSION 00342 return length-n; 00343 #else 00344 return n; 00345 #endif 00346 } 00347 00348 #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) 00349 extern "C" void PREFIX(_exit)(int return_code) { 00350 while(1) {} 00351 } 00352 00353 extern "C" void _ttywrch(int ch) { 00354 #if DEVICE_SERIAL 00355 serial_putc(&stdio_uart, ch); 00356 #endif 00357 } 00358 #endif 00359 00360 #if defined(__ICCARM__) 00361 extern "C" size_t __read (int fh, unsigned char *buffer, size_t length) { 00362 #else 00363 extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int length, int mode) { 00364 #endif 00365 int n; // n is the number of bytes read 00366 00367 #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00368 if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { 00369 error("Error - reading from a file in an ISR or critical section\r\n"); 00370 } 00371 #endif 00372 00373 if (fh < 3) { 00374 // only read a character at a time from stdin 00375 #if DEVICE_SERIAL 00376 if (!stdio_uart_inited) init_serial(); 00377 #if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES 00378 while (true) { 00379 char c = serial_getc(&stdio_uart); 00380 if ((c == '\r' && stdio_in_prev != '\n') || 00381 (c == '\n' && stdio_in_prev != '\r')) { 00382 stdio_in_prev = c; 00383 *buffer = '\n'; 00384 break; 00385 } else if ((c == '\r' && stdio_in_prev == '\n') || 00386 (c == '\n' && stdio_in_prev == '\r')) { 00387 stdio_in_prev = c; 00388 // onto next character 00389 continue; 00390 } else { 00391 stdio_in_prev = c; 00392 *buffer = c; 00393 break; 00394 } 00395 } 00396 #else 00397 *buffer = serial_getc(&stdio_uart); 00398 #endif 00399 #endif 00400 n = 1; 00401 } else { 00402 FileHandle* fhc = filehandles[fh-3]; 00403 if (fhc == NULL) { 00404 errno = EBADF; 00405 return -1; 00406 } 00407 00408 n = fhc->read(buffer, length); 00409 if (n < 0) { 00410 errno = -n; 00411 } 00412 } 00413 #ifdef __ARMCC_VERSION 00414 return length-n; 00415 #else 00416 return n; 00417 #endif 00418 } 00419 00420 00421 #ifdef __ARMCC_VERSION 00422 extern "C" int PREFIX(_istty)(FILEHANDLE fh) 00423 #else 00424 extern "C" int _isatty(FILEHANDLE fh) 00425 #endif 00426 { 00427 /* stdin, stdout and stderr should be tty */ 00428 if (fh < 3) return 1; 00429 00430 FileHandle* fhc = filehandles[fh-3]; 00431 if (fhc == NULL) { 00432 errno = EBADF; 00433 return 0; 00434 } 00435 00436 int tty = fhc->isatty(); 00437 if (tty < 0) { 00438 errno = -tty; 00439 return 0; 00440 } else { 00441 return tty; 00442 } 00443 } 00444 00445 extern "C" 00446 #if defined(__ARMCC_VERSION) 00447 int _sys_seek(FILEHANDLE fh, long offset) 00448 #elif defined(__ICCARM__) 00449 long __lseek(int fh, long offset, int whence) 00450 #else 00451 int _lseek(FILEHANDLE fh, int offset, int whence) 00452 #endif 00453 { 00454 #if defined(__ARMCC_VERSION) 00455 int whence = SEEK_SET; 00456 #endif 00457 00458 if (fh < 3) { 00459 errno = ESPIPE; 00460 return -1; 00461 } 00462 00463 FileHandle* fhc = filehandles[fh-3]; 00464 if (fhc == NULL) { 00465 errno = EBADF; 00466 return -1; 00467 } 00468 00469 off_t off = fhc->seek(offset, whence); 00470 if (off < 0) { 00471 errno = -off; 00472 return -1; 00473 } 00474 // Assuming INT_MAX = LONG_MAX, so we don't care about prototype difference 00475 if (off > INT_MAX) { 00476 errno = EOVERFLOW; 00477 return -1; 00478 } 00479 return off; 00480 } 00481 00482 #ifdef __ARMCC_VERSION 00483 extern "C" int PREFIX(_ensure)(FILEHANDLE fh) { 00484 if (fh < 3) return 0; 00485 00486 FileHandle* fhc = filehandles[fh-3]; 00487 if (fhc == NULL) { 00488 errno = EBADF; 00489 return -1; 00490 } 00491 00492 int err = fhc->sync(); 00493 if (err < 0) { 00494 errno = -err; 00495 return -1; 00496 } else { 00497 return 0; 00498 } 00499 } 00500 00501 extern "C" long PREFIX(_flen)(FILEHANDLE fh) { 00502 if (fh < 3) { 00503 errno = EINVAL; 00504 return -1; 00505 } 00506 00507 FileHandle* fhc = filehandles[fh-3]; 00508 if (fhc == NULL) { 00509 errno = EBADF; 00510 return -1; 00511 } 00512 00513 off_t size = fhc->size(); 00514 if (size < 0) { 00515 errno = -size; 00516 return -1; 00517 } 00518 if (size > LONG_MAX) { 00519 errno = EOVERFLOW; 00520 return -1; 00521 } 00522 return size; 00523 } 00524 00525 extern "C" char Image$$RW_IRAM1$$ZI$$Limit[]; 00526 00527 extern "C" MBED_WEAK __value_in_regs struct __initial_stackheap _mbed_user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3) 00528 { 00529 uint32_t zi_limit = (uint32_t)Image$$RW_IRAM1$$ZI$$Limit; 00530 uint32_t sp_limit = __current_sp(); 00531 00532 zi_limit = (zi_limit + 7) & ~0x7; // ensure zi_limit is 8-byte aligned 00533 00534 struct __initial_stackheap r; 00535 r.heap_base = zi_limit; 00536 r.heap_limit = sp_limit; 00537 return r; 00538 } 00539 00540 extern "C" __value_in_regs struct __initial_stackheap __user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3) { 00541 return _mbed_user_setup_stackheap(R0, R1, R2, R3); 00542 } 00543 00544 #endif 00545 00546 00547 #if !defined(__ARMCC_VERSION) && !defined(__ICCARM__) 00548 extern "C" int _fstat(int fh, struct stat *st) { 00549 if (fh < 3) { 00550 st->st_mode = S_IFCHR; 00551 return 0; 00552 } 00553 00554 FileHandle* fhc = filehandles[fh-3]; 00555 if (fhc == NULL) { 00556 errno = EBADF; 00557 return -1; 00558 } 00559 00560 st->st_mode = fhc->isatty() ? S_IFCHR : S_IFREG; 00561 st->st_size = fhc->size(); 00562 return 0; 00563 } 00564 #endif 00565 00566 namespace std { 00567 extern "C" int remove(const char *path) { 00568 FilePath fp(path); 00569 FileSystemHandle *fs = fp.fileSystem(); 00570 if (fs == NULL) { 00571 errno = ENODEV; 00572 return -1; 00573 } 00574 00575 int err = fs->remove(fp.fileName()); 00576 if (err < 0) { 00577 errno = -err; 00578 return -1; 00579 } else { 00580 return 0; 00581 } 00582 } 00583 00584 extern "C" int rename(const char *oldname, const char *newname) { 00585 FilePath fpOld(oldname); 00586 FilePath fpNew(newname); 00587 FileSystemHandle *fsOld = fpOld.fileSystem(); 00588 FileSystemHandle *fsNew = fpNew.fileSystem(); 00589 00590 if (fsOld == NULL) { 00591 errno = ENODEV; 00592 return -1; 00593 } 00594 00595 /* rename only if both files are on the same FS */ 00596 if (fsOld != fsNew) { 00597 errno = EXDEV; 00598 return -1; 00599 } 00600 00601 int err = fsOld->rename(fpOld.fileName(), fpNew.fileName()); 00602 if (err < 0) { 00603 errno = -err; 00604 return -1; 00605 } else { 00606 return 0; 00607 } 00608 } 00609 00610 extern "C" char *tmpnam(char *s) { 00611 errno = EBADF; 00612 return NULL; 00613 } 00614 00615 extern "C" FILE *tmpfile() { 00616 errno = EBADF; 00617 return NULL; 00618 } 00619 } // namespace std 00620 00621 #ifdef __ARMCC_VERSION 00622 extern "C" char *_sys_command_string(char *cmd, int len) { 00623 return NULL; 00624 } 00625 #endif 00626 00627 extern "C" DIR *opendir(const char *path) { 00628 FilePath fp(path); 00629 FileSystemHandle* fs = fp.fileSystem(); 00630 if (fs == NULL) { 00631 errno = ENODEV; 00632 return NULL; 00633 } 00634 00635 DirHandle *dir; 00636 int err = fs->open(&dir, fp.fileName()); 00637 if (err < 0) { 00638 errno = -err; 00639 return NULL; 00640 } 00641 00642 return dir; 00643 } 00644 00645 extern "C" struct dirent *readdir(DIR *dir) { 00646 static struct dirent ent; 00647 int err = dir->read(&ent); 00648 if (err < 1) { 00649 if (err < 0) { 00650 errno = -err; 00651 } 00652 return NULL; 00653 } 00654 00655 return &ent; 00656 } 00657 00658 extern "C" int closedir(DIR *dir) { 00659 int err = dir->close(); 00660 if (err < 0) { 00661 errno = -err; 00662 return -1; 00663 } else { 00664 return 0; 00665 } 00666 } 00667 00668 extern "C" void rewinddir(DIR *dir) { 00669 dir->rewind(); 00670 } 00671 00672 extern "C" off_t telldir(DIR *dir) { 00673 return dir->tell(); 00674 } 00675 00676 extern "C" void seekdir(DIR *dir, off_t off) { 00677 dir->seek(off); 00678 } 00679 00680 extern "C" int mkdir(const char *path, mode_t mode) { 00681 FilePath fp(path); 00682 FileSystemHandle *fs = fp.fileSystem(); 00683 if (fs == NULL) { 00684 errno = ENODEV; 00685 return -1; 00686 } 00687 00688 int err = fs->mkdir(fp.fileName(), mode); 00689 if (err < 0) { 00690 errno = -err; 00691 return -1; 00692 } else { 00693 return 0; 00694 } 00695 } 00696 00697 extern "C" int stat(const char *path, struct stat *st) { 00698 FilePath fp(path); 00699 FileSystemHandle *fs = fp.fileSystem(); 00700 if (fs == NULL) { 00701 errno = ENODEV; 00702 return -1; 00703 } 00704 00705 int err = fs->stat(fp.fileName(), st); 00706 if (err < 0) { 00707 errno = -err; 00708 return -1; 00709 } else { 00710 return 0; 00711 } 00712 } 00713 00714 #if defined(TOOLCHAIN_GCC) 00715 /* prevents the exception handling name demangling code getting pulled in */ 00716 #include "mbed_error.h" 00717 namespace __gnu_cxx { 00718 void __verbose_terminate_handler() { 00719 error("Exception"); 00720 } 00721 } 00722 extern "C" WEAK void __cxa_pure_virtual(void); 00723 extern "C" WEAK void __cxa_pure_virtual(void) { 00724 exit(1); 00725 } 00726 00727 #endif 00728 00729 // Provide implementation of _sbrk (low-level dynamic memory allocation 00730 // routine) for GCC_ARM which compares new heap pointer with MSP instead of 00731 // SP. This make it compatible with RTX RTOS thread stacks. 00732 #if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_GCC_CR) 00733 00734 #if defined(TARGET_CORTEX_A) 00735 extern "C" uint32_t __HeapLimit; 00736 #endif 00737 00738 // Turn off the errno macro and use actual global variable instead. 00739 #undef errno 00740 extern "C" int errno; 00741 00742 // Dynamic memory allocation related syscall. 00743 #if defined(TARGET_NUVOTON) 00744 00745 // Overwrite _sbrk() to support two region model (heap and stack are two distinct regions). 00746 // __wrap__sbrk() is implemented in: 00747 // TARGET_NUMAKER_PFM_NUC472 targets/TARGET_NUVOTON/TARGET_NUC472/TARGET_NUMAKER_PFM_NUC472/TOOLCHAIN_GCC_ARM/nuc472_retarget.c 00748 // TARGET_NUMAKER_PFM_M453 targets/TARGET_NUVOTON/TARGET_M451/TARGET_NUMAKER_PFM_M453/TOOLCHAIN_GCC_ARM/m451_retarget.c 00749 extern "C" void *__wrap__sbrk(int incr); 00750 extern "C" caddr_t _sbrk(int incr) { 00751 return (caddr_t) __wrap__sbrk(incr); 00752 } 00753 #else 00754 // Linker defined symbol used by _sbrk to indicate where heap should start. 00755 extern "C" uint32_t __end__; 00756 // Weak attribute allows user to override, e.g. to use external RAM for dynamic memory. 00757 extern "C" WEAK caddr_t _sbrk(int incr) { 00758 static unsigned char* heap = (unsigned char*)&__end__; 00759 unsigned char* prev_heap = heap; 00760 unsigned char* new_heap = heap + incr; 00761 00762 #if defined(TARGET_CORTEX_A) 00763 if (new_heap >= (unsigned char*)&__HeapLimit) { /* __HeapLimit is end of heap section */ 00764 #else 00765 if (new_heap >= (unsigned char*)__get_MSP()) { 00766 #endif 00767 errno = ENOMEM; 00768 return (caddr_t)-1; 00769 } 00770 00771 // Additional heap checking if set 00772 if (mbed_heap_size && (new_heap >= mbed_heap_start + mbed_heap_size)) { 00773 errno = ENOMEM; 00774 return (caddr_t)-1; 00775 } 00776 00777 heap = new_heap; 00778 return (caddr_t) prev_heap; 00779 } 00780 #endif 00781 #endif 00782 00783 #if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_GCC_CR) 00784 extern "C" void _exit(int return_code) { 00785 #else 00786 namespace std { 00787 extern "C" void exit(int return_code) { 00788 #endif 00789 00790 #if DEVICE_STDIO_MESSAGES 00791 #if MBED_CONF_PLATFORM_STDIO_FLUSH_AT_EXIT 00792 fflush(stdout); 00793 fflush(stderr); 00794 #endif 00795 #endif 00796 00797 #if DEVICE_SEMIHOST 00798 if (mbed_interface_connected()) { 00799 semihost_exit(); 00800 } 00801 #endif 00802 if (return_code) { 00803 mbed_die(); 00804 } 00805 00806 while (1); 00807 } 00808 00809 #if !defined(TOOLCHAIN_GCC_ARM) && !defined(TOOLCHAIN_GCC_CR) 00810 } //namespace std 00811 #endif 00812 00813 #if defined(TOOLCHAIN_ARM) || defined(TOOLCHAIN_GCC) 00814 00815 // This series of function disable the registration of global destructors 00816 // in a dynamic table which will be called when the application exit. 00817 // In mbed, program never exit properly, it dies. 00818 // More informations about this topic for ARMCC here: 00819 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/6449.html 00820 extern "C" { 00821 int __aeabi_atexit(void *object, void (*dtor)(void* /*this*/), void *handle) { 00822 return 1; 00823 } 00824 00825 int __cxa_atexit(void (*dtor)(void* /*this*/), void *object, void *handle) { 00826 return 1; 00827 } 00828 00829 void __cxa_finalize(void *handle) { 00830 } 00831 00832 } // end of extern "C" 00833 00834 #endif 00835 00836 00837 #if defined(TOOLCHAIN_GCC) 00838 00839 /* 00840 * Depending on how newlib is configured, it is often not enough to define 00841 * __aeabi_atexit, __cxa_atexit and __cxa_finalize in order to override the 00842 * behavior regarding the registration of handlers with atexit. 00843 * 00844 * To overcome this limitation, exit and atexit are overriden here. 00845 */ 00846 extern "C"{ 00847 00848 /** 00849 * @brief Retarget of exit for GCC. 00850 * @details Unlike the standard version, this function doesn't call any function 00851 * registered with atexit before calling _exit. 00852 */ 00853 void __wrap_exit(int return_code) { 00854 _exit(return_code); 00855 } 00856 00857 /** 00858 * @brief Retarget atexit from GCC. 00859 * @details This function will always fail and never register any handler to be 00860 * called at exit. 00861 */ 00862 int __wrap_atexit(void (*func)()) { 00863 return 1; 00864 } 00865 00866 } 00867 00868 #endif 00869 00870 00871 00872 namespace mbed { 00873 00874 void mbed_set_unbuffered_stream(std::FILE *_file) { 00875 #if defined (__ICCARM__) 00876 char buf[2]; 00877 std::setvbuf(_file,buf,_IONBF,NULL); 00878 #else 00879 setbuf(_file, NULL); 00880 #endif 00881 } 00882 00883 /* Applications are expected to use fdopen() 00884 * not this function directly. This code had to live here because FILE and FileHandle 00885 * processes are all linked together here. 00886 */ 00887 std::FILE *mbed_fdopen(FileHandle *fh, const char *mode) 00888 { 00889 // This is to avoid scanf(buf, ":%.4s", fh) and the bloat it brings. 00890 char buf[1 + sizeof(fh)]; /* :(pointer) */ 00891 MBED_STATIC_ASSERT(sizeof(buf) == 5, "Pointers should be 4 bytes."); 00892 buf[0] = ':'; 00893 memcpy(buf + 1, &fh, sizeof(fh)); 00894 00895 std::FILE *stream = std::fopen(buf, mode); 00896 /* newlib-nano doesn't appear to ever call _isatty itself, so 00897 * happily fully buffers an interactive stream. Deal with that here. 00898 */ 00899 if (stream && fh->isatty()) { 00900 mbed_set_unbuffered_stream(stream); 00901 } 00902 return stream; 00903 } 00904 00905 int mbed_getc(std::FILE *_file){ 00906 #if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ < 8000000) 00907 /*This is only valid for unbuffered streams*/ 00908 int res = std::fgetc(_file); 00909 if (res>=0){ 00910 _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */ 00911 _file->_Rend = _file->_Wend; 00912 _file->_Next = _file->_Wend; 00913 } 00914 return res; 00915 #else 00916 return std::fgetc(_file); 00917 #endif 00918 } 00919 00920 char* mbed_gets(char*s, int size, std::FILE *_file){ 00921 #if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ < 8000000) 00922 /*This is only valid for unbuffered streams*/ 00923 char *str = fgets(s,size,_file); 00924 if (str!=NULL){ 00925 _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */ 00926 _file->_Rend = _file->_Wend; 00927 _file->_Next = _file->_Wend; 00928 } 00929 return str; 00930 #else 00931 return std::fgets(s,size,_file); 00932 #endif 00933 } 00934 00935 } // namespace mbed 00936 00937 #if defined (__ICCARM__) 00938 // Stub out locks when an rtos is not present 00939 extern "C" WEAK void __iar_system_Mtxinit(__iar_Rmtx *mutex) {} 00940 extern "C" WEAK void __iar_system_Mtxdst(__iar_Rmtx *mutex) {} 00941 extern "C" WEAK void __iar_system_Mtxlock(__iar_Rmtx *mutex) {} 00942 extern "C" WEAK void __iar_system_Mtxunlock(__iar_Rmtx *mutex) {} 00943 extern "C" WEAK void __iar_file_Mtxinit(__iar_Rmtx *mutex) {} 00944 extern "C" WEAK void __iar_file_Mtxdst(__iar_Rmtx *mutex) {} 00945 extern "C" WEAK void __iar_file_Mtxlock(__iar_Rmtx *mutex) {} 00946 extern "C" WEAK void __iar_file_Mtxunlock(__iar_Rmtx *mutex) {} 00947 #if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ >= 8000000) 00948 #pragma section="__iar_tls$$DATA" 00949 extern "C" WEAK void *__aeabi_read_tp (void) { 00950 // Thread Local storage is not supported, using main thread memory for errno 00951 return __section_begin("__iar_tls$$DATA"); 00952 } 00953 #endif 00954 #elif defined(__CC_ARM) 00955 // Do nothing 00956 #elif defined (__GNUC__) 00957 struct _reent; 00958 // Stub out locks when an rtos is not present 00959 extern "C" WEAK void __rtos_malloc_lock( struct _reent *_r ) {} 00960 extern "C" WEAK void __rtos_malloc_unlock( struct _reent *_r ) {} 00961 extern "C" WEAK void __rtos_env_lock( struct _reent *_r ) {} 00962 extern "C" WEAK void __rtos_env_unlock( struct _reent *_r ) {} 00963 00964 extern "C" void __malloc_lock( struct _reent *_r ) 00965 { 00966 __rtos_malloc_lock(_r); 00967 } 00968 00969 extern "C" void __malloc_unlock( struct _reent *_r ) 00970 { 00971 __rtos_malloc_unlock(_r); 00972 } 00973 00974 extern "C" void __env_lock( struct _reent *_r ) 00975 { 00976 __rtos_env_lock(_r); 00977 } 00978 00979 extern "C" void __env_unlock( struct _reent *_r ) 00980 { 00981 __rtos_env_unlock(_r); 00982 } 00983 00984 #endif 00985 00986 #if defined (__GNUC__) || defined(__CC_ARM) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) 00987 00988 #define CXA_GUARD_INIT_DONE (1 << 0) 00989 #define CXA_GUARD_INIT_IN_PROGRESS (1 << 1) 00990 #define CXA_GUARD_MASK (CXA_GUARD_INIT_DONE | CXA_GUARD_INIT_IN_PROGRESS) 00991 00992 extern "C" int __cxa_guard_acquire(int *guard_object_p) 00993 { 00994 uint8_t *guard_object = (uint8_t *)guard_object_p; 00995 if (CXA_GUARD_INIT_DONE == (*guard_object & CXA_GUARD_MASK)) { 00996 return 0; 00997 } 00998 singleton_lock(); 00999 if (CXA_GUARD_INIT_DONE == (*guard_object & CXA_GUARD_MASK)) { 01000 singleton_unlock(); 01001 return 0; 01002 } 01003 MBED_ASSERT(0 == (*guard_object & CXA_GUARD_MASK)); 01004 *guard_object = *guard_object | CXA_GUARD_INIT_IN_PROGRESS; 01005 return 1; 01006 } 01007 01008 extern "C" void __cxa_guard_release(int *guard_object_p) 01009 { 01010 uint8_t *guard_object = (uint8_t *)guard_object_p; 01011 MBED_ASSERT(CXA_GUARD_INIT_IN_PROGRESS == (*guard_object & CXA_GUARD_MASK)); 01012 *guard_object = (*guard_object & ~CXA_GUARD_MASK) | CXA_GUARD_INIT_DONE; 01013 singleton_unlock(); 01014 } 01015 01016 extern "C" void __cxa_guard_abort(int *guard_object_p) 01017 { 01018 uint8_t *guard_object = (uint8_t *)guard_object_p; 01019 MBED_ASSERT(CXA_GUARD_INIT_IN_PROGRESS == (*guard_object & CXA_GUARD_MASK)); 01020 *guard_object = *guard_object & ~CXA_GUARD_INIT_IN_PROGRESS; 01021 singleton_unlock(); 01022 } 01023 01024 #endif 01025 01026 #if defined(MBED_MEM_TRACING_ENABLED) && (defined(__CC_ARM) || defined(__ICCARM__)) 01027 01028 // If the memory tracing is enabled, the wrappers in mbed_alloc_wrappers.cpp 01029 // provide the implementation for these. Note: this needs to use the wrappers 01030 // instead of malloc()/free() as the caller address would point to wrappers, 01031 // not the caller of "new" or "delete". 01032 extern "C" void* malloc_wrapper(size_t size, const void* caller); 01033 extern "C" void free_wrapper(void *ptr, const void* caller); 01034 01035 void *operator new(std::size_t count) 01036 { 01037 void *buffer = malloc_wrapper(count, MBED_CALLER_ADDR()); 01038 if (NULL == buffer) { 01039 error("Operator new out of memory\r\n"); 01040 } 01041 return buffer; 01042 } 01043 01044 void *operator new[](std::size_t count) 01045 { 01046 void *buffer = malloc_wrapper(count, MBED_CALLER_ADDR()); 01047 if (NULL == buffer) { 01048 error("Operator new[] out of memory\r\n"); 01049 } 01050 return buffer; 01051 } 01052 01053 void *operator new(std::size_t count, const std::nothrow_t& tag) 01054 { 01055 return malloc_wrapper(count, MBED_CALLER_ADDR()); 01056 } 01057 01058 void *operator new[](std::size_t count, const std::nothrow_t& tag) 01059 { 01060 return malloc_wrapper(count, MBED_CALLER_ADDR()); 01061 } 01062 01063 void operator delete(void *ptr) 01064 { 01065 free_wrapper(ptr, MBED_CALLER_ADDR()); 01066 } 01067 void operator delete[](void *ptr) 01068 { 01069 free_wrapper(ptr, MBED_CALLER_ADDR()); 01070 } 01071 01072 #elif defined(MBED_MEM_TRACING_ENABLED) && defined(__GNUC__) 01073 01074 #include <reent.h> 01075 01076 extern "C" void* malloc_wrapper(struct _reent * r, size_t size, void * caller); 01077 extern "C" void free_wrapper(struct _reent * r, void * ptr, void * caller); 01078 01079 void *operator new(std::size_t count) 01080 { 01081 void *buffer = malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); 01082 if (NULL == buffer) { 01083 error("Operator new out of memory\r\n"); 01084 } 01085 return buffer; 01086 } 01087 01088 void *operator new[](std::size_t count) 01089 { 01090 void *buffer = malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); 01091 if (NULL == buffer) { 01092 error("Operator new[] out of memory\r\n"); 01093 } 01094 return buffer; 01095 } 01096 01097 void *operator new(std::size_t count, const std::nothrow_t& tag) 01098 { 01099 return malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); 01100 } 01101 01102 void *operator new[](std::size_t count, const std::nothrow_t& tag) 01103 { 01104 return malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); 01105 } 01106 01107 void operator delete(void *ptr) 01108 { 01109 free_wrapper(_REENT, ptr, MBED_CALLER_ADDR()); 01110 } 01111 01112 void operator delete[](void *ptr) 01113 { 01114 free_wrapper(_REENT, ptr, MBED_CALLER_ADDR()); 01115 } 01116 01117 #else 01118 01119 void *operator new(std::size_t count) 01120 { 01121 void *buffer = malloc(count); 01122 if (NULL == buffer) { 01123 error("Operator new out of memory\r\n"); 01124 } 01125 return buffer; 01126 } 01127 01128 void *operator new[](std::size_t count) 01129 { 01130 void *buffer = malloc(count); 01131 if (NULL == buffer) { 01132 error("Operator new[] out of memory\r\n"); 01133 } 01134 return buffer; 01135 } 01136 01137 void *operator new(std::size_t count, const std::nothrow_t& tag) 01138 { 01139 return malloc(count); 01140 } 01141 01142 void *operator new[](std::size_t count, const std::nothrow_t& tag) 01143 { 01144 return malloc(count); 01145 } 01146 01147 void operator delete(void *ptr) 01148 { 01149 free(ptr); 01150 } 01151 void operator delete[](void *ptr) 01152 { 01153 free(ptr); 01154 } 01155 01156 #endif 01157 01158 /* @brief standard c library clock() function. 01159 * 01160 * This function returns the number of clock ticks elapsed since the start of the program. 01161 * 01162 * @note Synchronization level: Thread safe 01163 * 01164 * @return 01165 * the number of clock ticks elapsed since the start of the program. 01166 * 01167 * */ 01168 extern "C" clock_t clock() 01169 { 01170 _mutex->lock(); 01171 clock_t t = ticker_read(get_us_ticker_data()); 01172 t /= 1000000 / CLOCKS_PER_SEC; // convert to processor time 01173 _mutex->unlock(); 01174 return t; 01175 } 01176 01177 // temporary - Default to 1MHz at 32 bits if target does not have us_ticker_get_info 01178 MBED_WEAK const ticker_info_t* us_ticker_get_info() 01179 { 01180 static const ticker_info_t info = { 01181 1000000, 01182 32 01183 }; 01184 return &info; 01185 } 01186 01187 // temporary - Default to 1MHz at 32 bits if target does not have lp_ticker_get_info 01188 MBED_WEAK const ticker_info_t* lp_ticker_get_info() 01189 { 01190 static const ticker_info_t info = { 01191 1000000, 01192 32 01193 }; 01194 return &info; 01195 }
Generated on Tue Jul 12 2022 18:02:51 by
1.7.2
