Move vector table to beginning of flash image (#10)

* Move vector table to beginning of flash image. Modify a boot2 to use the table.

* Move binary info header up between ELF entry and reset handler

* Extract common routines from boot2_w25q080 into helper files

* Non-default boot2s: use common routines, make callable as void(*)(void)

* BSD3 headers on boot2 files (people might want to use them elsewhere)

* Promote binary info header to its own section, + comment/readability changes

* Fix scope of asminclude path (fixes user custom boot2 definitions)

* Rename symbol, clarify comment
This commit is contained in:
Luke Wren 2021-01-28 13:50:45 +00:00 committed by Graham Sanderson
parent 419890cfd8
commit 166cb0fef6
14 changed files with 229 additions and 267 deletions

View File

@ -24,7 +24,10 @@ function(pico_define_boot_stage2 NAME SOURCES)
target_link_options(${NAME} PRIVATE "--specs=nosys.specs")
target_link_options(${NAME} PRIVATE "-nostartfiles")
endif ()
# boot2_helpers include dir
target_include_directories(${NAME} PRIVATE ${PICO_BOOT_STAGE2_DIR}/asminclude)
target_link_libraries(${NAME} hardware_regs)
target_link_options(${NAME} PRIVATE "LINKER:--script=${PICO_BOOT_STAGE2_DIR}/boot_stage2.ld")
set_target_properties(${NAME} PROPERTIES LINK_DEPENDS ${PICO_BOOT_STAGE2_DIR}/boot_stage2.ld)

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT2_HELPER_EXIT_FROM_BOOT2
#define _BOOT2_HELPER_EXIT_FROM_BOOT2
#include "hardware/regs/m0plus.h"
// If entered from the bootrom, lr (which we earlier pushed) will be 0,
// and we vector through the table at the start of the main flash image.
// Any regular function call will have a nonzero value for lr.
check_return:
pop {r0}
cmp r0, #0
beq vector_into_flash
bx r0
vector_into_flash:
ldr r0, =(XIP_BASE + 0x100)
ldr r1, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
str r0, [r1]
ldmia r0, {r0, r1}
msr msp, r0
bx r1
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT2_HELPER_READ_FLASH_SREG
#define _BOOT2_HELPER_READ_FLASH_SREG
#include "boot2_helpers/wait_ssi_ready.S"
// Pass status read cmd into r0.
// Returns status value in r0.
.global read_flash_sreg
.type read_flash_sreg,%function
.thumb_func
read_flash_sreg:
push {r1, lr}
str r0, [r3, #SSI_DR0_OFFSET]
// Dummy byte:
str r0, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
// Discard first byte and combine the next two
ldr r0, [r3, #SSI_DR0_OFFSET]
ldr r0, [r3, #SSI_DR0_OFFSET]
pop {r1, pc}
#endif

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _BOOT2_HELPER_WAIT_SSI_READY
#define _BOOT2_HELPER_WAIT_SSI_READY
wait_ssi_ready:
push {r0, r1, lr}
// Command is complete when there is nothing left to send
// (TX FIFO empty) and SSI is no longer busy (CSn deasserted)
1:
ldr r1, [r3, #SSI_SR_OFFSET]
movs r0, #SSI_SR_TFE_BITS
tst r1, r0
beq 1b
movs r0, #SSI_SR_BUSY_BITS
tst r1, r0
bne 1b
pop {r0, r1, pc}
#endif

View File

@ -1,6 +1,7 @@
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019 Raspberry Pi (Trading) Ltd.
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: Anything which responds to 03h serial read command
//
@ -17,7 +18,7 @@
#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "ssi.h"
#include "hardware/regs/ssi.h"
// ----------------------------------------------------------------------------
// Config section
@ -92,58 +93,8 @@ _stage2_boot:
// translated by the SSI into 03h read commands to the external flash (if cache is missed),
// and the data will be returned to the bus.
soft_reset:
// Jump to exit point provided in lr. Bootrom will pass null, in which
// case we use default exit target at a 256 byte offset into XIP region
// (immediately after this second stage's flash location)
pop {r0}
cmp r0, #0
bne 1f
ldr r0, =(XIP_BASE + 0x101)
1:
bx r0
// Common functions
wait_ssi_ready:
push {r0, r1, lr}
// Command is complete when there is nothing left to send
// (TX FIFO empty) and SSI is no longer busy (CSn deasserted)
1:
ldr r1, [r3, #SSI_SR_OFFSET]
mov r0, #SSI_SR_TFE_BITS
tst r1, r0
beq 1b
mov r0, #SSI_SR_BUSY_BITS
tst r1, r0
bne 1b
pop {r0, r1, pc}
#ifdef PROGRAM_STATUS_REG
// Pass status read cmd into r0.
// Returns status value in r0.
.global read_flash_sreg
.type read_flash_sreg,%function
.thumb_func
read_flash_sreg:
push {r1, lr}
str r0, [r3, #SSI_DR0_OFFSET]
// Dummy byte:
str r0, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
// Discard first byte and combine the next two
ldr r0, [r3, #SSI_DR0_OFFSET]
ldr r0, [r3, #SSI_DR0_OFFSET]
pop {r1, pc}
#endif
// ----------------------------------------------------------------------------
// Literal Table
// ----------------------------------------------------------------------------
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
.global literals
literals:

View File

@ -1,6 +1,6 @@
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019 Raspberry Pi (Trading) Ltd.
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: ISSI IS25LP080D
// Based on W25Q080 code: main difference is the QE bit being in
@ -29,7 +29,7 @@
#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "ssi.h"
#include "hardware/regs/ssi.h"
// ----------------------------------------------------------------------------
// Config section
@ -89,16 +89,17 @@
.type _stage2_boot,%function
.thumb_func
_stage2_boot:
push {lr}
ldr r5, =XIP_SSI_BASE // Use as base address where possible
ldr r3, =XIP_SSI_BASE // Use as base address where possible
// Disable SSI to allow further config
mov r1, #0
str r1, [r5, #SSI_SSIENR_OFFSET]
str r1, [r3, #SSI_SSIENR_OFFSET]
// Set baud rate
mov r1, #PICO_FLASH_SPI_CLKDIV
str r1, [r5, #SSI_BAUDR_OFFSET]
str r1, [r3, #SSI_BAUDR_OFFSET]
// On QSPI parts we usually need a 01h SR-write command to enable QSPI mode
// (i.e. turn WPn and HOLDn into IO2/IO3)
@ -109,11 +110,11 @@ program_sregs:
(SSI_CTRLR0_TMOD_VALUE_TX_AND_RX << SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRL0_SPI_TXRX)
str r1, [r5, #SSI_CTRLR0_OFFSET]
str r1, [r3, #SSI_CTRLR0_OFFSET]
// Enable SSI and select slave 0
mov r1, #1
str r1, [r5, #SSI_SSIENR_OFFSET]
str r1, [r3, #SSI_SSIENR_OFFSET]
// Check whether SR needs updating
ldr r0, =CMD_READ_STATUS
@ -124,21 +125,21 @@ program_sregs:
// Send write enable command
mov r1, #CMD_WRITE_ENABLE
str r1, [r5, #SSI_DR0_OFFSET]
str r1, [r3, #SSI_DR0_OFFSET]
// Poll for completion and discard RX
bl wait_ssi_ready
ldr r1, [r5, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
// Send status write command followed by data bytes
mov r1, #CMD_WRITE_STATUS
str r1, [r5, #SSI_DR0_OFFSET]
str r1, [r3, #SSI_DR0_OFFSET]
mov r0, #0
str r2, [r5, #SSI_DR0_OFFSET]
str r2, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
ldr r1, [r5, #SSI_DR0_OFFSET]
ldr r1, [r5, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r3, #SSI_DR0_OFFSET]
// Poll status register for write completion
1:
@ -152,12 +153,12 @@ skip_sreg_programming:
// Send a 0xA3 high-performance-mode instruction
// ldr r1, =0xa3
// str r1, [r5, #SSI_DR0_OFFSET]
// str r1, [r3, #SSI_DR0_OFFSET]
// bl wait_ssi_ready
// Disable SSI again so that it can be reconfigured
mov r1, #0
str r1, [r5, #SSI_SSIENR_OFFSET]
str r1, [r3, #SSI_SSIENR_OFFSET]
#endif
@ -179,10 +180,10 @@ dummy_read:
<< SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRLR0_ENTER_XIP)
str r1, [r5, #SSI_CTRLR0_OFFSET]
str r1, [r3, #SSI_CTRLR0_OFFSET]
mov r1, #0x0 // NDF=0 (single 32b read)
str r1, [r5, #SSI_CTRLR1_OFFSET]
str r1, [r3, #SSI_CTRLR1_OFFSET]
#define SPI_CTRLR0_ENTER_XIP \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
@ -197,12 +198,12 @@ dummy_read:
str r1, [r0]
mov r1, #1 // Re-enable SSI
str r1, [r5, #SSI_SSIENR_OFFSET]
str r1, [r3, #SSI_SSIENR_OFFSET]
mov r1, #CMD_READ
str r1, [r5, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
mov r1, #MODE_CONTINUOUS_READ // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010
str r1, [r5, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
// Poll for completion
bl wait_ssi_ready
@ -218,7 +219,7 @@ dummy_read:
// to 4'b0000).
mov r1, #0
str r1, [r5, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
// Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO:
@ -240,58 +241,20 @@ configure_ssi:
str r1, [r0]
mov r1, #1
str r1, [r5, #SSI_SSIENR_OFFSET] // Re-enable SSI
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
// We are now in XIP mode, with all transactions using Dual I/O and only
// needing to send 24-bit addresses (plus mode bits) for each read transaction.
soft_reset:
// Just jump to start of image after this 256-byte boot stage2 (with thumb bit set)
ldr r0, =(XIP_BASE + 256 + 1)
bx r0
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
// Common functions
wait_ssi_ready:
push {r0, r1, lr}
// Command is complete when there is nothing left to send
// (TX FIFO empty) and SSI is no longer busy (CSn deasserted)
1:
ldr r1, [r5, #SSI_SR_OFFSET]
mov r0, #SSI_SR_TFE_BITS
tst r1, r0
beq 1b
mov r0, #SSI_SR_BUSY_BITS
tst r1, r0
bne 1b
pop {r0, r1, pc}
#include "boot2_helpers/wait_ssi_ready.S"
#ifdef PROGRAM_STATUS_REG
// Pass status read cmd into r0.
// Returns status value in r0.
.global read_flash_sreg
.type read_flash_sreg,%function
.thumb_func
read_flash_sreg:
push {r1, lr}
str r0, [r5, #SSI_DR0_OFFSET]
// Dummy byte:
str r0, [r5, #SSI_DR0_OFFSET]
bl wait_ssi_ready
// Discard first byte and combine the next two
ldr r0, [r5, #SSI_DR0_OFFSET]
ldr r0, [r5, #SSI_DR0_OFFSET]
pop {r1, pc}
#include "boot2_helpers/read_flash_sreg.S"
#endif
// ----------------------------------------------------------------------------
// Literal Table
// ----------------------------------------------------------------------------
.global literals
literals:
.ltorg

View File

@ -1,3 +1,9 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// Stub second stage which calls into USB bootcode, with parameters.
// USB boot takes two parameters:
// - A GPIO mask for activity LED -- if mask is 0, don't touch GPIOs at all

View File

@ -1,6 +1,7 @@
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019 Raspberry Pi (Trading) Ltd.
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: Winbond W25Q080
// Also supports W25Q16JV (which has some different SR instructions)
@ -270,59 +271,15 @@ configure_ssi:
// Bus accesses to the XIP window will now be transparently serviced by the
// external flash on cache miss. We are ready to run code from flash.
soft_reset:
// Jump to exit point provided in lr. Bootrom will pass null, in which
// case we use default exit target at a 256 byte offset into XIP region
// (immediately after this second stage's flash location)
pop {r0}
cmp r0, #0
bne 1f
ldr r0, =(XIP_BASE + 0x101)
1:
bx r0
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
// Common functions
wait_ssi_ready:
push {r0, r1, lr}
// Command is complete when there is nothing left to send
// (TX FIFO empty) and SSI is no longer busy (CSn deasserted)
1:
ldr r1, [r3, #SSI_SR_OFFSET]
movs r0, #SSI_SR_TFE_BITS
tst r1, r0
beq 1b
movs r0, #SSI_SR_BUSY_BITS
tst r1, r0
bne 1b
pop {r0, r1, pc}
#include "boot2_helpers/wait_ssi_ready.S"
#ifdef PROGRAM_STATUS_REG
// Pass status read cmd into r0.
// Returns status value in r0.
.global read_flash_sreg
.type read_flash_sreg,%function
.thumb_func
read_flash_sreg:
push {r1, lr}
str r0, [r3, #SSI_DR0_OFFSET]
// Dummy byte:
str r0, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready
// Discard first byte and combine the next two
ldr r0, [r3, #SSI_DR0_OFFSET]
ldr r0, [r3, #SSI_DR0_OFFSET]
pop {r1, pc}
#include "boot2_helpers/read_flash_sreg.S"
#endif
// ----------------------------------------------------------------------------
// Literal Table
// ----------------------------------------------------------------------------
.global literals
literals:
.ltorg

View File

@ -1,26 +1,7 @@
// ----------------------------------------------------------------------------
//
// .d8888b. 888 .d8888b. 888
// d88P Y88b 888 d88P Y88b 888
// 888 888 Y88b. 888
// .d88P 88888b. .d88888 "Y888b. 888888 8888b. .d88b. .d88b.
// .od888P" 888 "88b d88" 888 "Y88b. 888 "88b d88P"88b d8P Y8b
// d88P" 888 888 888 888 "888 888 .d888888 888 888 88888888
// 888" 888 888 Y88b 888 Y88b d88P Y88b. 888 888 Y88b 888 Y8b.
// 888888888 888 888 "Y88888 "Y8888P" "Y888 "Y888888 "Y88888 "Y8888
// 888
// Y8b d88P
// "Y88P"
// 888888b. 888 .d8888b. 888
// 888 "88b 888 d88P Y88b 888
// 888 .88P 888 888 888 888
// 8888888K. .d88b. .d88b. 888888 888 .d88b. .d88888 .d88b.
// 888 "Y88b d88""88b d88""88b 888 888 d88""88b d88" 888 d8P Y8b
// 888 888 888 888 888 888 888 888 888 888 888 888 888 88888888
// 888 d88P Y88..88P Y88..88P Y88b. Y88b d88P Y88..88P Y88b 888 Y8b.
// 8888888P" "Y88P" "Y88P" "Y888 "Y8888P" "Y88P" "Y88888 "Y8888
//
// ----------------------------------------------------------------------------
// Second stage boot code
// Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// SPDX-License-Identifier: BSD-3-Clause
//
// Device: Winbond W25X10CL
//
@ -51,7 +32,7 @@
#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "ssi.h"
#include "hardware/regs/ssi.h"
// The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
// This must be an even number.
@ -101,19 +82,19 @@
.type _stage2_boot,%function
.thumb_func
_stage2_boot:
ldr r5, =XIP_SSI_BASE // Use as base address where possible
push {lr}
ldr r3, =XIP_SSI_BASE // Use as base address where possible
// We are primarily interested in setting up Flash for DSPI XIP w/ continuous read
mov r1, #0
str r1, [r5, #SSI_SSIENR_OFFSET] // Disable SSI to allow further config
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI to allow further config
// The Boot ROM sets a very conservative SPI clock frequency to be sure it can
// read the initial 256 bytes from any device. Here we can be more aggressive.
mov r1, #PICO_FLASH_SPI_CLKDIV
str r1, [r5, #SSI_BAUDR_OFFSET] // Set SSI Clock
str r1, [r3, #SSI_BAUDR_OFFSET] // Set SSI Clock
// First we need to send the initial command to get us in to Fast Read Dual I/O
// mode. As this transaction requires a command, we can't send it in XIP mode.
@ -133,10 +114,10 @@ _stage2_boot:
<< SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRLR0_ENTER_XIP)
str r1, [r5, #SSI_CTRLR0_OFFSET]
str r1, [r3, #SSI_CTRLR0_OFFSET]
mov r1, #0x0 // NDF=0 (single 32b read)
str r1, [r5, #SSI_CTRLR1_OFFSET]
str r1, [r3, #SSI_CTRLR1_OFFSET]
#define SPI_CTRLR0_ENTER_XIP \
(7 << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Send 28 bits (24 address + 4 mode) */ \
@ -151,19 +132,19 @@ _stage2_boot:
str r1, [r0]
mov r1, #1 // Re-enable SSI
str r1, [r5, #SSI_SSIENR_OFFSET]
str r1, [r3, #SSI_SSIENR_OFFSET]
mov r1, #W25X10CL_CMD_READ_DATA_FAST_DUAL_IO // 8b command = 0xBB
str r1, [r5, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
mov r1, #0x0000002 // 28-bit Address for dummy read = 0x000000 + 0x2 Mode bits to set M[5:4]=10
str r1, [r5, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
// Now we wait for the read transaction to complete by monitoring the SSI
// status register and checking for the "RX FIFO Not Empty" flag to assert.
mov r1, #SSI_SR_RFNE_BITS
00:
ldr r0, [r5, #SSI_SR_OFFSET] // Read status register
ldr r0, [r3, #SSI_SR_OFFSET] // Read status register
tst r0, r1 // RFNE status flag set?
beq 00b // If not then wait
@ -178,7 +159,7 @@ _stage2_boot:
// to 4'b0000).
mov r1, #0
str r1, [r5, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
// Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO:
@ -200,20 +181,16 @@ _stage2_boot:
str r1, [r0]
mov r1, #1
str r1, [r5, #SSI_SSIENR_OFFSET] // Re-enable SSI
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
// We are now in XIP mode, with all transactions using Dual I/O and only
// needing to send 24-bit addresses (plus mode bits) for each read transaction.
soft_reset:
// Just jump to start of image after this 256-byte boot stage2 (with thumb bit set)
ldr r0, =(XIP_BASE + 256 + 1)
bx r0
// ----------------------------------------------------------------------------
// Literal Table
// ----------------------------------------------------------------------------
// Pull in standard exit routine
#include "boot2_helpers/exit_from_boot2.S"
.global literals
literals:
.ltorg
.end

View File

@ -144,40 +144,61 @@ __unhandled_user_irq:
unhandled_user_irq_num_in_r0:
bkpt #0
.section .reset, "ax"
// ----------------------------------------------------------------------------
// This is the beginning of the image, which is entered from stage2 or bootrom USB MSD watchdog reboot
.section .binary_info_header, "a"
// note if we are NO_FLASH then start: below is currently identical anyway, so save 4 bytes
#if !PICO_NO_FLASH
// We simply install our own vector table and redirect through it
ldr r0, =__vectors
b __vector_entry
// 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
// ELF entry point generally called when we load an ELF via debugger
// ----------------------------------------------------------------------------
.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
// non flash
// Vector through our own table (SP, VTOR will not have been set up at
// this point). Same path for debugger entry and bootloader entry.
ldr r0, =__vectors
#else
// todo clear watchdog?
// When using flash, we install and use the ROM vector table to go thru regular bootrom/stage2 flash sequence
// Debugger tried to run code after loading, so SSI is in 03h-only mode.
// Go back through bootrom + boot2 to properly initialise flash.
movs r0, #0
#endif
__vector_entry:
ldr r1, =(PPB_BASE + M0PLUS_CPUID_OFFSET)
str r0, [r1, #8]
ldr r1, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
str r0, [r1]
ldmia r0!, {r1, r2}
msr msp, r1
bx r2
// ----------------------------------------------------------------------------
// Reset handler:
// - initialises .data
// - clears .bss
@ -188,11 +209,12 @@ __vector_entry:
.type _reset_handler,%function
.thumb_func
_reset_handler:
// Hang all cores except core 0
// 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
ldr r0, =(SIO_BASE + SIO_CPUID_OFFSET)
ldr r0, [r0]
cmp r0, #0
bne wait_for_vector
bne hold_non_core0_in_bootrom
adr r4, data_cpy_table
@ -243,15 +265,6 @@ data_cpy:
blo data_cpy_loop
bx lr
#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
.align 2
data_cpy_table:
#if PICO_COPY_TO_RAM
@ -284,11 +297,12 @@ runtime_init:
bx lr
// ----------------------------------------------------------------------------
// In case core 1's VTOR has already been moved into flash, we need to handle
// core 1 reset. However, we do so by just jumping back into bootrom version of
// wait_for_vector
// If core 1 somehow gets into crt0 due to a spectacular VTOR mishap, we need to
// catch it and send back to the sleep-and-launch code in the bootrom. Shouldn't
// happen (it should sleep in the ROM until given an entry point via the
// cross-core FIFOs) but it's good to be defensive.
wait_for_vector:
hold_non_core0_in_bootrom:
ldr r0, = 'W' | ('V' << 8)
bl rom_func_lookup
bx r0
@ -312,4 +326,4 @@ __get_current_exception:
.section .heap
.align 2
.equ HeapSize, PICO_HEAP_SIZE
.space HeapSize
.space HeapSize

View File

@ -59,12 +59,11 @@ SECTIONS
*/
.text : {
__reset_start = .;
KEEP (*(.reset))
. = ALIGN(256);
__reset_end = .;
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
__logical_binary_start = .;
KEEP (*(.vectors))
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
KEEP (*(.reset))
/* TODO revisit this now memset/memcpy/float in ROM */
/* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
* FLASH ... we will include any thing excluded here in .data below by default */
@ -246,6 +245,8 @@ SECTIONS
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
/* todo assert on extra code */
}

View File

@ -59,12 +59,11 @@ SECTIONS
*/
.flashtext : {
__reset_start = .;
KEEP (*(.reset))
. = ALIGN(256);
__reset_end = .;
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
__logical_binary_start = .;
KEEP (*(.vectors))
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
KEEP (*(.reset))
}
.rodata : {
@ -247,6 +246,8 @@ SECTIONS
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
/* todo assert on extra code */
}

View File

@ -59,12 +59,11 @@ SECTIONS
*/
.text : {
__reset_start = .;
KEEP (*(.reset))
. = ALIGN(256);
__reset_end = .;
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
__logical_binary_start = .;
KEEP (*(.vectors))
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
KEEP (*(.reset))
/* TODO revisit this now memset/memcpy/float in ROM */
/* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
* FLASH ... we will include any thing excluded here in .data below by default */
@ -246,6 +245,8 @@ SECTIONS
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
/* todo assert on extra code */
}

View File

@ -32,19 +32,21 @@ ENTRY(_entry_point)
SECTIONS
{
/* Watchdog reboot into RAM (via USB MSD will enter) image at the start of .text
The debugger will use the ELF entry point, which is the _entry_point
symbol if present, otherwise defaults to start of .text.
/* Note in NO_FLASH builds the entry point for both the bootrom, and debugger
entry (ELF entry point), are *first* in the image, and the vector table
follows immediately afterward. This is because the bootrom enters RAM
binaries directly at their lowest address (preferring main RAM over XIP
cache-as-SRAM if both are used).
*/
.text : {
__reset_start = .;
__logical_binary_start = .;
__reset_start = .;
KEEP (*(.reset))
/* reset should come first */
KEEP (*(.reset))
. = ALIGN(256);
__reset_end = .;
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
. = ALIGN(256);
KEEP (*(.vectors))
*(.time_critical*)
*(.text*)
@ -208,6 +210,8 @@ SECTIONS
/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
/* todo assert on extra code */
}