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:
parent
419890cfd8
commit
166cb0fef6
@ -25,6 +25,9 @@ function(pico_define_boot_stage2 NAME SOURCES)
|
|||||||
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)
|
||||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user