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 GitHub
parent 5e5776b9c0
commit 732b53271f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 "--specs=nosys.specs")
target_link_options(${NAME} PRIVATE "-nostartfiles") target_link_options(${NAME} PRIVATE "-nostartfiles")
endif () endif ()
# boot2_helpers include dir
target_include_directories(${NAME} PRIVATE ${PICO_BOOT_STAGE2_DIR}/asminclude)
target_link_libraries(${NAME} hardware_regs) target_link_libraries(${NAME} hardware_regs)
target_link_options(${NAME} PRIVATE "LINKER:--script=${PICO_BOOT_STAGE2_DIR}/boot_stage2.ld") 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) 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 // 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 // Device: Anything which responds to 03h serial read command
// //
@ -17,7 +18,7 @@
#include "pico/asm_helper.S" #include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h" #include "hardware/regs/addressmap.h"
#include "ssi.h" #include "hardware/regs/ssi.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Config section // Config section
@ -92,58 +93,8 @@ _stage2_boot:
// translated by the SSI into 03h read commands to the external flash (if cache is missed), // 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. // and the data will be returned to the bus.
soft_reset: // Pull in standard exit routine
// Jump to exit point provided in lr. Bootrom will pass null, in which #include "boot2_helpers/exit_from_boot2.S"
// 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
// ----------------------------------------------------------------------------
.global literals .global literals
literals: literals:

View File

