1/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "pico.h"
8
9#include "hardware/regs/addressmap.h"
10#include "hardware/regs/rvcsr.h"
11#include "pico/binary_info/defs.h"
12#include "boot/picobin.h"
13#include "pico/bootrom_constants.h"
14
15#ifdef NDEBUG
16#ifndef COLLAPSE_IRQS
17#define COLLAPSE_IRQS
18#endif
19#endif
20
21#if !defined(PICO_CRT0_INCLUDE_PICOBIN_IMAGE_TYPE_ITEM)
22#define PICO_CRT0_INCLUDE_PICOBIN_IMAGE_TYPE_ITEM 1
23#endif
24
25#ifndef PICO_CRT0_INCLUDE_PICOBIN_BLOCK
26#define PICO_CRT0_INCLUDE_PICOBIN_BLOCK PICO_CRT0_INCLUDE_PICOBIN_IMAGE_TYPE_ITEM
27#endif
28
29#ifndef PICO_CRT0_INCLUDE_PICOBIN_END_BLOCK
30#define PICO_CRT0_INCLUDE_PICOBIN_END_BLOCK (PICO_CRT0_INCLUDE_PICOBIN_BLOCK && !PICO_NO_FLASH)
31#endif
32
33// If vectors are in RAM, we put them in the .data section, so that they are
34// preloaded by _reset_handler (assuming this is not a loaded-in-place
35// binary).
36#if PICO_NO_RAM_VECTOR_TABLE || PICO_NO_FLASH
37.section .vectors, "ax"
38#else
39.section .data
40#endif
41
42.p2align 6
43.global __vectors, __VECTOR_TABLE
44__VECTOR_TABLE:
45__vectors:
46
47// Hardware vector table for standard RISC-V interrupts, indicated by `mtvec`.
48
49.option push
50.option norvc
51.option norelax
52j isr_riscv_machine_exception
53.word 0
54.word 0
55j isr_riscv_machine_soft_irq
56.word 0
57.word 0
58.word 0
59j isr_riscv_machine_timer
60.word 0
61.word 0
62.word 0
63// j isr_riscv_machine_external_irq -> inlined below
64.option pop
65
66// External IRQ dispatch, inlined into the last vector table slot. Note if
67// this code is modified, the VTABLE_FIRST_IRQ define in platform_defs.h also
68// needs to be modified (it identifies the beginning of the soft vector table)
69.global isr_riscv_machine_external_irq
70.weak isr_riscv_machine_external_irq
71isr_riscv_machine_external_irq:
72    // Save caller saves and exception return state whilst IRQs are disabled.
73    // We can't be preempted during this time, but if a higher-priority IRQ
74    // arrives before we read meinext, that will be the one we enter.
75    addi sp, sp, -80
76    sw ra,  0(sp)
77    sw t0,  4(sp)
78    sw t1,  8(sp)
79    sw t2, 12(sp)
80    sw a0, 16(sp)
81    sw a1, 20(sp)
82    sw a2, 24(sp)
83    sw a3, 28(sp)
84    sw a4, 32(sp)
85    sw a5, 36(sp)
86    sw a6, 40(sp)
87    sw a7, 44(sp)
88    sw t3, 48(sp)
89    sw t4, 52(sp)
90    sw t5, 56(sp)
91    sw t6, 60(sp)
92    csrr a0, mepc
93    csrr a1, mstatus
94    sw a0, 64(sp)
95    sw a1, 68(sp)
96save_meicontext:
97    // Make sure to set meicontext.clearts to clear+save mie.msie/mtie along
98    // with ext IRQ context. We don't let these preempt ext IRQs because they
99    // clear meicontext.mreteirq, which breaks __get_current_exception().
100    csrrsi a2, RVCSR_MEICONTEXT_OFFSET, RVCSR_MEICONTEXT_CLEARTS_BITS
101    sw a2, 72(sp)
102
103get_first_irq:
104    // Sample the current highest-priority active IRQ (left-shifted by 2) from
105    // meinext, and write 1 to meinext.update to update meicontext with the
106    // preemption priority and IRQ number of this IRQ
107    csrrsi a0, RVCSR_MEINEXT_OFFSET, RVCSR_MEINEXT_UPDATE_BITS
108    // MSB will be set if there is no active IRQ at the current priority level
109    bltz a0, no_more_irqs
110dispatch_irq:
111    // Preemption priority was configured by meinext update, so enable preemption:
112    csrsi mstatus, 0x8
113    // <- from this point we can be preempted by a higher-priority interrupt.
114    // meinext is pre-shifted by 2, so only an add is required to index table
115    lui a1, %hi(__soft_vector_table)
116    add a1, a1, a0
117    lw a1, %lo(__soft_vector_table)(a1)
118    jalr ra, a1
119    // Disable IRQs on returning so we can sample the next IRQ
120    csrci mstatus, 0x8
121get_next_irq:
122    // Get the next-highest-priority IRQ that is active at this level. If
123    // there is such an IRQ, update meicontext with new preemption priority.
124    csrrsi a0, RVCSR_MEINEXT_OFFSET, RVCSR_MEINEXT_UPDATE_BITS
125    // MSB will be set if there is no active IRQ at the current priority level
126    bgez a0, dispatch_irq
127
128no_more_irqs:
129    // Restore saved context and return from IRQ
130    lw a0, 64(sp)
131    lw a1, 68(sp)
132    lw a2, 72(sp)
133    csrw mepc, a0
134    csrw mstatus, a1
135    csrw RVCSR_MEICONTEXT_OFFSET, a2
136    lw ra,  0(sp)
137    lw t0,  4(sp)
138    lw t1,  8(sp)
139    lw t2, 12(sp)
140    // skip a0 for now
141    lw a1, 20(sp)
142    lw a2, 24(sp)
143    lw a3, 28(sp)
144    lw a4, 32(sp)
145    lw a5, 36(sp)
146    lw a6, 40(sp)
147    lw a7, 44(sp)
148    lw t3, 48(sp)
149    lw t4, 52(sp)
150    lw t5, 56(sp)
151    lw t6, 60(sp)
152    // Before popping the stack frame, check if there is a new IRQ, and if so,
153    // abandon the mret and take the IRQ. This avoids a worst-case (restore ->
154    // mret -> enter -> save) latency. Note since we have already restored
155    // meicontext, we will have to re-save it, to re-clear mtie/msie.
156check_irq_before_exit:
157    csrr a0, RVCSR_MEINEXT_OFFSET
158    bgez a0, save_meicontext
159    lw a0, 16(sp)
160    addi sp, sp, 80
161    mret
162
163// Default software vector table for system interrupts, routed through
164// mip.meip. Note this is assumed in e.g. hardware_irq to begin exactly 0x34
165// words after the hardware vector table indicated by mtvec (defined above).
166.p2align 4
167.global __soft_vector_table
168__soft_vector_table:
169.word isr_irq0
170.word isr_irq1
171.word isr_irq2
172.word isr_irq3
173.word isr_irq4
174.word isr_irq5
175.word isr_irq6
176.word isr_irq7
177.word isr_irq8
178.word isr_irq9
179.word isr_irq10
180.word isr_irq11
181.word isr_irq12
182.word isr_irq13
183.word isr_irq14
184.word isr_irq15
185.word isr_irq16
186.word isr_irq17
187.word isr_irq18
188.word isr_irq19
189.word isr_irq20
190.word isr_irq21
191.word isr_irq22
192.word isr_irq23
193.word isr_irq24
194.word isr_irq25
195.word isr_irq26
196.word isr_irq27
197.word isr_irq28
198.word isr_irq29
199.word isr_irq30
200.word isr_irq31
201.word isr_irq32
202.word isr_irq33
203.word isr_irq34
204.word isr_irq35
205.word isr_irq36
206.word isr_irq37
207.word isr_irq38
208.word isr_irq39
209.word isr_irq40
210.word isr_irq41
211.word isr_irq42
212.word isr_irq43
213.word isr_irq44
214.word isr_irq45
215.word isr_irq46
216.word isr_irq47
217.word isr_irq48
218.word isr_irq49
219.word isr_irq50
220.word isr_irq51
221
222// all default trap handlers do nothing, and we can check for them being set to our
223// default values by seeing if they point to somewhere between __defaults_isrs_start and __default_isrs_end
224.global __default_isrs_start
225__default_isrs_start:
226
227// Declare a weak symbol for each ISR.
228// By default, they will fall through to the undefined IRQ handler below (breakpoint),
229// but can be overridden by C functions with correct name.
230
231.macro decl_isr name
232.weak \name
233\name:
234.endm
235
236.macro decl_isr_bkpt name
237.weak \name
238\name:
239    ebreak
240.endm
241
242// hardware_exception on RISC-V defines its own weak handler
243#if !PICO_CRT0_NO_ISR_RISCV_MACHINE_EXCEPTION
244// Breakpoint will just cause another exception and trash the exception
245// state, since there is no double fault lockup on RISC-V. Instead, just
246// sleep the core indefinitely, or until debugger connects.
247decl_isr isr_riscv_machine_exception
248#endif
249
250// Note the mip.mtip is also available as SIO_IRQ_MTIMECMP, and this may be a
251// better option, because it plays nicely with interrupt preemption.
252decl_isr_bkpt isr_riscv_machine_timer
253decl_isr_bkpt isr_riscv_machine_soft_irq
254
255decl_isr isr_irq0
256decl_isr isr_irq1
257decl_isr isr_irq2
258decl_isr isr_irq3
259decl_isr isr_irq4
260decl_isr isr_irq5
261decl_isr isr_irq6
262decl_isr isr_irq7
263decl_isr isr_irq8
264decl_isr isr_irq9
265decl_isr isr_irq10
266decl_isr isr_irq11
267decl_isr isr_irq12
268decl_isr isr_irq13
269decl_isr isr_irq14
270decl_isr isr_irq15
271decl_isr isr_irq16
272decl_isr isr_irq17
273decl_isr isr_irq18
274decl_isr isr_irq19
275decl_isr isr_irq20
276decl_isr isr_irq21
277decl_isr isr_irq22
278decl_isr isr_irq23
279decl_isr isr_irq24
280decl_isr isr_irq25
281decl_isr isr_irq26
282decl_isr isr_irq27
283decl_isr isr_irq28
284decl_isr isr_irq29
285decl_isr isr_irq30
286decl_isr isr_irq31
287decl_isr isr_irq32
288decl_isr isr_irq33
289decl_isr isr_irq34
290decl_isr isr_irq35
291decl_isr isr_irq36
292decl_isr isr_irq37
293decl_isr isr_irq38
294decl_isr isr_irq39
295decl_isr isr_irq40
296decl_isr isr_irq41
297decl_isr isr_irq42
298decl_isr isr_irq43
299decl_isr isr_irq44
300decl_isr isr_irq45
301decl_isr isr_irq46
302decl_isr isr_irq47
303decl_isr isr_irq48
304decl_isr isr_irq49
305decl_isr isr_irq50
306decl_isr isr_irq51
307    // fall through
308
309// All unhandled USER IRQs fall through to here. Note there is no way to get
310// the "current exception" on RISC-V (as there is no such thing -- the
311// hardware does not model the exception lifecycle like on Arm) so instead we
312// just pass the IRQ number into the IRQ handler in a0.
313.global __unhandled_user_irq
314__unhandled_user_irq:
315.global unhandled_user_irq_num_in_a0
316unhandled_user_irq_num_in_a0:
317    // The dispatch code will have left IRQ << 2 in a0 from its meinext read,
318    // so just need to shift it back down
319    srli a0, a0, 2
320    ebreak
321
322.global __default_isrs_end
323__default_isrs_end:
324
325// ----------------------------------------------------------------------------
326
327.section .binary_info_header, "a"
328
329// Header must be in first 256 bytes of main image (i.e. excluding flash boot2).
330// For flash builds we put it immediately after vector table; for NO_FLASH the
331// vectors are at a +0x100 offset because the bootrom enters RAM images directly
332// at their lowest address, so we put the header in the VTOR alignment hole.
333
334#if !PICO_NO_BINARY_INFO
335binary_info_header:
336.word BINARY_INFO_MARKER_START
337.word __binary_info_start
338.word __binary_info_end
339.word data_cpy_table // we may need to decode pointers that are in RAM at runtime.
340.word BINARY_INFO_MARKER_END
341#endif
342
343#include "embedded_start_block.inc.S"
344
345// ----------------------------------------------------------------------------
346
347.section .reset, "ax"
348
349// On flash builds, the vector table comes first in the image (conventional).
350// On NO_FLASH builds, the reset handler section comes first, as the entry
351// point is at offset 0 (fixed due to bootrom), and VTOR is highly-aligned.
352// Image is entered in various ways:
353//
354// - NO_FLASH builds are entered from beginning by UF2 bootloader
355//
356// - Flash builds vector through the table into _reset_handler from boot2
357//
358// - Either type can be entered via _entry_point by the debugger, and flash builds
359//   must then be sent back round the boot sequence to properly initialise flash
360
361// ELF entry point:
362.global _entry_point
363_entry_point:
364
365#if PICO_NO_FLASH
366    // Go through our own reset handler. Same path for debugger entry and
367    // bootloader entry.
368    j _reset_handler
369#else
370    // Debugger tried to run code after loading, so SSI is in 03h-only mode.
371    // Go back through bootrom + boot2 to properly initialise flash.
372    j reenter_bootrom
373#endif
374
375// Reset handler:
376// - initialises .data
377// - clears .bss
378// - calls runtime_init
379// - calls main
380// - calls exit (which should eventually hang the processor via _exit)
381
382_reset_handler:
383.option push
384.option norelax
385    la gp, __global_pointer$
386.option pop
387    la sp, __StackTop
388    // Leave interrupts globally disabled for now, we will set that up later
389    // in runtime_init_per_core_h3_irq_registers. Still worth installing the vector table:
390    la a0, __vectors + 1
391    csrw mtvec, a0
392
393    // Only core 0 should run the C runtime startup code; core 1 is normally
394    // sleeping in the bootrom at this point but check to be sure
395    csrr a0, mhartid
396    bnez a0, reenter_bootrom
397
398#if PICO_RP2350 && PICO_EMBED_XIP_SETUP && !PICO_NO_FLASH
399    // Execute boot2 on the core 0 stack (it also gets copied into BOOTRAM due
400    // to inclusion in the data copy table below)
401_copy_xip_setup:
402    mv a2, sp
403    addi sp, sp, -256
404    mv a0, sp
405    la a1, __boot2_entry_point
4061:
407    // Iterate forward, as sequential flash access is faster
408    lw a3, (a1)
409    sw a3, (a0)
410    addi a0, a0, 4
411    addi a1, a1, 4
412    bltu a0, a2, 1b
413_call_xip_setup:
414    jalr sp
415    addi sp, sp, 256
416#endif
417
418    // In a NO_FLASH binary, don't perform .data etc copy, since it's loaded
419    // in-place by the SRAM load. Still need to clear .bss
420#if !PICO_NO_FLASH
421    la a4, data_cpy_table
422
423    // assume there is at least one entry
4241:
425    lw a1, 0(a4)
426    beqz a1, 2f
427    lw a2, 4(a4)
428    lw a3, 8(a4)
429    addi a4, a4, 12
430    jal data_cpy
431    j 1b
4322:
433#endif
434
435    // Zero out the BSS
436    la a1, __bss_start__
437    la a2, __bss_end__
438    j bss_fill_test
439bss_fill_loop:
440    sw zero, (a1)
441    addi a1, a1, 4
442bss_fill_test:
443    bne a1, a2, bss_fill_loop
444
445platform_entry: // symbol for stack traces
446    // Use `call` pseudo-instruction instead of a bare `jal` so that the
447    // linker can use longer sequences if these are out of `jal` range. Will
448    // still get relaxed to a `jal` if possible.
449    // call runtime_init_per_core_h3_irq_registers (now called in runtime_init)
450    call runtime_init
451    call main
452    call exit
453    // exit should not return.  If it does, hang the core.
454    // (fall thru into our hang _exit impl
4551: // separate label because _exit can be moved out of branch range
456    ebreak
457    j 1b
458
459data_cpy_loop:
460    lw a0, (a1)
461    sw a0, (a2)
462    addi a1, a1, 4
463    addi a2, a2, 4
464data_cpy:
465    bltu a2, a3, data_cpy_loop
466    ret
467
468.align 2
469data_cpy_table:
470#if PICO_RP2350 && PICO_EMBED_XIP_SETUP && !PICO_NO_FLASH
471.word __boot2_start__
472.word BOOTRAM_BASE
473.word BOOTRAM_BASE + 256
474#endif
475#if PICO_COPY_TO_RAM
476.word __ram_text_source__
477.word __ram_text_start__
478.word __ram_text_end__
479#endif
480.word __etext
481.word __data_start__
482.word __data_end__
483
484.word __scratch_x_source__
485.word __scratch_x_start__
486.word __scratch_x_end__
487
488.word __scratch_y_source__
489.word __scratch_y_start__
490.word __scratch_y_end__
491
492.word 0 // null terminator
493
494// ----------------------------------------------------------------------------
495// Provide safe defaults for _exit and runtime_init
496// Full implementations usually provided by platform.c
497
498.weak runtime_init
499runtime_init:
500    ret
501
502// ----------------------------------------------------------------------------
503// If core 1 somehow gets into crt0, we need to catch it and send back to the
504// sleep-and-launch code in the bootrom. Shouldn't happen (it should sleep in
505// the ROM until given an entry point via the cross-core FIFOs) but it's good
506// to be defensive.
507
508// Enter through the shared reset handler: on core 1 this should quickly reach
509// the wait-for-vector code.
510reenter_bootrom:
511
512#ifdef RASPBERRYPI_AMETHYST_FPGA
513    // todo remove once 64k bootrom support is not required: vvvvvvvvvvvvvvvvvvvvv
514    // Try jumping 32k higher and see if we get a fault :)
515    li a0, BOOTROM_ENTRY_OFFSET + 32 * 1024
516    la a1, 1f
517    csrw mtvec, a1
518    jr a0
519    // Go here if we trapped:
520.p2align 2
5211:
522#endif
523
524    li a0, BOOTROM_ENTRY_OFFSET
525    jr a0
526
527// ----------------------------------------------------------------------------
528// IRQ register clearing
529
530// Enable interrupts globally, but disable all interrupt sources.
531//
532// This is put in the .text section as it is called again on core 1 launch. In
533// COPY_TO_RAM binaries, the .reset section is always in flash, whereas .text
534// is in SRAM, and we try to avoid running any code from flash after entering
535// user code in a COPY_TO_RAM binary. Note because of this we don't call this
536// function here in crt0 until after the flash-to-RAM copying is finished.
537
538.section .text
539.global runtime_init_per_core_h3_irq_registers
540runtime_init_per_core_h3_irq_registers:
541    // First clear all IRQ force array bits. Iterate over array registers 0
542    // through 3 inclusive, allowing for up to 64 IRQs. Don't clear the
543    // enable array as earlier (non-per-core) init stages may have already
544    // set up IRQs.
545    li a0, 3
5461:
547    csrw RVCSR_MEIFA_OFFSET, a0
548    addi a0, a0, -1
549    bgez a0, 1b
550    // Setting the global external IRQ enable in mie prepares us to enable
551    // IRQs one-by-one later. Also clear the soft IRQ and timer IRQ enables:
552    li a0, RVCSR_MIE_MEIE_BITS
553    csrw mie, a0
554    // Set the global IRQ: we will now take any individual interrupt that is
555    // pending && enabled
556    csrsi mstatus, RVCSR_MSTATUS_MIE_BITS
557    // Take this chance to clear mscratch, which is used to detect nested
558    // exceptions in isr_riscv_machine_exception:
559    csrw mscratch, zero
560    ret
561
562// ----------------------------------------------------------------------------
563// Stack/heap dummies to set size
564
565// Prior to SDK 1.5.1 these were `.section .stack` without the `, "a"`... Clang linker gives a warning about this,
566// however setting it explicitly to `, "a"` makes GCC *now* discard the section unless it is also KEEP. This
567// seems like very surprising behavior!
568//
569// Strictly the most correct thing to do (as .stack and .heap are unreferenced) is to mark them as "a", and also KEEP, which
570// works correctly for both GCC and Clang, however doing so may break anyone who already has custom linker scripts without
571// the KEEP. Therefore we will only add the "a" on Clang, but will also use KEEP to our own linker scripts.
572
573.macro spacer_section name
574#if PICO_ASSEMBLER_IS_CLANG
575.section \name, "a"
576#else
577.section \name
578#endif
579.endm
580
581spacer_section .stack
582// align to allow for memory protection (although this alignment is pretty much ignored by linker script)
583.p2align 5
584    .equ StackSize, PICO_STACK_SIZE
585.space StackSize
586
587spacer_section .heap
588.p2align 2
589    .equ HeapSize, PICO_HEAP_SIZE
590.space HeapSize
591
592#include "embedded_end_block.inc.S"
593
594