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