@ -1,6 +1,6 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Second stage boot code // Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// Copyright (c) 2019 Raspberry Pi (Trading) Ltd. // SPDX-License-Identifier: BSD-3-Clause
// //
// Device: ISSI IS25LP080D // Device: ISSI IS25LP080D
// Based on W25Q080 code: main difference is the QE bit being in // Based on W25Q080 code: main difference is the QE bit being in
@ -29,7 +29,7 @@
#include "pico/asm_helper.S" #include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h" #include "hardware/regs/addressmap.h"
#include "ssi.h" #include "hardware/regs/ssi.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Config section // Config section
@ -89,16 +89,17 @@
.type _stage2_boot,%function .type _stage2_boot,%function
.thumb_func .thumb_func
_stage2_boot: _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 // Disable SSI to allow further config
mov r1, #0 mov r1, #0
str r1, [r5, #SSI_SSIENR_OFFSET] str r1, [r3, #SSI_SSIENR_OFFSET]
// Set baud rate // Set baud rate
mov r1, #PICO_FLASH_SPI_CLKDIV 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 // On QSPI parts we usually need a 01h SR-write command to enable QSPI mode
// (i.e. turn WPn and HOLDn into IO2/IO3) // (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) (SSI_CTRLR0_TMOD_VALUE_TX_AND_RX << SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRL0_SPI_TXRX) ldr r1, =(CTRL0_SPI_TXRX)
str r1, [r5, #SSI_CTRLR0_OFFSET] str r1, [r3, #SSI_CTRLR0_OFFSET]
// Enable SSI and select slave 0 // Enable SSI and select slave 0
mov r1, #1 mov r1, #1
str r1, [r5, #SSI_SSIENR_OFFSET] str r1, [r3, #SSI_SSIENR_OFFSET]
// Check whether SR needs updating // Check whether SR needs updating
ldr r0, =CMD_READ_STATUS ldr r0, =CMD_READ_STATUS
@ -124,21 +125,21 @@ program_sregs:
// Send write enable command // Send write enable command
mov r1, #CMD_WRITE_ENABLE mov r1, #CMD_WRITE_ENABLE
str r1, [r5, #SSI_DR0_OFFSET] str r1, [r3, #SSI_DR0_OFFSET]
// Poll for completion and discard RX // Poll for completion and discard RX
bl wait_ssi_ready bl wait_ssi_ready
ldr r1, [r5, #SSI_DR0_OFFSET] ldr r1, [r3, #SSI_DR0_OFFSET]
// Send status write command followed by data bytes // Send status write command followed by data bytes
mov r1, #CMD_WRITE_STATUS mov r1, #CMD_WRITE_STATUS
str r1, [r5, #SSI_DR0_OFFSET] str r1, [r3, #SSI_DR0_OFFSET]
mov r0, #0 mov r0, #0
str r2, [r5, #SSI_DR0_OFFSET] str r2, [r3, #SSI_DR0_OFFSET]
bl wait_ssi_ready bl wait_ssi_ready
ldr r1, [r5, #SSI_DR0_OFFSET] ldr r1, [r3, #SSI_DR0_OFFSET]
ldr r1, [r5, #SSI_DR0_OFFSET] ldr r1, [r3, #SSI_DR0_OFFSET]
// Poll status register for write completion // Poll status register for write completion
1: 1:
@ -152,12 +153,12 @@ skip_sreg_programming:
// Send a 0xA3 high-performance-mode instruction // Send a 0xA3 high-performance-mode instruction
// ldr r1, =0xa3 // ldr r1, =0xa3
// str r1, [r5, #SSI_DR0_OFFSET] // str r1, [r3, #SSI_DR0_OFFSET]
// bl wait_ssi_ready // bl wait_ssi_ready
// Disable SSI again so that it can be reconfigured // Disable SSI again so that it can be reconfigured
mov r1, #0 mov r1, #0
str r1, [r5, #SSI_SSIENR_OFFSET] str r1, [r3, #SSI_SSIENR_OFFSET]
#endif #endif
@ -179,10 +180,10 @@ dummy_read:
<< SSI_CTRLR0_TMOD_LSB) << SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRLR0_ENTER_XIP) 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) 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 \ #define SPI_CTRLR0_ENTER_XIP \
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \ (ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
@ -197,12 +198,12 @@ dummy_read:
str r1, [r0] str r1, [r0]
mov r1, #1 // Re-enable SSI mov r1, #1 // Re-enable SSI
str r1, [r5, #SSI_SSIENR_OFFSET] str r1, [r3, #SSI_SSIENR_OFFSET]
mov r1, #CMD_READ 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 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 // Poll for completion
bl wait_ssi_ready bl wait_ssi_ready
@ -218,7 +219,7 @@ dummy_read:
// to 4'b0000). // to 4'b0000).
mov r1, #0 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 // Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO: // the TX FIFO:
@ -240,58 +241,20 @@ configure_ssi:
str r1, [r0] str r1, [r0]
mov r1, #1 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 // 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. // needing to send 24-bit addresses (plus mode bits) for each read transaction.
soft_reset: // Pull in standard exit routine
// Just jump to start of image after this 256-byte boot stage2 (with thumb bit set) #include "boot2_helpers/exit_from_boot2.S"
ldr r0, =(XIP_BASE + 256 + 1)
bx r0
// Common functions // Common functions
#include "boot2_helpers/wait_ssi_ready.S"
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}
#ifdef PROGRAM_STATUS_REG #ifdef PROGRAM_STATUS_REG
// Pass status read cmd into r0. #include "boot2_helpers/read_flash_sreg.S"
// 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}
#endif #endif
// ----------------------------------------------------------------------------
// Literal Table
// ----------------------------------------------------------------------------
.global literals .global literals
literals: literals:
.ltorg .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. // Stub second stage which calls into USB bootcode, with parameters.
// USB boot takes two parameters: // USB boot takes two parameters:
// - A GPIO mask for activity LED -- if mask is 0, don't touch GPIOs at all // - 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 // 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 // Device: Winbond W25Q080
// Also supports W25Q16JV (which has some different SR instructions) // 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 // 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. // external flash on cache miss. We are ready to run code from flash.
soft_reset: // Pull in standard exit routine
// Jump to exit point provided in lr. Bootrom will pass null, in which #include "boot2_helpers/exit_from_boot2.S"
// 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 // Common functions
#include "boot2_helpers/wait_ssi_ready.S"
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}
#ifdef PROGRAM_STATUS_REG #ifdef PROGRAM_STATUS_REG
// Pass status read cmd into r0. #include "boot2_helpers/read_flash_sreg.S"
// 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 #endif
// ----------------------------------------------------------------------------
// Literal Table
// ----------------------------------------------------------------------------
.global literals .global literals
literals: literals:
.ltorg .ltorg

View File

@ -1,26 +1,7 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// // Second stage boot code
// .d8888b. 888 .d8888b. 888 // Copyright (c) 2019-2021 Raspberry Pi (Trading) Ltd.
// d88P Y88b 888 d88P Y88b 888 // SPDX-License-Identifier: BSD-3-Clause
// 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
//
// ----------------------------------------------------------------------------
// //
// Device: Winbond W25X10CL // Device: Winbond W25X10CL
// //
@ -51,7 +32,7 @@
#include "pico/asm_helper.S" #include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h" #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. // The serial flash interface will run at clk_sys/PICO_FLASH_SPI_CLKDIV.
// This must be an even number. // This must be an even number.
@ -101,19 +82,19 @@
.type _stage2_boot,%function .type _stage2_boot,%function
.thumb_func .thumb_func
_stage2_boot: _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
// We are primarily interested in setting up Flash for DSPI XIP w/ continuous read // We are primarily interested in setting up Flash for DSPI XIP w/ continuous read
mov r1, #0 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 // 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. // read the initial 256 bytes from any device. Here we can be more aggressive.
mov r1, #PICO_FLASH_SPI_CLKDIV 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 // 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. // 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) << SSI_CTRLR0_TMOD_LSB)
ldr r1, =(CTRLR0_ENTER_XIP) 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) 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 \ #define SPI_CTRLR0_ENTER_XIP \
(7 << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Send 28 bits (24 address + 4 mode) */ \ (7 << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Send 28 bits (24 address + 4 mode) */ \
@ -151,19 +132,19 @@ _stage2_boot:
str r1, [r0] str r1, [r0]
mov r1, #1 // Re-enable SSI 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 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 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 // 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. // status register and checking for the "RX FIFO Not Empty" flag to assert.
mov r1, #SSI_SR_RFNE_BITS mov r1, #SSI_SR_RFNE_BITS
00: 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? tst r0, r1 // RFNE status flag set?
beq 00b // If not then wait beq 00b // If not then wait
@ -178,7 +159,7 @@ _stage2_boot:
// to 4'b0000). // to 4'b0000).
mov r1, #0 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 // Note that the INST_L field is used to select what XIP data gets pushed into
// the TX FIFO: // the TX FIFO:
@ -200,20 +181,16 @@ _stage2_boot:
str r1, [r0] str r1, [r0]
mov r1, #1 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 // 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. // needing to send 24-bit addresses (plus mode bits) for each read transaction.
soft_reset: // Pull in standard exit routine
// Just jump to start of image after this 256-byte boot stage2 (with thumb bit set) #include "boot2_helpers/exit_from_boot2.S"
ldr r0, =(XIP_BASE + 256 + 1)
bx r0
// ----------------------------------------------------------------------------
// Literal Table
// ----------------------------------------------------------------------------
.global literals
literals:
.ltorg .ltorg
.end .end

View File

@ -144,40 +144,61 @@ __unhandled_user_irq:
unhandled_user_irq_num_in_r0: unhandled_user_irq_num_in_r0:
bkpt #0 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 // Header must be in first 256 bytes of main image (i.e. excluding flash boot2).
#if !PICO_NO_FLASH // For flash builds we put it immediately after vector table; for NO_FLASH the
// We simply install our own vector table and redirect through it // vectors are at a +0x100 offset because the bootrom enters RAM images directly
ldr r0, =__vectors // at their lowest address, so we put the header in the VTOR alignment hole.
b __vector_entry
#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 #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 .type _entry_point,%function
.thumb_func .thumb_func
.global _entry_point .global _entry_point
_entry_point: _entry_point:
#if PICO_NO_FLASH #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 ldr r0, =__vectors
#else #else
// todo clear watchdog? // Debugger tried to run code after loading, so SSI is in 03h-only mode.
// When using flash, we install and use the ROM vector table to go thru regular bootrom/stage2 flash sequence // Go back through bootrom + boot2 to properly initialise flash.
movs r0, #0 movs r0, #0
#endif #endif
ldr r1, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
__vector_entry: str r0, [r1]
ldr r1, =(PPB_BASE + M0PLUS_CPUID_OFFSET)
str r0, [r1, #8]
ldmia r0!, {r1, r2} ldmia r0!, {r1, r2}
msr msp, r1 msr msp, r1
bx r2 bx r2
// ----------------------------------------------------------------------------
// Reset handler: // Reset handler:
// - initialises .data // - initialises .data
// - clears .bss // - clears .bss
@ -188,11 +209,12 @@ __vector_entry:
.type _reset_handler,%function .type _reset_handler,%function
.thumb_func .thumb_func
_reset_handler: _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, =(SIO_BASE + SIO_CPUID_OFFSET)
ldr r0, [r0] ldr r0, [r0]
cmp r0, #0 cmp r0, #0
bne wait_for_vector bne hold_non_core0_in_bootrom
adr r4, data_cpy_table adr r4, data_cpy_table
@ -243,15 +265,6 @@ data_cpy:
blo data_cpy_loop blo data_cpy_loop
bx lr 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 .align 2
data_cpy_table: data_cpy_table:
#if PICO_COPY_TO_RAM #if PICO_COPY_TO_RAM
@ -284,11 +297,12 @@ runtime_init:
bx lr bx lr
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// In case core 1's VTOR has already been moved into flash, we need to handle // If core 1 somehow gets into crt0 due to a spectacular VTOR mishap, we need to
// core 1 reset. However, we do so by just jumping back into bootrom version of // catch it and send back to the sleep-and-launch code in the bootrom. Shouldn't
// wait_for_vector // 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) ldr r0, = 'W' | ('V' << 8)
bl rom_func_lookup bl rom_func_lookup
bx r0 bx r0
@ -312,4 +326,4 @@ __get_current_exception:
.section .heap .section .heap
.align 2 .align 2
.equ HeapSize, PICO_HEAP_SIZE .equ HeapSize, PICO_HEAP_SIZE
.space HeapSize .space HeapSize

View File

@ -59,12 +59,11 @@ SECTIONS
*/ */
.text : { .text : {
__reset_start = .; __logical_binary_start = .;
KEEP (*(.reset))
. = ALIGN(256);
__reset_end = .;
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
KEEP (*(.vectors)) KEEP (*(.vectors))
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
KEEP (*(.reset))
/* TODO revisit this now memset/memcpy/float in ROM */ /* 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 /* 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 */ * 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 */ /* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") 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 */ /* todo assert on extra code */
} }

View File

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

View File

@ -59,12 +59,11 @@ SECTIONS
*/ */
.text : { .text : {
__reset_start = .; __logical_binary_start = .;
KEEP (*(.reset))
. = ALIGN(256);
__reset_end = .;
ASSERT(__reset_end - __reset_start == 256, "ERROR: reset section should only be 256 bytes");
KEEP (*(.vectors)) KEEP (*(.vectors))
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
KEEP (*(.reset))
/* TODO revisit this now memset/memcpy/float in ROM */ /* 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 /* 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 */ * 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 */ /* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") 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 */ /* todo assert on extra code */
} }

View File

@ -32,19 +32,21 @@ ENTRY(_entry_point)
SECTIONS SECTIONS
{ {
/* Watchdog reboot into RAM (via USB MSD will enter) image at the start of .text /* Note in NO_FLASH builds the entry point for both the bootrom, and debugger
The debugger will use the ELF entry point, which is the _entry_point entry (ELF entry point), are *first* in the image, and the vector table
symbol if present, otherwise defaults to start of .text. 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 : { .text : {
__reset_start = .; __logical_binary_start = .;
__reset_start = .;
KEEP (*(.reset)) KEEP (*(.reset))
/* reset should come first */
KEEP (*(.reset))
. = ALIGN(256);
__reset_end = .; __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)) KEEP (*(.vectors))
*(.time_critical*) *(.time_critical*)
*(.text*) *(.text*)
@ -208,6 +210,8 @@ SECTIONS
/* Check if data + heap + stack exceeds RAM limit */ /* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") 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 */ /* todo assert on extra code */
} }