diff --git a/src/rp2_common/boot_stage2/CMakeLists.txt b/src/rp2_common/boot_stage2/CMakeLists.txt index 1f6a298..47fa125 100644 --- a/src/rp2_common/boot_stage2/CMakeLists.txt +++ b/src/rp2_common/boot_stage2/CMakeLists.txt @@ -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) diff --git a/src/rp2_common/boot_stage2/asminclude/boot2_helpers/exit_from_boot2.S b/src/rp2_common/boot_stage2/asminclude/boot2_helpers/exit_from_boot2.S new file mode 100644 index 0000000..6f06fc1 --- /dev/null +++ b/src/rp2_common/boot_stage2/asminclude/boot2_helpers/exit_from_boot2.S @@ -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 diff --git a/src/rp2_common/boot_stage2/asminclude/boot2_helpers/read_flash_sreg.S b/src/rp2_common/boot_stage2/asminclude/boot2_helpers/read_flash_sreg.S new file mode 100644 index 0000000..83698ed --- /dev/null +++ b/src/rp2_common/boot_stage2/asminclude/boot2_helpers/read_flash_sreg.S @@ -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 diff --git a/src/rp2_common/boot_stage2/asminclude/boot2_helpers/wait_ssi_ready.S b/src/rp2_common/boot_stage2/asminclude/boot2_helpers/wait_ssi_ready.S new file mode 100644 index 0000000..2e49b64 --- /dev/null +++ b/src/rp2_common/boot_stage2/asminclude/boot2_helpers/wait_ssi_ready.S @@ -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 diff --git a/src/rp2_common/boot_stage2/boot2_generic_03h.S b/src/rp2_common/boot_stage2/boot2_generic_03h.S index 68d1ef2..a10e66a 100644 --- a/src/rp2_common/boot_stage2/boot2_generic_03h.S +++ b/src/rp2_common/boot_stage2/boot2_generic_03h.S @@ -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: diff --git a/src/rp2_common/boot_stage2/boot2_is25lp080.S b/src/rp2_common/boot_stage2/boot2_is25lp080.S index 3c33e5b..80bf9d1 100644 --- a/src/rp2_common/boot_stage2/boot2_is25lp080.S +++ b/src/rp2_common/boot_stage2/boot2_is25lp080.S @@ -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 diff --git a/src/rp2_common/boot_stage2/boot2_usb_blinky.S b/src/rp2_common/boot_stage2/boot2_usb_blinky.S index fcf057e..74c47a3 100644 --- a/src/rp2_common/boot_stage2/boot2_usb_blinky.S +++ b/src/rp2_common/boot_stage2/boot2_usb_blinky.S @@ -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 diff --git a/src/rp2_common/boot_stage2/boot2_w25q080.S b/src/rp2_common/boot_stage2/boot2_w25q080.S index 0b4178d..ad3238e 100644 --- a/src/rp2_common/boot_stage2/boot2_w25q080.S +++ b/src/rp2_common/boot_stage2/boot2_w25q080.S @@ -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 diff --git a/src/rp2_common/boot_stage2/boot2_w25x10cl.S b/src/rp2_common/boot_stage2/boot2_w25x10cl.S index 80f82c6..02628d4 100644 --- a/src/rp2_common/boot_stage2/boot2_w25x10cl.S +++ b/src/rp2_common/boot_stage2/boot2_w25x10cl.S @@ -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 diff --git a/src/rp2_common/pico_standard_link/crt0.S b/src/rp2_common/pico_standard_link/crt0.S index 9b62134..95a44ff 100644 --- a/src/rp2_common/pico_standard_link/crt0.S +++ b/src/rp2_common/pico_standard_link/crt0.S @@ -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 \ No newline at end of file +.space HeapSize diff --git a/src/rp2_common/pico_standard_link/memmap_blocked_ram.ld b/src/rp2_common/pico_standard_link/memmap_blocked_ram.ld index 1803591..3f34237 100644 --- a/src/rp2_common/pico_standard_link/memmap_blocked_ram.ld +++ b/src/rp2_common/pico_standard_link/memmap_blocked_ram.ld @@ -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 */ } diff --git a/src/rp2_common/pico_standard_link/memmap_copy_to_ram.ld b/src/rp2_common/pico_standard_link/memmap_copy_to_ram.ld index 8bd4009..23a62b9 100644 --- a/src/rp2_common/pico_standard_link/memmap_copy_to_ram.ld +++ b/src/rp2_common/pico_standard_link/memmap_copy_to_ram.ld @@ -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 */ } diff --git a/src/rp2_common/pico_standard_link/memmap_default.ld b/src/rp2_common/pico_standard_link/memmap_default.ld index 5a927fe..934cfbd 100644 --- a/src/rp2_common/pico_standard_link/memmap_default.ld +++ b/src/rp2_common/pico_standard_link/memmap_default.ld @@ -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 */ } diff --git a/src/rp2_common/pico_standard_link/memmap_no_flash.ld b/src/rp2_common/pico_standard_link/memmap_no_flash.ld index a3f972a..7a5977f 100644 --- a/src/rp2_common/pico_standard_link/memmap_no_flash.ld +++ b/src/rp2_common/pico_standard_link/memmap_no_flash.ld @@ -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 */ }