1 /*
2  *  SPDX-License-Identifier: BSD-3-Clause
3  *  SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
4  *
5  */
6 
7 #include "pico/runtime.h"
8 #include "pico/runtime_init.h"
9 #include "hardware/structs/scb.h"
10 #ifdef PSA_API_TEST_CRYPTO
11 #include "hardware/ticks.h"
12 #include "hardware/clocks.h"
13 #endif
14 
15 #include "stdint.h"
16 
17 /* Do not use __cmsis_start */
18 #define __PROGRAM_START
19 #include "tfm_hal_device_header.h"
20 
copy_zero_tables(void)21 void copy_zero_tables(void) {
22     typedef struct {
23         uint32_t const* src;
24         uint32_t* dest;
25         uint32_t  wlen;
26     } __copy_table_t;
27 
28     typedef struct {
29         uint32_t* dest;
30         uint32_t  wlen;
31     } __zero_table_t;
32 
33     extern const __copy_table_t __copy_table_start__;
34     extern const __copy_table_t __copy_table_end__;
35     extern const __zero_table_t __zero_table_start__;
36     extern const __zero_table_t __zero_table_end__;
37 
38     for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) {
39         for(uint32_t i=0u; i<pTable->wlen; ++i) {
40             pTable->dest[i] = pTable->src[i];
41         }
42     }
43 
44     for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) {
45         for(uint32_t i=0u; i<pTable->wlen; ++i) {
46             pTable->dest[i] = 0u;
47         }
48     }
49 }
50 
hard_assertion_failure(void)51 void hard_assertion_failure(void) {
52     SPM_ASSERT(0);
53 }
54 
runtime_run_initializers_from(uintptr_t * from)55 static void runtime_run_initializers_from(uintptr_t *from) {
56 
57     /* Start and end points of the constructor list, defined by the linker script. */
58     extern uintptr_t __preinit_array_end;
59 
60     /* Call each function in the list, based on the mask
61        We have to take the address of the symbols, as __preinit_array_start *is*
62        the first function value, not the address of it. */
63     for (uintptr_t *p = from; p < &__preinit_array_end; p++) {
64         uintptr_t val = *p;
65         ((void (*)(void))val)();
66     }
67 }
68 
runtime_run_initializers(void)69 void runtime_run_initializers(void) {
70     extern uintptr_t __preinit_array_start;
71     runtime_run_initializers_from(&__preinit_array_start);
72 }
73 
74 /* We keep the per-core initializers in the standard __preinit_array so a standard C library
75    initialization will fo the core 0 initialization, however we also want to be able to find
76    them after the fact so that we can run them on core 1. Per core initializers have sections
77    __preinit_array.ZZZZZ.nnnnn i.e. the ZZZZZ sorts below all the standard __preinit_array.nnnnn
78    values, and then we sort within the ZZZZZ.
79 
80    We create a dummy initializer in __preinit_array.YYYYY (between the standard initializers
81    and the per core initializers), so we find the first per core initializer. Whilst we could
82    have done this via an entry in the linker script, we want to preserve backwards compatibility
83    with RP2040 custom linker scripts. */
first_per_core_initializer(void)84 static void first_per_core_initializer(void) {}
85 PICO_RUNTIME_INIT_FUNC(first_per_core_initializer, "YYYYY");
86 
runtime_run_per_core_initializers(void)87 void runtime_run_per_core_initializers(void) {
88     runtime_run_initializers_from(&__pre_init_first_per_core_initializer);
89 }
90 
91 extern uint32_t __vectors_start__;
92 extern uint32_t __INITIAL_SP;
93 extern uint32_t __STACK_LIMIT;
94 extern uint64_t __STACK_SEAL;
95 
runtime_init(void)96 void runtime_init(void) {
97     scb_hw->vtor = (uintptr_t) &__vectors_start__;
98     copy_zero_tables();
99 
100     __disable_irq();
101     __set_PSP((uint32_t)(&__INITIAL_SP));
102 
103     __set_MSPLIM((uint32_t)(&__STACK_LIMIT));
104     __set_PSPLIM((uint32_t)(&__STACK_LIMIT));
105 
106     __TZ_set_STACKSEAL_S((uint32_t *)(&__STACK_SEAL));
107 
108     runtime_run_initializers();
109 
110 #ifdef PSA_API_TEST_CRYPTO
111     /* RSA Key generation test takes very long. Use 4 times slower WD
112        reference tick when it is enabled. */
113     tick_start(TICK_WATCHDOG, 4 * clock_get_hz(clk_ref) / MHZ);
114 #endif
115 
116     SystemInit();
117 }
118