1 /* 2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <string.h> 8 #include "pico/bootrom.h" 9 #include "pico/bootrom/sf_table.h" 10 11 // NOTE THIS FUNCTION TABLE IS NOT PUBLIC OR NECESSARILY COMPLETE... 12 // IT IS ***NOT*** SAFE TO CALL THESE FUNCTION POINTERS FROM ARBITRARY CODE 13 uint32_t sd_table[SF_TABLE_V2_SIZE / 2]; 14 15 #if !(PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED) missing_double_func_shim(void)16static __attribute__((noreturn)) void missing_double_func_shim(void) { 17 panic("missing double function"); 18 } 19 #endif 20 extern void double_table_shim_on_use_helper(void); 21 22 void __attribute__((weak)) *sf_clz_func; 23 __aeabi_double_init(void)24void __aeabi_double_init(void) { 25 int rom_version = rp2040_rom_version(); 26 #if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED 27 if (rom_version == 1) { 28 29 // this is a little tricky.. we only want to pull in a shim if the corresponding function 30 // is called. to that end we include a SVC instruction with the table offset as the call number 31 // followed by the shim function pointer inside the actual wrapper function. that way if the wrapper 32 // function is garbage collected, so is the shim function. 33 // 34 // double_table_shim_on_use_helper expects this SVC instruction in the calling code soon after the address 35 // pointed to by IP and patches the double_table entry with the real shim the first time the function is called. 36 for(uint i=0; i<SF_TABLE_V2_SIZE/4; i++) { 37 sd_table[i] = (uintptr_t)double_table_shim_on_use_helper; 38 } 39 } 40 #else 41 if (rom_version == 1) { 42 // opting for soft failure for now - you'll get a panic at runtime if you call any of the missing methods 43 for(uint i=0;i<SF_TABLE_V2_SIZE/4;i++) { 44 sd_table[i] = (uintptr_t)missing_double_func_shim; 45 } 46 } 47 #endif 48 if (rom_version >= 2) { 49 void *rom_table = rom_data_lookup(rom_table_code('S', 'D')); 50 assert(*((uint8_t *)rom_data_lookup(rom_table_code('S', 'F'))-2) * 4 >= SF_TABLE_V2_SIZE); 51 memcpy(&sd_table, rom_table, SF_TABLE_V2_SIZE); 52 if (rom_version == 2) { 53 #ifndef NDEBUG 54 if (*(uint16_t *)0x3854 != 0xb500 || // this is dsincos(_internal) 55 56 *(uint16_t *)0x38d8 != 0x4649 || // this is dsin_finish 57 *(uint16_t *)0x389c != 0x4659 // this is dcos_finish 58 ) { 59 panic(NULL); 60 } 61 #endif 62 } 63 } 64 if (rom_version < 3) { 65 // we use the unused entry for SINCOS 66 sd_table[SF_TABLE_V3_FSINCOS / 4] = (uintptr_t) double_table_shim_on_use_helper; 67 } 68 69 sf_clz_func = rom_func_lookup(ROM_FUNC_CLZ32); 70 } 71