1/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "pico.h"
8#include "pico/asm_helper.S"
9
10#include "pico/platform/cpu_regs.h"
11
12#include "hardware/regs/addressmap.h"
13#include "hardware/regs/sio.h"
14#include "pico/binary_info/defs.h"
15#include "boot/picobin.h"
16#include "pico/bootrom.h"
17
18#ifdef NDEBUG
19#ifndef COLLAPSE_IRQS
20#define COLLAPSE_IRQS
21#endif
22#endif
23
24pico_default_asm_setup
25
26.section .vectors, "ax"
27.align 2
28
29.global __vectors, __VECTOR_TABLE
30__VECTOR_TABLE:
31__vectors:
32.word __StackTop
33.word _reset_handler
34.word isr_nmi
35.word isr_hardfault
36.word isr_invalid // Reserved, should never fire
37.word isr_invalid // Reserved, should never fire
38.word isr_invalid // Reserved, should never fire
39.word isr_invalid // Reserved, should never fire
40.word isr_invalid // Reserved, should never fire
41.word isr_invalid // Reserved, should never fire
42.word isr_invalid // Reserved, should never fire
43.word isr_svcall
44.word isr_invalid // Reserved, should never fire
45.word isr_invalid // Reserved, should never fire
46.word isr_pendsv
47.word isr_systick
48#if PICO_NO_STORED_VECTOR_TABLE && !PICO_NO_FLASH // note in no flash binary, we only have the single RAM vector table anyway
49#if PICO_NO_RAM_VECTOR_TABLE
50#error Can't specify PICO_NO_STORED_VECTOR_TABLE and PICO_NO_RAM_VECTOR_TABLE
51#endif
52// we don't include any IRQ vectors; we will initialize them during runtime_init in the RAM vector table
53#else
54
55.macro if_irq_word num func
56.if \num < NUM_IRQS
57.word \func
58.endif
59.endm
60
61// we include a lot of these to allow for different number of IRQs.
62// if_irq_word will only include IRQs that are valid, but we can't
63// use a macro loop because isr_irqx MUST appear in the source
64// as CMSIS rename exceptions #defines it to another value
65if_irq_word 0 isr_irq0
66if_irq_word 1 isr_irq1
67if_irq_word 2 isr_irq2
68if_irq_word 3 isr_irq3
69if_irq_word 4 isr_irq4
70if_irq_word 5 isr_irq5
71if_irq_word 6 isr_irq6
72if_irq_word 7 isr_irq7
73if_irq_word 8 isr_irq8
74if_irq_word 9 isr_irq9
75if_irq_word 10 isr_irq10
76if_irq_word 11 isr_irq11
77if_irq_word 12 isr_irq12
78if_irq_word 13 isr_irq13
79if_irq_word 14 isr_irq14
80if_irq_word 15 isr_irq15
81if_irq_word 16 isr_irq16
82if_irq_word 17 isr_irq17
83if_irq_word 18 isr_irq18
84if_irq_word 19 isr_irq19
85if_irq_word 20 isr_irq20
86if_irq_word 21 isr_irq21
87if_irq_word 22 isr_irq22
88if_irq_word 23 isr_irq23
89if_irq_word 24 isr_irq24
90if_irq_word 25 isr_irq25
91if_irq_word 26 isr_irq26
92if_irq_word 27 isr_irq27
93if_irq_word 28 isr_irq28
94if_irq_word 29 isr_irq29
95if_irq_word 30 isr_irq30
96if_irq_word 31 isr_irq31
97if_irq_word 32 isr_irq32
98if_irq_word 33 isr_irq33
99if_irq_word 34 isr_irq34
100if_irq_word 35 isr_irq35
101if_irq_word 36 isr_irq36
102if_irq_word 37 isr_irq37
103if_irq_word 38 isr_irq38
104if_irq_word 39 isr_irq39
105if_irq_word 40 isr_irq40
106if_irq_word 41 isr_irq41
107if_irq_word 42 isr_irq42
108if_irq_word 43 isr_irq43
109if_irq_word 44 isr_irq44
110if_irq_word 45 isr_irq45
111if_irq_word 46 isr_irq46
112if_irq_word 47 isr_irq47
113if_irq_word 48 isr_irq48
114if_irq_word 49 isr_irq49
115if_irq_word 50 isr_irq50
116if_irq_word 51 isr_irq51
117if_irq_word 52 isr_irq52
118if_irq_word 53 isr_irq53
119if_irq_word 54 isr_irq54
120if_irq_word 55 isr_irq55
121if_irq_word 56 isr_irq56
122if_irq_word 57 isr_irq57
123if_irq_word 58 isr_irq58
124if_irq_word 59 isr_irq59
125if_irq_word 60 isr_irq60
126if_irq_word 61 isr_irq61
127if_irq_word 62 isr_irq62
128if_irq_word 63 isr_irq63
129if_irq_word 64 isr_irq64
130if_irq_word 65 isr_irq65
131if_irq_word 66 isr_irq66
132if_irq_word 67 isr_irq67
133if_irq_word 68 isr_irq68
134if_irq_word 69 isr_irq69
135if_irq_word 70 isr_irq70
136if_irq_word 71 isr_irq71
137if_irq_word 72 isr_irq72
138if_irq_word 73 isr_irq73
139if_irq_word 74 isr_irq74
140if_irq_word 75 isr_irq75
141if_irq_word 76 isr_irq76
142if_irq_word 77 isr_irq77
143if_irq_word 78 isr_irq78
144if_irq_word 79 isr_irq79
145#if NUM_IRQS > 80
146#error more IRQ entries required
147#endif
148#endif
149
150// all default exception handlers do nothing, and we can check for them being set to our
151// default values by seeing if they point to somewhere between __defaults_isrs_start and __default_isrs_end
152.global __default_isrs_start
153__default_isrs_start:
154
155// Declare a weak symbol for each ISR.
156// By default, they will fall through to the undefined IRQ handler below (breakpoint),
157// but can be overridden by C functions with correct name.
158
159.macro decl_isr_bkpt name
160.weak \name
161.type \name,%function
162.thumb_func
163\name:
164    bkpt #0
165.endm
166
167// these are separated out for clarity
168decl_isr_bkpt isr_invalid
169decl_isr_bkpt isr_nmi
170decl_isr_bkpt isr_hardfault
171decl_isr_bkpt isr_svcall
172decl_isr_bkpt isr_pendsv
173decl_isr_bkpt isr_systick
174
175.global __default_isrs_end
176__default_isrs_end:
177
178.altmacro
179.macro decl_isr name
180#if !PICO_NO_STORED_VECTOR_TABLE | PICO_NO_FLASH
181// We declare a weak label, so user can override
182.weak \name
183#else
184// We declare a strong label, so user can't override (their version would not automatically be used)
185#endif
186.type \name,%function
187.thumb_func
188\name:
189.endm
190
191.macro if_irq_decl num func
192.if \num < NUM_IRQS
193decl_isr \func
194.endif
195.endm
196
197if_irq_decl 0 isr_irq0
198if_irq_decl 1 isr_irq1
199if_irq_decl 2 isr_irq2
200if_irq_decl 3 isr_irq3
201if_irq_decl 4 isr_irq4
202if_irq_decl 5 isr_irq5
203if_irq_decl 6 isr_irq6
204if_irq_decl 7 isr_irq7
205if_irq_decl 8 isr_irq8
206if_irq_decl 9 isr_irq9
207if_irq_decl 10 isr_irq10
208if_irq_decl 11 isr_irq11
209if_irq_decl 12 isr_irq12
210if_irq_decl 13 isr_irq13
211if_irq_decl 14 isr_irq14
212if_irq_decl 15 isr_irq15
213if_irq_decl 16 isr_irq16
214if_irq_decl 17 isr_irq17
215if_irq_decl 18 isr_irq18
216if_irq_decl 19 isr_irq19
217if_irq_decl 20 isr_irq20
218if_irq_decl 21 isr_irq21
219if_irq_decl 22 isr_irq22
220if_irq_decl 23 isr_irq23
221if_irq_decl 24 isr_irq24
222if_irq_decl 25 isr_irq25
223if_irq_decl 26 isr_irq26
224if_irq_decl 27 isr_irq27
225if_irq_decl 28 isr_irq28
226if_irq_decl 29 isr_irq29
227if_irq_decl 30 isr_irq30
228if_irq_decl 31 isr_irq31
229if_irq_decl 32 isr_irq32
230if_irq_decl 33 isr_irq33
231if_irq_decl 34 isr_irq34
232if_irq_decl 35 isr_irq35
233if_irq_decl 36 isr_irq36
234if_irq_decl 37 isr_irq37
235if_irq_decl 38 isr_irq38
236if_irq_decl 39 isr_irq39
237if_irq_decl 40 isr_irq40
238if_irq_decl 41 isr_irq41
239if_irq_decl 42 isr_irq42
240if_irq_decl 43 isr_irq43
241if_irq_decl 44 isr_irq44
242if_irq_decl 45 isr_irq45
243if_irq_decl 46 isr_irq46
244if_irq_decl 47 isr_irq47
245if_irq_decl 48 isr_irq48
246if_irq_decl 49 isr_irq49
247if_irq_decl 50 isr_irq50
248if_irq_decl 51 isr_irq51
249if_irq_decl 52 isr_irq52
250if_irq_decl 53 isr_irq53
251if_irq_decl 54 isr_irq54
252if_irq_decl 55 isr_irq55
253if_irq_decl 56 isr_irq56
254if_irq_decl 57 isr_irq57
255if_irq_decl 58 isr_irq58
256if_irq_decl 59 isr_irq59
257if_irq_decl 60 isr_irq60
258if_irq_decl 61 isr_irq61
259if_irq_decl 62 isr_irq62
260if_irq_decl 63 isr_irq63
261if_irq_decl 64 isr_irq64
262if_irq_decl 65 isr_irq65
263if_irq_decl 66 isr_irq66
264if_irq_decl 67 isr_irq67
265if_irq_decl 68 isr_irq68
266if_irq_decl 69 isr_irq69
267if_irq_decl 70 isr_irq70
268if_irq_decl 71 isr_irq71
269if_irq_decl 72 isr_irq72
270if_irq_decl 73 isr_irq73
271if_irq_decl 74 isr_irq74
272if_irq_decl 75 isr_irq75
273if_irq_decl 76 isr_irq76
274if_irq_decl 77 isr_irq77
275if_irq_decl 78 isr_irq78
276if_irq_decl 79 isr_irq79
277#if NUM_IRQS > 80
278#error more IRQ entries required
279#endif
280
281// All unhandled USER IRQs fall through to here
282.global __unhandled_user_irq
283.thumb_func
284__unhandled_user_irq:
285    mrs  r0, ipsr
286    subs r0, #16
287.global unhandled_user_irq_num_in_r0
288unhandled_user_irq_num_in_r0:
289    bkpt #0
290
291// ----------------------------------------------------------------------------
292
293.section .binary_info_header, "a"
294
295// Header must be in first 256 bytes of main image (i.e. excluding flash boot2).
296// For flash builds we put it immediately after vector table; for NO_FLASH the
297// vectors are at a +0x100 offset because the bootrom enters RAM images directly
298// at their lowest address, so we put the header in the VTOR alignment hole.
299
300#if !PICO_NO_BINARY_INFO
301binary_info_header:
302.word BINARY_INFO_MARKER_START
303.word __binary_info_start
304.word __binary_info_end
305.word data_cpy_table // we may need to decode pointers that are in RAM at runtime.
306.word BINARY_INFO_MARKER_END
307#endif
308
309#include "embedded_start_block.inc.S"
310
311// ----------------------------------------------------------------------------
312
313.section .reset, "ax"
314
315// On flash builds, the vector table comes first in the image (conventional).
316// On NO_FLASH builds, the reset handler section comes first, as the entry
317// point is at offset 0 (fixed due to bootrom), and VTOR is highly-aligned.
318// Image is entered in various ways:
319//
320// - NO_FLASH builds are entered from beginning by UF2 bootloader
321//
322// - Flash builds vector through the table into _reset_handler from boot2
323//
324// - Either type can be entered via _entry_point by the debugger, and flash builds
325//   must then be sent back round the boot sequence to properly initialise flash
326
327// ELF entry point:
328.type _entry_point,%function
329.thumb_func
330.global _entry_point
331_entry_point:
332
333#if PICO_NO_FLASH
334    // on the NO_FLASH case, we do not do a rest thru bootrom below, so the RCP may or may not have been initialized:
335    //
336    // in the normal (e.g. UF2 download etc. case) we will have passed thru bootrom initialization, but if
337    // a NO_FLASH binary is loaded by the debugger, and run directly after a reset, then we won't have.
338    //
339    // we must therefore initialize the RCP if it hasn't already been
340
341#if HAS_REDUNDANCY_COPROCESSOR
342    // just enable the RCP which is fine if it already was (we assume no other co-processors are enabled at this point to save space)
343    ldr r0, = PPB_BASE + M33_CPACR_OFFSET
344    movs r1, #ARM_CPU_PREFIXED(CPACR_CP7_BITS)
345    str r1, [r0]
346    // only initialize canary seeds if they haven't been (as to do so twice is a fault)
347    mrc p7, #1, apsr_nzcv, c0, c0, #0
348    bmi 1f
349    // i dont think it much matters what we initialized to, as to have gotten here we must have not
350    // gone thru the bootrom (which a secure boot would have)
351    mcrr p7, #8, r0, r0, c0
352    mcrr p7, #8, r0, r0, c1
353    sev
3541:
355#endif
356    ldr r0, =__vectors
357    // Vector through our own table (SP, VTOR will not have been set up at
358    // this point). Same path for debugger entry and bootloader entry.
359#else
360    // Debugger tried to run code after loading, so SSI is in 03h-only mode.
361    // Go back through bootrom + boot2 to properly initialise flash.
362    ldr r0, =BOOTROM_VTABLE_OFFSET
363#endif
364
365_enter_vtable_in_r0:
366    ldr r1, =(PPB_BASE + ARM_CPU_PREFIXED(VTOR_OFFSET))
367    str r0, [r1]
368    ldmia r0!, {r1, r2}
369    msr msp, r1
370    bx r2
371
372// Reset handler:
373// - initialises .data
374// - clears .bss
375// - calls runtime_init
376// - calls main
377// - calls exit (which should eventually hang the processor via _exit)
378
379.type _reset_handler,%function
380.thumb_func
381_reset_handler:
382    // Only core 0 should run the C runtime startup code; core 1 is normally
383    // sleeping in the bootrom at this point but check to be sure (e.g. if
384    // debugger put core 1 at the ELF entry point for some reason)
385    ldr r0, =(SIO_BASE + SIO_CPUID_OFFSET)
386    ldr r0, [r0]
387#if __ARM_ARCH_6M__
388    cmp r0, #0
389    beq 1f
390#else
391    cbz r0, 1f
392#endif
393hold_non_core0_in_bootrom:
394    // Send back to the ROM to wait for core 0 to launch it.
395    ldr r0, =BOOTROM_VTABLE_OFFSET
396    b _enter_vtable_in_r0
3971:
398
399#if !PICO_RP2040 && PICO_EMBED_XIP_SETUP && !PICO_NO_FLASH
400    // Execute boot2 on the core 0 stack (it also gets copied into BOOTRAM due
401    // to inclusion in the data copy table below). Note the reference
402    // to __boot2_entry_point here is what prevents the .boot2 section from
403    // being garbage-collected.
404_copy_xip_setup:
405    ldr r1, =__boot2_entry_point
406    mov r3, sp
407    add sp, #-256
408    mov r2, sp
409    bl data_cpy
410_call_xip_setup:
411    mov r0, sp
412    adds r0, #1
413    blx r0
414    add sp, #256
415#endif
416
417    // In a NO_FLASH binary, don't perform .data etc copy, since it's loaded
418    // in-place by the SRAM load. Still need to clear .bss
419#if !PICO_NO_FLASH
420    adr r4, data_cpy_table
421
422    // assume there is at least one entry
4231:
424    ldmia r4!, {r1-r3}
425    cmp r1, #0
426    beq 2f
427    bl data_cpy
428    b 1b
4292:
430#endif
431
432    // Zero out the BSS
433    ldr r1, =__bss_start__
434    ldr r2, =__bss_end__
435    movs r0, #0
436    b bss_fill_test
437bss_fill_loop:
438    stm r1!, {r0}
439bss_fill_test:
440    cmp r1, r2
441    bne bss_fill_loop
442
443platform_entry: // symbol for stack traces
444    // Use 32-bit jumps, in case these symbols are moved out of branch range
445    // (e.g. if main is in SRAM and crt0 in flash)
446#if !__ARM_ARCH_6M__
447    // Make sure stack limit is 0 - the user can set it themselves
448    //  todo probably worth adding to the EXE_DEF in the future
449    movs r0, #0
450    msr msplim, r0
451#endif
452    ldr r1, =runtime_init
453    blx r1
454    ldr r1, =main
455    blx r1
456    ldr r1, =exit
457    blx r1
458    // exit should not return.  If it does, hang the core.
4591: // separate label because _exit can be moved out of branch range
460    bkpt #0
461    b 1b
462
463
464#if !PICO_NO_FLASH
465data_cpy_loop:
466    ldm r1!, {r0}
467    stm r2!, {r0}
468data_cpy:
469    cmp r2, r3
470    blo data_cpy_loop
471    bx lr
472#endif
473
474// Note the data copy table is still included for NO_FLASH builds, even though
475// we skip the copy, because it is listed in binary info
476
477.align 2
478data_cpy_table:
479#if PICO_RP2350 && PICO_EMBED_XIP_SETUP && !PICO_NO_FLASH
480.word __boot2_start__
481.word BOOTRAM_BASE
482.word BOOTRAM_BASE + 256
483#endif
484
485#if PICO_COPY_TO_RAM
486.word __ram_text_source__
487.word __ram_text_start__
488.word __ram_text_end__
489#endif
490.word __etext
491.word __data_start__
492.word __data_end__
493
494.word __scratch_x_source__
495.word __scratch_x_start__
496.word __scratch_x_end__
497
498.word __scratch_y_source__
499.word __scratch_y_start__
500.word __scratch_y_end__
501
502.word 0 // null terminator
503
504// ----------------------------------------------------------------------------
505// Provide safe defaults for _exit and runtime_init
506// Full implementations usually provided by platform.c
507
508.weak runtime_init
509.type runtime_init,%function
510.thumb_func
511runtime_init:
512    bx lr
513
514// ----------------------------------------------------------------------------
515// Stack/heap dummies to set size
516
517// Prior to SDK 1.5.1 these were `.section .stack` without the `, "a"`... Clang linker gives a warning about this,
518// however setting it explicitly to `, "a"` makes GCC *now* discard the section unless it is also KEEP. This
519// seems like very surprising behavior!
520//
521// Strictly the most correct thing to do (as .stack and .heap are unreferenced) is to mark them as "a", and also KEEP, which
522// works correctly for both GCC and Clang, however doing so may break anyone who already has custom linker scripts without
523// the KEEP. Therefore we will only add the "a" on Clang, but will also use KEEP to our own linker scripts.
524
525.macro spacer_section name
526#if PICO_ASSEMBLER_IS_CLANG
527.section \name, "a"
528#else
529.section \name
530#endif
531.endm
532
533spacer_section .stack
534// align to allow for memory protection (although this alignment is pretty much ignored by linker script)
535.p2align 5
536    .equ StackSize, PICO_STACK_SIZE
537.space StackSize
538
539spacer_section .heap
540.p2align 2
541    .equ HeapSize, PICO_HEAP_SIZE
542.space HeapSize
543
544#include "embedded_end_block.inc.S"
545