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.
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 20:03:21 by
