Newsletter
Sed ut perspiciatis unde.
Subscribe
|
/** |
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd. |
|
* |
|
* SPDX-License-Identifier: BSD-3-Clause |
|
*/ |
|
|
|
|
|
// —————————————————————————- |
|
// Bootrom Runtime 0 |
|
// —————————————————————————- |
|
// This is not a full crt0 — in particular, no .bss or .data initialisation |
|
// (use of .data/.bss is disallowed via linker script assertions). |
|
// The bootrom is not permitted to use statically-allocated memory, as parts of |
|
// it are called into by user code. |
|
// The purpose of this file is: |
|
// – Provide initial entry point for both cores |
|
// – Provide holding pen and launch code for core 1 |
|
// – Provide direct-boot entry for core 0, mainly intended for running |
|
// ARM code during ATE |
|
// – Pass core 0 control over to the main flash boot sequence |
|
|
|
#include “hardware/regs/addressmap.h” |
|
#include “hardware/regs/pads_bank0.h” |
|
#include “hardware/regs/resets.h” |
|
#include “hardware/regs/sio.h” |
|
#include “hardware/regs/watchdog.h” |
|
#include “hardware/regs/syscfg.h” |
|
#include “hardware/regs/clocks.h” |
|
#include “hardware/regs/vreg_and_chip_reset.h” |
|
#include “hardware/regs/m0plus.h” |
|
#include “git_info.h” |
|
|
|
.cpu cortex-m0 |
|
.thumb |
|
.section .vectors |
|
.balign 2 |
|
|
|
.global __vectors |
|
__vectors: |
|
.word _stacktop // MSP |
|
.word _start // Reset |
|
.word _nmi // NMI |
|
.word _dead // HardFault |
|
|
|
.global _magic |
|
_magic: |
|
# magic |
|
.byte ‘M’, ‘u’ |
|
# compatibility version (change if function table is incompatible, or functions are backwards incompatible) |
|
.byte 1 |
|
# ROM version |
|
.byte 3 |
|
|
|
.global _well_known |
|
_well_known: |
|
.hword function_table |
|
.hword data_table |
|
.hword table_lookup + 1 |
|
.hword 0 // pad |
|
|
|
.global table_lookup |
|
.type table_lookup,%function |
|
.thumb_func |
|
table_lookup: |
|
mov r3, #0 |
|
ldrh r2, [r0] |
|
cmp r2, r3 |
|
beq 1f |
|
ldrh r3, [r0, #2] |
|
add r0, #4 |
|
cmp r1, r2 |
|
bne table_lookup |
|
1: |
|
mov r0, r3 |
|
bx lr |
|
|
|
.global _dead |
|
.type _dead,%function |
|
.thumb_func |
|
_dead: // in place of irq4 vector |
|
wfi |
|
b _dead |
|
|
|
// this is all a bit cheeky, but the existing code assumed that the table above could go there because nothing ever called |
|
// some code in irq0 -4 slots |
|
|
|
// If you reach this, something has gone wrong. Most likely, the debugger |
|
// has done a core-only reset while the NMI mask was set, and a relevant |
|
// IRQ was asserted. This is probably not intentional, and is confusing |
|
// to debug, so we should just clear the NMI masks. |
|
.align 2 |
|
.global _nmi |
|
.type _nmi,%function |
|
.thumb_func |
|
_nmi: |
|
// we do not want to use any stack as we’re called from the core 0 boot path. |
|
// we use r12 as this is saved/restored by the processor in an actual NMI |
|
mov r12, lr |
|
// We can take an NMI straight out of reset, so we should first ensure |
|
// that SYSCFG is being clocked, else we end up straight back in NMI |
|
bl enable_clocks |
|
// Then just clear the NMI mask (for both cores) |
|
ldr r0, =(SYSCFG_BASE + SYSCFG_PROC0_NMI_MASK_OFFSET) |
|
mov r1, #0 |
|
str r1, [r0] |
|
str r1, [r0, #4] |
|
mov pc, r12 |
|
|
|
// On a cold boot, the clocks will already be enabled, because the power-on state |
|
// machine will have reset the clock controls. However we can have trouble on a warm |
|
// boot, that is to say: |
|
// – The debugger has just reset the processors and started them running |
|
// – The watchdog has fired, with WDSEL selecting a restart point after |
|
// clocks_bank_default. |
|
// Assume that enough clocks are already enabled to run this code! |
|
// Note it is NOT recommended to disable things like ROM clock if WDSEL is |
|
// later than CLOCKS_BANK_DEFAULT. |
|
.global enable_clocks |
|
.type enable_clocks,%function |
|
.thumb_func |
|
enable_clocks: |
|
ldr r0, =(CLOCKS_BASE + CLOCKS_WAKE_EN0_OFFSET) |
|
// Set entire clock enable mask. Relying on HCGs to avoid huge current transient |
|
mov r1, #0 |
|
mvn r1, r1 |
|
str r1, [r0] |
|
str r1, [r0, #4] |
|
// we steal the return for its own function |
|
.global _noop |
|
.type _noop,%function |
|
.thumb_func |
|
_noop: |
|
bx lr |
|
|
|
.align 2 |
|
.global software_git_revision |
|
software_git_revision: |
|
.word GIT_REV |
|
|
|
.global __irq5_vector |
|
__irq5_vector: |
|
.word isr_irq5 |
|
|
|
copyright: |
|
.string “(C) 2020 Raspberry Pi Trading Ltd” |
|
|
|
|
|
function_table: |
|
# function table |
|
#ifdef USE_POPCOUNT32 |
|
.byte ‘P, ‘3’ |
|
.hword popcount32 + 1 |
|
#endif |
|
#ifdef USE_REVERSE32 |
|
.byte ‘R’, ‘3’ |
|
.hword reverse32 + 1 |
|
#endif |
|
#ifdef USE_CLZ32 |
|
.byte ‘L’, ‘3’ |
|
.hword clz32 + 1 |
|
#endif |
|
#ifdef USE_CTZ32 |
|
.byte ‘T’, ‘3’ |
|
.hword ctz32 + 1 |
|
#endif |
|
.byte ‘M’, ‘S’ |
|
.hword __memset + 1 |
|
.byte ‘S’, ‘4’ |
|
.hword __memset_4 + 1 |
|
.byte ‘M’, ‘C’ |
|
.hword __memcpy + 1 |
|
.byte ‘C’, ‘4’ |
|
.hword __memcpy_44 + 1 |
|
.byte ‘U’, ‘B’ |
|
.hword reset_usb_boot + 1 |
|
.byte ‘D’, ‘T’ |
|
.hword debug_trampoline + 1 |
|
.byte ‘D’, ‘E’ |
|
.hword debug_trampoline_end + 1 |
|
.byte ‘W’, ‘V’ |
|
.hword wait_for_vector + 1 |
|
.byte ‘I’, ‘F’ |
|
.hword connect_internal_flash + 1 |
|
.byte ‘E’, ‘X’ |
|
.hword flash_exit_xip + 1 |
|
.byte ‘R’, ‘E’ |
|
.hword flash_range_erase + 1 |
|
.byte ‘R’, ‘P’ |
|
.hword flash_range_program + 1 |
|
.byte ‘F’, ‘C’ |
|
.hword flash_flush_cache + 1 |
|
.byte ‘C’, ‘X’ |
|
.hword flash_enter_cmd_xip + 1 |
|
# end of function table marker |
|
.hword 0 |
|
|
|
.global data_table |
|
data_table: |
|
.byte ‘G’, ‘R’ |
|
.hword software_git_revision |
|
.byte ‘C’, ‘R’ |
|
.hword copyright |
|
.byte ‘S’, ‘F’ |
|
.hword soft_float_table |
|
.byte ‘S’, ‘D’ |
|
.hword soft_double_table |
|
.byte ‘F’, ‘Z’ |
|
.hword soft_float_table_size |
|
// expose library start and end to facilitate users copying into RAM |
|
.byte ‘F, ‘S’ |
|
.hword mufp_lib_start |
|
.byte ‘F, ‘E’ |
|
.hword mufp_lib_end |
|
// expose library start and end to facilitate users copying into RAM |
|
.byte ‘D, ‘S’ |
|
.hword mufp_lib_double_start |
|
.byte ‘D, ‘E’ |
|
.hword mufp_lib_double_end |
|
.hword 0 |
|
|
|
// —————————————————————————- |
|
// Entry point for both cores |
|
// —————————————————————————- |
|
|
|
.global _start |
|
.type _start,%function |
|
.thumb_func |
|
_start: |
|
|
|
// Check if this is core 0, and go to holding pen if not |
|
check_core: |
|
// NOTE: We DO NOT use any stack prior to possible watchdog entry (this includes NMI vector handler) |
|
ldr r0, =SIO_BASE |
|
ldr r1, [r0, #SIO_CPUID_OFFSET] |
|
cmp r1, #0 |
|
bne wait_for_vector |
|
|
|
// Make sure all the control registers we are about to access are being clocked. |
|
// On a cold boot everything will be set up by the power-on state machine, |
|
// but the clock setup may be dirty on a warm boot. |
|
|
|
// note that the NMI handler does exactly what we want (enable_clocks) and also disables NMI |
|
bl _nmi |
|
|
|
// If the rescue flag is set in PoR block, we should halt immediately. |
|
// (presumably some lethal code is in flash which would stop the debugger from |
|
// communicating with the processors). |
|
check_rescue: |
|
ldr r1, =(VREG_AND_CHIP_RESET_BASE + VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET) |
|
ldr r2, [r1] |
|
#if VREG_AND_CHIP_RESET_CHIP_RESET_PSM_RESTART_FLAG_BITS != 0x01000000 |
|
#error |
|
#endif |
|
lsr r3, r2, #25 |
|
bcc 1f |
|
// Acknowledge and halt (note we write all bits, but VREG_AND_CHIP_RESET_CHIP_RESET_PSM_RESTART_FLAG_BITS |
|
// is the only WC bit |
|
str r2, [r1] |
|
b _dead |
|
1: |
|
|
|
disable_adc_ie: |
|
#if RESETS_RESET_PADS_BANK0_BITS != (0x80 << 1) |
|
#error |
|
#endif |
|
mov r0, #0x80 |
|
lsl r0, #1 |
|
bl unreset_block_ |
Read More