blob: 9bf12631ac828f63df91fe39deb9a80645231372 [file] [log] [blame]
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico.h"
#include "pico/asm_helper.S"
#include "pico/platform/cpu_regs.h"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/sio.h"
#include "pico/binary_info/defs.h"
#include "boot/picobin.h"
#include "pico/bootrom.h"
#ifdef NDEBUG
#ifndef COLLAPSE_IRQS
#define COLLAPSE_IRQS
#endif
#endif
pico_default_asm_setup
.section .vectors, "ax"
.align 2
.global __vectors, __VECTOR_TABLE
__VECTOR_TABLE:
__vectors:
.word __StackTop
.word _reset_handler
.word isr_nmi
.word isr_hardfault
.word isr_invalid // Reserved, should never fire
.word isr_invalid // Reserved, should never fire
.word isr_invalid // Reserved, should never fire
.word isr_invalid // Reserved, should never fire
.word isr_invalid // Reserved, should never fire
.word isr_invalid // Reserved, should never fire
.word isr_invalid // Reserved, should never fire
.word isr_svcall
.word isr_invalid // Reserved, should never fire
.word isr_invalid // Reserved, should never fire
.word isr_pendsv
.word isr_systick
#if PICO_NO_STORED_VECTOR_TABLE && !PICO_NO_FLASH // note in no flash binary, we only have the single RAM vector table anyway
#if PICO_NO_RAM_VECTOR_TABLE
#error Can't specify PICO_NO_STORED_VECTOR_TABLE and PICO_NO_RAM_VECTOR_TABLE
#endif
// we don't include any IRQ vectors; we will initialize them during runtime_init in the RAM vector table
#else
.altmacro
.macro isr_irqx irq_num
.word isr_irq\irq_num
.endm
.set irq_num, 0
.rept NUM_IRQS
isr_irqx %irq_num
.set irq_num, irq_num + 1
.endr
#endif
// all default exception handlers do nothing, and we can check for them being set to our
// default values by seeing if they point to somewhere between __defaults_isrs_start and __default_isrs_end
.global __default_isrs_start
__default_isrs_start:
// Declare a weak symbol for each ISR.
// By default, they will fall through to the undefined IRQ handler below (breakpoint),
// but can be overridden by C functions with correct name.
.macro decl_isr_bkpt name
.weak \name
.type \name,%function
.thumb_func
\name:
bkpt #0
.endm
// these are separated out for clarity
decl_isr_bkpt isr_invalid
decl_isr_bkpt isr_nmi
decl_isr_bkpt isr_hardfault
decl_isr_bkpt isr_svcall
decl_isr_bkpt isr_pendsv
decl_isr_bkpt isr_systick
.global __default_isrs_end
__default_isrs_end:
.macro decl_isr name
#if !PICO_NO_STORED_VECTOR_TABLE | PICO_NO_FLASH
// We declare a weak label, so user can override
.weak \name
#else
// We declare a strong label, so user can't override (their version would not automatically be used)
#endif
.type \name,%function
.thumb_func
\name:
.endm
.macro decl_isrx irq_num
decl_isr isr_irq\irq_num
.endm
.set irq_num, 0
.rept NUM_IRQS
decl_isrx %irq_num
.set irq_num, irq_num + 1
.endr
// All unhandled USER IRQs fall through to here
.global __unhandled_user_irq
.thumb_func
__unhandled_user_irq:
mrs r0, ipsr
subs r0, #16
.global unhandled_user_irq_num_in_r0
unhandled_user_irq_num_in_r0:
bkpt #0
// ----------------------------------------------------------------------------
.section .binary_info_header, "a"
// Header must be in first 256 bytes of main image (i.e. excluding flash boot2).
// For flash builds we put it immediately after vector table; for NO_FLASH the
// vectors are at a +0x100 offset because the bootrom enters RAM images directly
// at their lowest address, so we put the header in the VTOR alignment hole.
#if !PICO_NO_BINARY_INFO
binary_info_header:
.word BINARY_INFO_MARKER_START
.word __binary_info_start
.word __binary_info_end
.word data_cpy_table // we may need to decode pointers that are in RAM at runtime.
.word BINARY_INFO_MARKER_END
#endif
#include "embedded_start_block.inc.S"
// ----------------------------------------------------------------------------
.section .reset, "ax"
// On flash builds, the vector table comes first in the image (conventional).
// On NO_FLASH builds, the reset handler section comes first, as the entry
// point is at offset 0 (fixed due to bootrom), and VTOR is highly-aligned.
// Image is entered in various ways:
//
// - NO_FLASH builds are entered from beginning by UF2 bootloader
//
// - Flash builds vector through the table into _reset_handler from boot2
//
// - Either type can be entered via _entry_point by the debugger, and flash builds
// must then be sent back round the boot sequence to properly initialise flash
// ELF entry point:
.type _entry_point,%function
.thumb_func
.global _entry_point
_entry_point:
#if PICO_NO_FLASH
// on the NO_FLASH case, we do not do a rest thru bootrom below, so the RCP may or may not have been initialized:
//
// in the normal (e.g. UF2 download etc. case) we will have passed thru bootrom initialization, but if
// a NO_FLASH binary is loaded by the debugger, and run directly after a reset, then we won't have.
//
// we must therefore initialize the RCP if it hasn't already been
#if HAS_REDUNDANCY_COPROCESSOR
// 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)
ldr r0, = PPB_BASE + M33_CPACR_OFFSET
movs r1, #ARM_CPU_PREFIXED(CPACR_CP7_BITS)
str r1, [r0]
// only initialize canary seeds if they haven't been (as to do so twice is a fault)
mrc p7, #1, apsr_nzcv, c0, c0, #0
bmi 1f
// i dont think it much matters what we initialized to, as to have gotten here we must have not
// gone thru the bootrom (which a secure boot would have)
mcrr p7, #8, r0, r0, c0
mcrr p7, #8, r0, r0, c1
sev
1:
#endif
ldr r0, =__vectors
// Vector through our own table (SP, VTOR will not have been set up at
// this point). Same path for debugger entry and bootloader entry.
#else
// Debugger tried to run code after loading, so SSI is in 03h-only mode.
// Go back through bootrom + boot2 to properly initialise flash.
ldr r0, =BOOTROM_VTABLE_OFFSET
#endif
_enter_vtable_in_r0:
ldr r1, =(PPB_BASE + ARM_CPU_PREFIXED(VTOR_OFFSET))
str r0, [r1]
ldmia r0!, {r1, r2}
msr msp, r1
bx r2
// Reset handler:
// - initialises .data
// - clears .bss
// - calls runtime_init
// - calls main
// - calls exit (which should eventually hang the processor via _exit)
.type _reset_handler,%function
.thumb_func
_reset_handler:
// Only core 0 should run the C runtime startup code; core 1 is normally
// sleeping in the bootrom at this point but check to be sure (e.g. if
// debugger put core 1 at the ELF entry point for some reason)
ldr r0, =(SIO_BASE + SIO_CPUID_OFFSET)
ldr r0, [r0]
#if __ARM_ARCH_6M__
cmp r0, #0
beq 1f
#else
cbz r0, 1f
#endif
hold_non_core0_in_bootrom:
// Send back to the ROM to wait for core 0 to launch it.
ldr r0, =BOOTROM_VTABLE_OFFSET
b _enter_vtable_in_r0
1:
#if !PICO_RP2040 && PICO_EMBED_XIP_SETUP && !PICO_NO_FLASH
// Execute boot2 on the core 0 stack (it also gets copied into BOOTRAM due
// to inclusion in the data copy table below). Note the reference
// to __boot2_entry_point here is what prevents the .boot2 section from
// being garbage-collected.
_copy_xip_setup:
ldr r1, =__boot2_entry_point
mov r3, sp
add sp, #-256
mov r2, sp
bl data_cpy
_call_xip_setup:
mov r0, sp
adds r0, #1
blx r0
add sp, #256
#endif
// In a NO_FLASH binary, don't perform .data etc copy, since it's loaded
// in-place by the SRAM load. Still need to clear .bss
#if !PICO_NO_FLASH
adr r4, data_cpy_table
// assume there is at least one entry
1:
ldmia r4!, {r1-r3}
cmp r1, #0
beq 2f
bl data_cpy
b 1b
2:
#endif
// Zero out the BSS
ldr r1, =__bss_start__
ldr r2, =__bss_end__
movs r0, #0
b bss_fill_test
bss_fill_loop:
stm r1!, {r0}
bss_fill_test:
cmp r1, r2
bne bss_fill_loop
platform_entry: // symbol for stack traces
// Use 32-bit jumps, in case these symbols are moved out of branch range
// (e.g. if main is in SRAM and crt0 in flash)
#if !__ARM_ARCH_6M__
// Make sure stack limit is 0 - the user can set it themselves
// todo probably worth adding to the EXE_DEF in the future
movs r0, #0
msr msplim, r0
#endif
ldr r1, =runtime_init
blx r1
ldr r1, =main
blx r1
ldr r1, =exit
blx r1
// exit should not return. If it does, hang the core.
1: // separate label because _exit can be moved out of branch range
bkpt #0
b 1b
#if !PICO_NO_FLASH
data_cpy_loop:
ldm r1!, {r0}
stm r2!, {r0}
data_cpy:
cmp r2, r3
blo data_cpy_loop
bx lr
#endif
// Note the data copy table is still included for NO_FLASH builds, even though
// we skip the copy, because it is listed in binary info
.align 2
data_cpy_table:
#if PICO_RP2350 && PICO_EMBED_XIP_SETUP && !PICO_NO_FLASH
.word __boot2_start__
.word BOOTRAM_BASE
.word BOOTRAM_BASE + 256
#endif
#if PICO_COPY_TO_RAM
.word __ram_text_source__
.word __ram_text_start__
.word __ram_text_end__
#endif
.word __etext
.word __data_start__
.word __data_end__
.word __scratch_x_source__
.word __scratch_x_start__
.word __scratch_x_end__
.word __scratch_y_source__
.word __scratch_y_start__
.word __scratch_y_end__
.word 0 // null terminator
// ----------------------------------------------------------------------------
// Provide safe defaults for _exit and runtime_init
// Full implementations usually provided by platform.c
.weak runtime_init
.type runtime_init,%function
.thumb_func
runtime_init:
bx lr
// ----------------------------------------------------------------------------
// Stack/heap dummies to set size
// Prior to SDK 1.5.1 these were `.section .stack` without the `, "a"`... Clang linker gives a warning about this,
// however setting it explicitly to `, "a"` makes GCC *now* discard the section unless it is also KEEP. This
// seems like very surprising behavior!
//
// Strictly the most correct thing to do (as .stack and .heap are unreferenced) is to mark them as "a", and also KEEP, which
// works correctly for both GCC and Clang, however doing so may break anyone who already has custom linker scripts without
// the KEEP. Therefore we will only add the "a" on Clang, but will also use KEEP to our own linker scripts.
.macro spacer_section name
#if PICO_ASSEMBLER_IS_CLANG
.section \name, "a"
#else
.section \name
#endif
.endm
spacer_section .stack
// align to allow for memory protection (although this alignment is pretty much ignored by linker script)
.p2align 5
.equ StackSize, PICO_STACK_SIZE
.space StackSize
spacer_section .heap
.p2align 2
.equ HeapSize, PICO_HEAP_SIZE
.space HeapSize
#include "embedded_end_block.inc.S"