mbed
Fork of mbed-dev by
Embed:
(wiki syntax)
Show/hide line numbers
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
