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 sf_table[SF_TABLE_V2_SIZE / 2];
14 void __attribute__((weak)) *sf_clz_func;
15 
16 #if !(PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED)
missing_float_func_shim(void)17 static __attribute__((noreturn)) void missing_float_func_shim(void) {
18     panic("");
19 }
20 #endif
21 
__aeabi_float_init(void)22 void __aeabi_float_init(void) {
23     int rom_version = rp2040_rom_version();
24     void *rom_table = rom_data_lookup(rom_table_code('S', 'F'));
25 #if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
26     if (rom_version == 1) {
27         memcpy(&sf_table, rom_table, SF_TABLE_V1_SIZE);
28         extern void float_table_shim_on_use_helper(void);
29         // todo replace NDEBUG with a more exclusive assertion guard
30 #ifndef NDEBUG
31         if (*(uint16_t *)0x29ee != 0x0fc4 || // this is packx
32             *(uint16_t *)0x29c0 != 0x0dc2 || // this is upackx
33             *(uint16_t *)0x2b96 != 0xb5c0 || // this is cordic_vec
34             *(uint16_t *)0x2b18 != 0x2500 || // this is packretns
35             *(uint16_t *)0x2acc != 0xb510 || // this is float2fix
36             *(uint32_t *)0x2cfc != 0x6487ed51 // pi_q29
37         ) {
38             panic("");
39         }
40 #endif
41 
42         // this is a little tricky.. we only want to pull in a shim if the corresponding function
43         // is called. to that end we include a SVC instruction with the table offset as the call number
44         // followed by the shim function pointer inside the actual wrapper function. that way if the wrapper
45         // function is garbage collected, so is the shim function.
46         //
47         // float_table_shim_on_use_helper expects this SVC instruction in the calling code soon after the address
48         // pointed to by IP and patches the float_table entry with the real shim the first time the function is called.
49 
50         for(uint i=SF_TABLE_V1_SIZE/4; i<SF_TABLE_V2_SIZE/4; i++) {
51             sf_table[i] = (uintptr_t)float_table_shim_on_use_helper;
52         }
53         // we shim these for -0 and -denormal handling
54         sf_table[SF_TABLE_FLOAT2INT/4] = sf_table[SF_TABLE_FLOAT2FIX/4] = (uintptr_t)float_table_shim_on_use_helper;
55     }
56 #else
57     if (rom_version == 1) {
58         memcpy(&sf_table, rom_table, SF_TABLE_V1_SIZE);
59         // opting for soft failure for now - you'll get a panic at runtime if you call any of the missing methods
60         for(uint i=0;i<SF_TABLE_V2_SIZE/4;i++) {
61             if (!sf_table[i]) sf_table[i] = (uintptr_t)missing_float_func_shim;
62         }
63     }
64 #endif
65     if (rom_version >= 2) {
66         assert(*((uint8_t *)rom_table-2) * 4 >= SF_TABLE_V2_SIZE);
67         memcpy(&sf_table, rom_table, SF_TABLE_V2_SIZE);
68     }
69     sf_clz_func = rom_func_lookup(ROM_FUNC_CLZ32);
70 }
71