diff --git a/arch/src/Makefile b/arch/src/Makefile index c766542e57c97741da6d53296896c622d3ec05b5..3ef76ef32d54a00e9ba8cffe6bee487720944382 100644 --- a/arch/src/Makefile +++ b/arch/src/Makefile @@ -10,18 +10,11 @@ include $(BS_DIR)/toolchain.mk BS_LIB_NAME = arch -BS_LIB_SOURCES_armv7-m += armv7-m/exception.S -BS_LIB_SOURCES_armv7-m += armv7-m/config.S +BS_LIB_SOURCES_armv7-m += armv7-m/exceptions.c BS_LIB_SOURCES_armv7-m += arm_nvic.c BS_LIB_SOURCES_armv7-m += arm_main.c BS_LIB_SOURCES_armv7-m += arm_mm.c -ifeq ($(BS_LINKER),ARM) - BS_LIB_SOURCES_armv7-m += armv7-m/reset_arm.S -else - BS_LIB_SOURCES_armv7-m += armv7-m/reset_newlib.S -endif - BS_LIB_INCLUDES_armv7-m += $(TOP_DIR)/cmsis/CMSIS/Core/Include/ BS_LIB_SOURCES_host += host.c diff --git a/arch/src/arm_main.c b/arch/src/arm_main.c index d4feb76c330b6076162bb56f4746dd447c52ac10..e6faaf524bf30f056d7df6496fc5299887dcce4c 100644 --- a/arch/src/arm_main.c +++ b/arch/src/arm_main.c @@ -9,8 +9,15 @@ #include #include #include +#include #include +#define SCB_CCR ((FWK_RW uint32_t *)(0xE000ED14)) + +#define SCB_CCR_UNALIGN_TRP_MASK (1U << 3) +#define SCB_CCR_DIV_0_TRP_MASK (1U << 4) +#define SCB_CCR_STKALIGN_MASK (1U << 9) + extern int arm_nvic_init(struct fwk_arch_interrupt_driver **driver); extern int arm_mm_init(struct fwk_arch_mm_data *data); @@ -52,7 +59,31 @@ static struct fwk_arch_init_driver arch_init_driver = { .interrupt = arm_nvic_init, }; +static void arm_init_ccr(void) +{ + /* + * Set up the Configuration Control Register (CCR) in the System Control + * Block (1) by setting the following flag bits: + * + * UNALIGN_TRP [3]: Enable trapping on unaligned word or halfword accesses. + * DIV_0_TRP [4]: Enable trapping on division by zero. + * STKALIGN [9]: Enable automatic DWORD stack-alignment on exception + * entry (2). + * + * All other bits are left in their default state. + * + * (1) ARM® v7-M Architecture Reference Manual, section B3.2.8. + * (2) ARM® v7-M Architecture Reference Manual, section B1.5.7. + */ + + *SCB_CCR |= SCB_CCR_UNALIGN_TRP_MASK; + *SCB_CCR |= SCB_CCR_DIV_0_TRP_MASK; + *SCB_CCR |= SCB_CCR_STKALIGN_MASK; +} + int main(void) { + arm_init_ccr(); + return fwk_arch_init(&arch_init_driver); } diff --git a/arch/src/arm_mm.c b/arch/src/arm_mm.c index 5a434b102c4f3d4bded02b2792cabaa7a4c81e7d..66144706ff2cf8e1cb2e6c101bce38cd07dfca19 100644 --- a/arch/src/arm_mm.c +++ b/arch/src/arm_mm.c @@ -19,22 +19,20 @@ int arm_mm_init(struct fwk_arch_mm_data *data) fwk_assert(data != NULL); #ifdef __ARMCC_VERSION -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" - extern unsigned int Image$$ARM_LIB_STACKHEAP$$ZI$$Base; extern unsigned int Image$$ARM_LIB_STACKHEAP$$ZI$$Length; data->start = (uintptr_t)(&Image$$ARM_LIB_STACKHEAP$$ZI$$Base); data->size = (size_t)(&Image$$ARM_LIB_STACKHEAP$$ZI$$Length); - -# pragma clang diagnostic pop #else - extern unsigned int __stackheap_start__; - extern unsigned int __stackheap_size__; + extern char __stackheap_start__; + extern char __stackheap_end__; + + uintptr_t start = (uintptr_t)(&__stackheap_start__); + uintptr_t end = (uintptr_t)(&__stackheap_end__); - data->start = (uintptr_t)(&__stackheap_start__); - data->size = (size_t)(&__stackheap_size__); + data->start = start; + data->size = end - start; #endif return FWK_SUCCESS; diff --git a/arch/src/arm_nvic.c b/arch/src/arm_nvic.c index 38e192afbe0cada0f38ca966dd224446b433a66d..9fb2701347b54bdc6102b53a8aa725d7e00574bc 100644 --- a/arch/src/arm_nvic.c +++ b/arch/src/arm_nvic.c @@ -23,7 +23,7 @@ #include #endif -extern noreturn void exception_invalid(void); +extern noreturn void arm_exception_invalid(void); struct nvic; @@ -310,14 +310,14 @@ int arm_nvic_init(const struct fwk_arch_interrupt_driver **driver) return FWK_E_NOMEM; /* - * Initialize all exception entries to point to the exception_invalid() + * Initialize all exception entries to point to the arm_exception_invalid() * handler. * * Note: Initialization starts from entry 1 since entry 0 is not an * exception pointer but the default stack pointer. */ for (i = 1; i < EXCEPTION_NUM_COUNT; i++) - vector[i] = exception_invalid; + vector[i] = arm_exception_invalid; /* Initialize IRQs */ for (i = 0; i < irq_count; i++) { diff --git a/arch/src/armv7-m/config.S b/arch/src/armv7-m/config.S deleted file mode 100644 index 48fd05646203c515005a70eec84b0efc351b65c8..0000000000000000000000000000000000000000 --- a/arch/src/armv7-m/config.S +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Arm SCP/MCP Software - * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Description: - * Architectural configuration. - */ - - .syntax unified - - .text - - .global arm_init_ccr - .thumb_func - .type arm_init_ccr, %function -arm_init_ccr: - /* - * Set up the Configuration Control Register (CCR) in the System Control - * Block (1) by setting the following flag bits: - * - * UNALIGN_TRP [3]: Enable trapping on unaligned word or halfword accesses. - * DIV_0_TRP [4]: Enable trapping on division by zero. - * STKALIGN [9]: Enable automatic DWORD stack-alignment on exception - * entry (2). - * - * All other bits are left in their default state. - * - * (1) ARM® v7-M Architecture Reference Manual, section B3.2.8. - * (2) ARM® v7-M Architecture Reference Manual, section B1.5.7. - */ - ldr r0, =0xE000ED14 /* Load CCR address (architecture-defined) */ - ldr r1, [r0] /* Load existing CCR value */ - orr r1, #0x218 /* Set flag bits */ - str r1, [r0] /* Store modified value back to the CCR */ - - bx lr - .pool diff --git a/arch/src/armv7-m/exception.S b/arch/src/armv7-m/exception.S deleted file mode 100644 index 18f3c133a887d52171b12af132302c04b741a264..0000000000000000000000000000000000000000 --- a/arch/src/armv7-m/exception.S +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Arm SCP/MCP Software - * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - - .syntax unified - - .section .exception, "a", %progbits - -/* - * We set up the exception table here. The table is put inside the ".exception" - * section, which is marked as PROGBITS (takes up space in the binary). The - * "exceptions" symbol is given the same ELF attributes as a standard C - * structure (allocatable object) in order to ensure it is properly exported - * or loaded. See the GNU assembler documentation for the exact meaning behind - * the directives provided here. See the .exception section described in the GNU - * linker script for the first two entries of the exception table. - */ - - .global exceptions -exceptions: - .word exception_invalid /* NMI */ - .word exception_invalid /* HardFault */ - .word exception_invalid /* MemManage */ - .word exception_invalid /* Bus Fault */ - .word exception_invalid /* UsageFault */ - .word exception_invalid /* Reserved */ - .word exception_invalid /* Reserved */ - .word exception_invalid /* Reserved */ - .word exception_invalid /* Reserved */ - .word exception_invalid /* SVCall */ - .word exception_invalid /* DebugMonitor */ - .word exception_invalid /* Reserved */ - .word exception_invalid /* PendSV */ - .word exception_invalid /* SysTick */ - - .type exceptions, %object - .size exceptions, . - exceptions - - .section .text - - .global exception_invalid - .thumb_func - .type exception_invalid, %function - .eabi_attribute Tag_ABI_align_preserved, 1 -exception_invalid: - wfi - b exception_invalid diff --git a/arch/src/armv7-m/exceptions.c b/arch/src/armv7-m/exceptions.c new file mode 100644 index 0000000000000000000000000000000000000000..143f63c67e45ac1b453a47138efe47d427a8ae0a --- /dev/null +++ b/arch/src/armv7-m/exceptions.c @@ -0,0 +1,122 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * ARMv7-M exception handlers. + */ + +#include +#include +#include +#include +#include + +#ifdef __NEWLIB__ +/* + * This function overloads a weak definition provided by Newlib. It is called + * during initialization of the C runtime just after .bss has been zeroed. + */ +void software_init_hook(void) +{ + extern char __data_load__; + extern char __data_start__; + extern char __data_end__; + + char *load = &__data_load__; + char *start = &__data_start__; + char *end = &__data_end__; + + if (load != start) + memcpy(start, load, end - start); +} +#endif + +noreturn void arm_exception_reset(void) +{ + /* + * When entering the firmware, before the framework is entered the following + * things happen: + * 1. The toolchain-specific C runtime is initialized + * For Arm Compiler: + * 1. Zero-initialized data is zeroed + * 2. Initialized data is decompressed and copied + * For GCC/Newlib: + * 1. Zero-initialized data is zeroed + * 2. Initialized data is copied by software_init_hook() + * 2. The main() function is called by the C runtime + */ + +#ifdef __ARMCC_VERSION + extern noreturn void __main(void); + + __main(); +#else + extern noreturn void _start(void); + + _start(); +#endif +} + +noreturn void arm_exception_invalid(void) +{ + while (true) + __WFI(); +} + +enum { + EXCEPTION_RESET, + EXCEPTION_NMI, + EXCEPTION_HARDFAULT, + EXCEPTION_MEMMANAGE, + EXCEPTION_BUSFAULT, + EXCEPTION_USAGEFAULT, + EXCEPTION_RESERVED0, + EXCEPTION_RESERVED1, + EXCEPTION_RESERVED2, + EXCEPTION_RESERVED3, + EXCEPTION_SVCALL, + EXCEPTION_DEBUGMONITOR, + EXCEPTINO_RESERVED4, + EXCEPTION_PENDSV, + EXCEPTION_SYSTICK, +}; + +#ifdef __ARMCC_VERSION +extern char Image$$ARM_LIB_STACKHEAP$$ZI$$Limit; + +# define arm_exception_stack (&Image$$ARM_LIB_STACKHEAP$$ZI$$Limit) +#else +extern char __stackheap_end__; + +# define arm_exception_stack (&__stackheap_end__) +#endif + +/* + * Set up the exception table. The structure below is marked as static because + * it doesn't need to be visible outside of this translation unit, but it is + * marked as used to ensure it is not removed by the compiler. It is added to + * the .exceptions section which will be explicitly placed at the beginning of + * the binary by the linker script. + */ + +static const struct { + uintptr_t stack; + uintptr_t exceptions[15]; +} exceptions __attribute__((used, section(".exceptions"))) = { + .stack = (uintptr_t)(arm_exception_stack), + .exceptions = { + [EXCEPTION_RESET] = (uintptr_t)(arm_exception_reset), + [EXCEPTION_NMI] = (uintptr_t)(arm_exception_invalid), + [EXCEPTION_HARDFAULT] = (uintptr_t)(arm_exception_invalid), + [EXCEPTION_MEMMANAGE] = (uintptr_t)(arm_exception_invalid), + [EXCEPTION_BUSFAULT] = (uintptr_t)(arm_exception_invalid), + [EXCEPTION_USAGEFAULT] = (uintptr_t)(arm_exception_invalid), + [EXCEPTION_SVCALL] = (uintptr_t)(arm_exception_invalid), + [EXCEPTION_DEBUGMONITOR] = (uintptr_t)(arm_exception_invalid), + [EXCEPTION_PENDSV] = (uintptr_t)(arm_exception_invalid), + [EXCEPTION_SYSTICK] = (uintptr_t)(arm_exception_invalid), + } +}; diff --git a/arch/src/armv7-m/ld.S b/arch/src/armv7-m/ld.S index 2050ca28ec66478a8a61f69c2af279719d9846bc..7d54f89d3c514c2884190f9bdc0ed783631cb8a0 100644 --- a/arch/src/armv7-m/ld.S +++ b/arch/src/armv7-m/ld.S @@ -6,152 +6,137 @@ * * Description: * GNU LD linker script. - * - * There are three supported memory layouts for the ARMv7-M architecture: - * - * Layout 1 - Single region: - * - All sections are placed in one contiguous region. - * - This layout uses only the mem0 memory region. - * - The memory is considered RXW by the linker, but the sections can be - * configured later on with different attributes using the MPU. - * - The main stack is placed at the end of mem0. - * - This layout is mainly used by second-stage firmware that is loaded directly - * into a single RAM. - * - * Layout 2 - Dual region with relocation: - * - One region is used for .text and .data (storage). - * - A second region is used for the remaining sections. - * - This layout uses memory regions mem0 and mem1 as the first and second - * regions, respectively. - * - The main stack is placed at the end of mem1. - * - This layout is mainly used by ROM firmware which uses part of the RAM for - * the data sections. - * - * Layout 3 - Dual region without relocation - * - One region is used only for the .text section. - * - A second region is used for all data sections. - * - This layout uses memory regions mem0 and mem1 as the first and second - * regions, respectively. - * - The main stack is placed at the end of mem1. - * - The main difference from layout 2 is that there is no relocation of the - * .data section. - * - This layout is mainly used by second-stage firmware loaded directly into - * two RAM regions. One of the RAM regions is attached to the instruction bus, - * which improves the performance as data and instruction accesses are - * independent. - * - */ - -#define FWK_MEM_MODE_INVALID 0 -#define FWK_MEM_MODE_SINGLE_REGION 1 -#define FWK_MEM_MODE_DUAL_REGION_RELOCATION 2 -#define FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION 3 - -#include - -/* Align the stack on an 8-byte boundary as CCR.STKALIGN is enabled */ -#define STACK_ALIGNMENT 8 - -/* Align the heap on a 4-byte boundary to avoid unaligned accesses */ -#define HEAP_ALIGNMENT 4 - -/* - * Input validation */ -#ifndef FIRMWARE_MEM_MODE - #error "FIRMWARE_MEM_MODE has not been configured" -#endif - -#ifndef FIRMWARE_MEM0_BASE - #error "FIRMWARE_MEM0_BASE has not been configured" -#endif +#include "scatter.h" -#ifndef FIRMWARE_MEM0_SIZE - #error "FIRMWARE_MEM0_SIZE has not been configured" -#endif - -#if ((FIRMWARE_MEM_MODE != FWK_MEM_MODE_SINGLE_REGION) && \ - (FIRMWARE_MEM_MODE != FWK_MEM_MODE_DUAL_REGION_RELOCATION) && \ - (FIRMWARE_MEM_MODE != FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION)) - #error "FIRMWARE_MEM_MODE has been configured improperly" -#endif - -#if FIRMWARE_MEM_MODE != FWK_MEM_MODE_SINGLE_REGION - #ifndef FIRMWARE_MEM1_BASE - #error "FIRMWARE_MEM1_BASE has not been configured" - #endif - - #ifndef FIRMWARE_MEM1_SIZE - #error "FIRMWARE_MEM1_SIZE has not been configured" - #endif -#endif - -ENTRY(exception_reset) +ENTRY(arm_exception_reset) MEMORY { #if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION - mem0 : ORIGIN = FIRMWARE_MEM0_BASE, LENGTH = FIRMWARE_MEM0_SIZE -#else + /* + * Single region memory layout: + * - MEM0 accepts: + * - Read-only sections + * - Read-write sections + * - Executable sections + */ + + mem0 (rwx) : ORIGIN = FIRMWARE_MEM0_BASE, LENGTH = FIRMWARE_MEM0_SIZE +#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_RELOCATION + /* + * Dual region memory layout with initialized data relocation: + * - MEM0 accepts: + * - Read-only sections + * - Executable sections + * + * - MEM1 accepts: + * - Read-write sections + */ + mem0 (rx) : ORIGIN = FIRMWARE_MEM0_BASE, LENGTH = FIRMWARE_MEM0_SIZE - mem1 (!rx) : ORIGIN = FIRMWARE_MEM1_BASE, LENGTH = FIRMWARE_MEM1_SIZE + mem1 (w) : ORIGIN = FIRMWARE_MEM1_BASE, LENGTH = FIRMWARE_MEM1_SIZE +#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION + /* + * Dual region memory layout without initialized data relocation: + * - MEM0 accepts: + * - Executable sections + * + * - MEM1 accepts: + * - Read-only sections + * - Read-write sections + */ + + mem0 (x) : ORIGIN = FIRMWARE_MEM0_BASE, LENGTH = FIRMWARE_MEM0_SIZE + mem1 (rw) : ORIGIN = FIRMWARE_MEM1_BASE, LENGTH = FIRMWARE_MEM1_SIZE #endif } #if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION - REGION_ALIAS("mem1", mem0); -#endif - -REGION_ALIAS("vexception", mem0); -REGION_ALIAS("vtext", mem0); -REGION_ALIAS("vrodata", mem0); -REGION_ALIAS("vdata", mem1); -REGION_ALIAS("vbss", mem1); -REGION_ALIAS("vstackheap", mem1); - -#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION - REGION_ALIAS("ldata", mem1); /* .data is loaded into mem1 by a loader */ -#else - REGION_ALIAS("ldata", mem0); /* .data is loaded into mem1 by crt0 */ + REGION_ALIAS("r", mem0); + REGION_ALIAS("w", mem0); + REGION_ALIAS("x", mem0); +#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_RELOCATION + REGION_ALIAS("r", mem0); + REGION_ALIAS("w", mem1); + REGION_ALIAS("x", mem0); +#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION + REGION_ALIAS("r", mem1); + REGION_ALIAS("w", mem1); + REGION_ALIAS("x", mem0); #endif SECTIONS { - .exception : { - LONG(__stack) - LONG(exception_reset | 1) /* The LSB must be set for Thumb functions */ - KEEP(*(.exception)) - } > vexception + /* + * Variables defined here: + * - __data_load__: Load address of .data + * - __data_start__: Start address of .data + * - __data_end__: End address of .data and .data-like orphans + * - __bss_start__: Start address of .bss + * - __bss_end__: End address of .bss and .bss-like orphans + * - __stackheap_start__: Start address of .stackheap + * - __stackheap_end__: End address of .stackheap + * - __stack: Initial stack pointer + */ + + .exceptions : { + KEEP(*(.exceptions)) + } > x .text : { *(.text .text.*) - } > vtext + } > x + + /* + * .init and .fini below refer to sections containing functions meant to + * run before program startup and after program shutdown. While we don't use + * these functions, Newlib refers to them unconditionally and they are, + * perhaps counterintuitively, stripped from the binary unless marked as + * KEEP. + */ + + .init : { + KEEP(*(.init)) + } > x + + .fini : { + KEEP(*(.fini)) + } > x .rodata : { *(.rodata .rodata.*) - } > vrodata + } > r .data : { + __data_load__ = LOADADDR(.data); + __data_start__ = ABSOLUTE(.); + *(.data .data.*) - } > vdata AT>ldata + } > w AT> r + + .bss (NOLOAD) : { + __bss_start__ = ABSOLUTE(.); - .bss : { *(.bss .bss.*) - } > vbss + } > w + + .stackheap (NOLOAD) : { + __stackheap_start__ = ABSOLUTE(.); - .stackheap ALIGN(HEAP_ALIGNMENT) : { - . = ORIGIN(vstackheap) + LENGTH(vstackheap) - (STACK_ALIGNMENT - 1); - . = ALIGN(STACK_ALIGNMENT); - } > vstackheap + . = ORIGIN(w) + LENGTH(w); - __stackheap_start__ = ADDR(.stackheap); - __stackheap_size__ = SIZEOF(.stackheap); + __stackheap_end__ = ABSOLUTE(.); + } > w - __data_start_vma__ = ADDR(.data); - __data_start_lma__ = LOADADDR(.data); - __data_size__ = SIZEOF(.data); + /* + * By default the linker places orphan sections after the section with the + * closest matching attributes. Calculating the end of a section based on + * the beginning of the next one that we know about means we can include BSS + * and DATA sections that we don't know about in these values. + */ - __bss_start__ = ADDR(.bss); - __bss_end__ = __bss_start__ + SIZEOF(.bss); + __data_end__ = __bss_start__; + __bss_end__ = __stackheap_start__; - __stack = __stackheap_start__ + __stackheap_size__; + __stack = __stackheap_end__; } diff --git a/arch/src/armv7-m/reset_arm.S b/arch/src/armv7-m/reset_arm.S deleted file mode 100644 index 3e57ba316f73777a87cf402fc0030c65cf55320b..0000000000000000000000000000000000000000 --- a/arch/src/armv7-m/reset_arm.S +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Arm SCP/MCP Software - * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Description: - * C runtime initialization for Arm Compiler 6. - */ - - .syntax unified - - .text - - .global exception_reset - .thumb_func - .type exception_reset, %function -exception_reset: - bl arm_init_ccr /* Initialize the CCR register */ - b __main /* Enter Arm Compiler 6's crt0 */ - .pool diff --git a/arch/src/armv7-m/reset_newlib.S b/arch/src/armv7-m/reset_newlib.S deleted file mode 100644 index b474d3203933bf51be418ff9a33f03ce07160d68..0000000000000000000000000000000000000000 --- a/arch/src/armv7-m/reset_newlib.S +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Arm SCP/MCP Software - * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - * Description: - * C runtime initialization for Newlib. - */ - - .syntax unified - - .text - - .global exception_reset - .thumb_func - .type exception_reset, %function -exception_reset: - b _start /* Enter Newlib's crt0 */ - .pool - -/* - * The following *_init_hook functions are called from _start and provide an - * early opportunity to do some critical runtime setup. From the point of view - * of the runtime, there is no difference between the hardware and software - * hook, but the hardware hook is called before the software hook. Accesses to - * mem1 are invalid until the data residing in it has been initialized by the - * software hook. - */ - - .global hardware_init_hook - .thumb_func - .type hardware_init_hook, %function -hardware_init_hook: - b arm_init_ccr /* Initialize the CCR register */ - .pool - - .global software_init_hook - .thumb_func - .type software_init_hook, %function -software_init_hook: - ldr r0, =__data_start_vma__ - ldr r1, =__data_start_lma__ - ldr r2, =__data_size__ - - cmp r0, r1 - bne memcpy /* Copy .data from ROM to RAM if necessary */ - bx lr /* Otherwise return */ - .pool diff --git a/arch/src/armv7-m/scatter.S b/arch/src/armv7-m/scatter.S index 57a41debd9163ea3e1f6f6c344d40225b81b6cce..0e90df2e9a5221bc9b96e3a7f3a014ed02a3dbfc 100644 --- a/arch/src/armv7-m/scatter.S +++ b/arch/src/armv7-m/scatter.S @@ -6,104 +6,80 @@ * * Description: * Arm Compiler 6 scatter file. - * - * There are three supported memory layouts for the ARMv7-M architecture: - * - * Layout 1 - Single region: - * - All sections are placed in one contiguous region. - * - This layout uses only the mem0 memory region. - * - The memory is considered RXW by the linker, but the sections can be - * configured later on with different attributes using the MPU. - * - The main stack is placed at the end of mem0. - * - This layout is mainly used by second-stage firmware that is loaded directly - * into a single RAM. - * - * Layout 2 - Dual region with relocation: - * - One region is used for .text and .data (storage). - * - A second region is used for the remaining sections. - * - This layout uses memory regions mem0 and mem1 as the first and second - * regions, respectively. - * - The main stack is placed at the end of mem1. - * - This layout is mainly used by ROM firmware which uses part of the RAM for - * the data sections. - * - * Layout 3 - Dual region without relocation - * - One region is used only for the .text section. - * - A second region is used for all data sections. - * - This layout uses memory regions mem0 and mem1 as the first and second - * regions, respectively. - * - The main stack is placed at the end of mem1. - * - The main difference from layout 2 is that there is no relocation of the - * .data section. - * - This layout is mainly used by second-stage firmware loaded directly into - * two RAM regions. One of the RAM regions is attached to the instruction bus, - * which improves the performance as data and instruction accesses are - * independent. - * */ -#define FWK_MEM_MODE_INVALID 0 -#define FWK_MEM_MODE_SINGLE_REGION 1 -#define FWK_MEM_MODE_DUAL_REGION_RELOCATION 2 -#define FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION 3 +#include "scatter.h" -#include - -/* - * Input validation - */ - -#ifndef FIRMWARE_MEM_MODE - #error "FIRMWARE_MEM_MODE has not been configured" -#endif +#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION + /* + * Single region memory layout: + * - MEM0 accepts: + * - Read-only sections + * - Read-write sections + * - Executable sections + */ -#ifndef FIRMWARE_MEM0_BASE - #error "FIRMWARE_MEM0_BASE has not been configured" -#endif + #define FIRMWARE_X_BASE +0 + #define FIRMWARE_R_BASE +0 + #define FIRMWARE_W_BASE +0 +#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_RELOCATION + /* + * Dual region memory layout with initialized data relocation: + * - MEM0 accepts: + * - Read-only sections + * - Executable sections + * + * - MEM1 accepts: + * - Read-write sections + */ -#ifndef FIRMWARE_MEM0_SIZE - #error "FIRMWARE_MEM0_SIZE has not been configured" -#endif + #define FIRMWARE_X_BASE +0 + #define FIRMWARE_R_BASE +0 -#if ((FIRMWARE_MEM_MODE != FWK_MEM_MODE_SINGLE_REGION) && \ - (FIRMWARE_MEM_MODE != FWK_MEM_MODE_DUAL_REGION_RELOCATION) && \ - (FIRMWARE_MEM_MODE != FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION)) - #error "FIRMWARE_MEM_MODE has been configured improperly" -#endif + #define FIRMWARE_W_BASE FIRMWARE_MEM1_BASE +#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION + /* + * Dual region memory layout without initialized data relocation: + * - MEM0 accepts: + * - Executable sections + * + * - MEM1 accepts: + * - Read-only sections + * - Read-write sections + */ -#if FIRMWARE_MEM_MODE != FWK_MEM_MODE_SINGLE_REGION - #ifndef FIRMWARE_MEM1_BASE - #error "FIRMWARE_MEM1_BASE has not been configured" - #endif + #define FIRMWARE_X_BASE +0 - #ifndef FIRMWARE_MEM1_SIZE - #error "FIRMWARE_MEM1_SIZE has not been configured" - #endif + #define FIRMWARE_R_BASE FIRMWARE_MEM1_BASE + #define FIRMWARE_W_BASE +0 #endif -#define FIRMWARE_MEM0_LIMIT (FIRMWARE_MEM0_BASE + FIRMWARE_MEM0_SIZE) - #if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION - #define FIRMWARE_MEM1_BASE +0 - #define FIRMWARE_MEM1_LIMIT (FIRMWARE_MEM0_BASE + FIRMWARE_MEM0_SIZE) - #define FIRMWARE_MEM1_SIZE (FIRMWARE_MEM1_LIMIT - ImageLimit(ER_RODATA)) + #define FIRMWARE_W_LIMIT FIRMWARE_MEM0_LIMIT #else - #define FIRMWARE_MEM1_LIMIT (FIRMWARE_MEM1_BASE + FIRMWARE_MEM1_SIZE) + #define FIRMWARE_W_LIMIT FIRMWARE_MEM1_LIMIT #endif -LR_MEM0 FIRMWARE_MEM0_BASE FIRMWARE_MEM0_SIZE { - ER_EXCEPTION +0 { - *(:gdef:__vectab_stack_and_reset, +FIRST) - *(.exception) +LR_FIRMWARE FIRMWARE_MEM0_BASE { + ER_EXCEPTIONS FIRMWARE_X_BASE { + *(.exceptions) + } + + ER_TEXT +0 { + *(+CODE) + } + + ER_RODATA FIRMWARE_R_BASE { + *(+CONST) } - ER_RODATA +0 { - *(+RO) + ER_DATA FIRMWARE_W_BASE { + *(+DATA) } - ER_RWDATA FIRMWARE_MEM1_BASE { - *(+RW, +ZI) + ER_BSS +0 { + *(+BSS) } - ARM_LIB_STACKHEAP +0 EMPTY (FIRMWARE_MEM1_LIMIT - ImageLimit(ER_RWDATA)) { } + ARM_LIB_STACKHEAP +0 EMPTY (FIRMWARE_W_LIMIT - +0) { } } diff --git a/arch/src/armv7-m/scatter.h b/arch/src/armv7-m/scatter.h new file mode 100644 index 0000000000000000000000000000000000000000..8afa8979a78c8522bd42ded6155fdcd94c4fb9cb --- /dev/null +++ b/arch/src/armv7-m/scatter.h @@ -0,0 +1,70 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Common linker script configuration options. + * + * There are three supported memory layouts for the ARMv7-M architecture: + * + * Layout 1 - Single region: + * This layout uses a single read/write/execute memory region for all data. + * This is traditionally used by firmware running from a general-purpose + * RAM region. In this configuration MEM0 represents the RAM region, and + * MEM1 is unused. + * + * Layout 2 - Dual region with relocation: + * This layout uses a read/execute memory region for read-only and + * executable data, and a write memory region for writable data. This is + * traditionally used by firmware running from a ROM region. In this + * configuration MEM0 represents the ROM region and MEM1 represents the RAM + * region. + * + * Layout 3 - Dual region without relocation: + * This layout uses an execute memory region for executable data, and a + * read/write memory region for writable data. This is traditionally used + * by firmware running from a RAM region attached to the instruction bus. + * In this configuration MEM0 represents the RAM region attached to the + * instruction bus and MEM1 represents the RAM region attached to the data + * bus. + */ + +#define FWK_MEM_MODE_SINGLE_REGION 0 +#define FWK_MEM_MODE_DUAL_REGION_RELOCATION 1 +#define FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION 2 + +#include + +#ifndef FIRMWARE_MEM_MODE + #error "FIRMWARE_MEM_MODE has not been configured" +#endif + +#if (FIRMWARE_MEM_MODE != FWK_MEM_MODE_SINGLE_REGION) && \ + (FIRMWARE_MEM_MODE != FWK_MEM_MODE_DUAL_REGION_RELOCATION) && \ + (FIRMWARE_MEM_MODE != FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION) + #error "FIRMWARE_MEM_MODE has been configured improperly" +#endif + +#ifndef FIRMWARE_MEM0_BASE + #error "FIRMWARE_MEM0_BASE has not been configured" +#endif + +#ifndef FIRMWARE_MEM0_SIZE + #error "FIRMWARE_MEM0_SIZE has not been configured" +#endif + +#define FIRMWARE_MEM0_LIMIT (FIRMWARE_MEM0_BASE + FIRMWARE_MEM0_SIZE) + +#if FIRMWARE_MEM_MODE != FWK_MEM_MODE_SINGLE_REGION + #ifndef FIRMWARE_MEM1_BASE + #error "FIRMWARE_MEM1_BASE has not been configured" + #endif + + #ifndef FIRMWARE_MEM1_SIZE + #error "FIRMWARE_MEM1_SIZE has not been configured" + #endif + + #define FIRMWARE_MEM1_LIMIT (FIRMWARE_MEM1_BASE + FIRMWARE_MEM1_SIZE) +#endif diff --git a/tools/build_system/rules.mk b/tools/build_system/rules.mk index 2f3b183613e9c7caf273c7b1b2a75a0ca1527c99..6fb61d9c6faa59b90d54f21bf0482aefdc466bc7 100644 --- a/tools/build_system/rules.mk +++ b/tools/build_system/rules.mk @@ -37,7 +37,7 @@ endif # GCC-specific optimization levels for debug and release modes # DEFAULT_OPT_GCC_DEBUG := g -DEFAULT_OPT_GCC_RELEASE := 3 +DEFAULT_OPT_GCC_RELEASE := 2 # # Compiler options used when building for the host @@ -97,6 +97,15 @@ CFLAGS_GCC += -Wno-missing-field-initializers # warn about the situations that have not already been fixed. CFLAGS_CLANG += -Wno-missing-braces +# Place functions and data into their own sections. This allows the linker to +# strip out functions with no references. +CFLAGS_GCC += -ffunction-sections -fdata-sections +LDFLAGS_GCC += -Wl,--gc-sections +LDFLAGS_ARM += -Wl,--remove + +# Arm Compiler 6 uses dollar symbols in its linker-defined symbol names +CFLAGS_CLANG += -Wno-dollar-in-identifier-extension + CFLAGS_GCC += -g CFLAGS_GCC += -std=c11 CFLAGS_CLANG += -fshort-enums # Required by RTX @@ -113,13 +122,7 @@ ARFLAGS_GCC = -rc LDFLAGS_GCC += -Wl,--cref -# Force an undefined reference to the exceptions table so that it is included -# even if no code refers to it. -LDFLAGS_GCC += -Wl,--undefined=exceptions -LDFLAGS_ARM += -Wl,--undefined=exceptions - -# Ensure main() is not removed by the linker -LDFLAGS_ARM += -Wl,--undefined=main +LDFLAGS_ARM += -Wl,--undefined=arm_exception_reset BUILTIN_LIBS_GCC := -lc -lgcc