aboutsummaryrefslogtreecommitdiff
path: root/arch/src
diff options
context:
space:
mode:
Diffstat (limited to 'arch/src')
-rw-r--r--arch/src/Makefile40
-rw-r--r--arch/src/arm_main.c38
-rw-r--r--arch/src/arm_mm.c57
-rw-r--r--arch/src/armv6-m/arm_nvic.c322
-rw-r--r--arch/src/armv6-m/armv6-crt0.S56
-rw-r--r--arch/src/armv6-m/exception.S42
-rw-r--r--arch/src/armv6-m/ld.S191
-rw-r--r--arch/src/armv6-m/reset-v6.S20
-rw-r--r--arch/src/armv7-m/arm_nvic.c352
-rw-r--r--arch/src/armv7-m/armv7-crt0.S53
-rw-r--r--arch/src/armv7-m/exception.S41
-rw-r--r--arch/src/armv7-m/ld.S191
-rw-r--r--arch/src/armv7-m/reset-v7.S39
-rw-r--r--arch/src/section.h77
14 files changed, 1519 insertions, 0 deletions
diff --git a/arch/src/Makefile b/arch/src/Makefile
new file mode 100644
index 0000000..d9a9205
--- /dev/null
+++ b/arch/src/Makefile
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include $(BS_DIR)/cpu.mk
+
+BS_LIB_NAME = arch
+
+BS_LIB_SOURCES_armv6-m += armv6-m/exception.S
+BS_LIB_SOURCES_armv6-m += armv6-m/reset-v6.S
+BS_LIB_SOURCES_armv6-m += armv6-m/armv6-crt0.S
+BS_LIB_SOURCES_armv6-m += armv6-m/arm_nvic.c
+BS_LIB_SOURCES_armv6-m += arm_main.c
+BS_LIB_SOURCES_armv6-m += arm_mm.c
+
+BS_LIB_INCLUDES_armv6-m += $(TOP_DIR)/cmsis/CMSIS/Core/Include/
+
+BS_LIB_SOURCES_armv7-m += armv7-m/exception.S
+BS_LIB_SOURCES_armv7-m += armv7-m/reset-v7.S
+BS_LIB_SOURCES_armv7-m += armv7-m/armv7-crt0.S
+BS_LIB_SOURCES_armv7-m += armv7-m/arm_nvic.c
+BS_LIB_SOURCES_armv7-m += arm_main.c
+BS_LIB_SOURCES_armv7-m += arm_mm.c
+
+BS_LIB_INCLUDES_armv7-m += $(TOP_DIR)/cmsis/CMSIS/Core/Include/
+
+BS_LIB_INCLUDES += $(ARCH_DIR)/include
+BS_LIB_INCLUDES += $(FWK_DIR)/include
+
+#
+# Select arch-specific sources and includes
+#
+BS_LIB_SOURCES += $(BS_LIB_SOURCES_$(BS_ARCH_CPU))
+BS_LIB_SOURCES += $(BS_LIB_SOURCES_$(BS_ARCH_ARCH))
+BS_LIB_INCLUDES += $(BS_LIB_INCLUDES_$(BS_ARCH_CPU))
+BS_LIB_INCLUDES += $(BS_LIB_INCLUDES_$(BS_ARCH_ARCH))
+
+include $(BS_DIR)/lib.mk
diff --git a/arch/src/arm_main.c b/arch/src/arm_main.c
new file mode 100644
index 0000000..eb116a7
--- /dev/null
+++ b/arch/src/arm_main.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdbool.h>
+#include <stdnoreturn.h>
+#include <fwk_arch.h>
+#include <fwk_errno.h>
+#include <cmsis_compiler.h>
+
+extern int arm_nvic_init(struct fwk_arch_interrupt_driver **driver);
+extern int arm_mm_init(struct fwk_arch_mm_data *data);
+
+/*
+ * Error handler for failures that occur during early initialization.
+ */
+static noreturn void arm_panic(void)
+{
+ while (true)
+ __WFI();
+}
+
+static struct fwk_arch_init_driver arch_init_driver = {
+ .mm = arm_mm_init,
+ .interrupt = arm_nvic_init,
+};
+
+void arm_main(void)
+{
+ int status;
+
+ status = fwk_arch_init(&arch_init_driver);
+ if (status != FWK_SUCCESS)
+ arm_panic();
+}
diff --git a/arch/src/arm_mm.c b/arch/src/arm_mm.c
new file mode 100644
index 0000000..a356150
--- /dev/null
+++ b/arch/src/arm_mm.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * Memory initialization.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <fwk_arch.h>
+#include <fwk_errno.h>
+#include <fwk_macros.h>
+#include <section.h>
+
+int arm_mm_init(struct fwk_arch_mm_data *data)
+{
+ const unsigned int ALIGNMENT = sizeof(uint64_t);
+
+ uintptr_t start;
+ uintptr_t end;
+
+ if (data == NULL)
+ return FWK_E_PARAM;
+
+ if (ARCH_SECTION_HEAP_SIZE == 0)
+ return FWK_E_NOMEM;
+
+ /* Check if the main stack section overlaps the .bss section */
+ if (ARCH_SECTION_STACK_START <= ARCH_SECTION_BSS_END) {
+ assert(false);
+ return FWK_E_PANIC;
+ }
+
+ /* Ensure the start address did not overflow following 64-bit alignment */
+ start = FWK_ALIGN_NEXT(ARCH_SECTION_HEAP_START, ALIGNMENT);
+ if (start < ARCH_SECTION_HEAP_START)
+ return FWK_E_NOMEM;
+
+ /* Ensure the end address did not underflow following 64-bit alignment */
+ end = FWK_ALIGN_PREVIOUS(ARCH_SECTION_HEAP_END, ALIGNMENT);
+ if (end > ARCH_SECTION_HEAP_END)
+ return FWK_E_NOMEM;
+
+ /*
+ * Ensure there is space left after performing 64-bit alignment on the start
+ * and end addresses.
+ */
+ if (end <= start)
+ return FWK_E_NOMEM;
+
+ data->start = start;
+ data->size = end - start;
+
+ return FWK_SUCCESS;
+}
diff --git a/arch/src/armv6-m/arm_nvic.c b/arch/src/armv6-m/arm_nvic.c
new file mode 100644
index 0000000..6c2eb33
--- /dev/null
+++ b/arch/src/armv6-m/arm_nvic.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * Interrupt management.
+ */
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdnoreturn.h>
+#include <fwk_arch.h>
+#include <fwk_errno.h>
+#include <fwk_interrupt.h>
+#include <fwk_macros.h>
+#include <fwk_mm.h>
+#include <cmsis_compiler.h>
+
+#ifdef BUILD_HAS_MULTITHREADING
+ #include <rtx_os.h>
+#endif
+
+extern noreturn void exception_invalid(void);
+
+struct nvic;
+
+#define SCB_VTOR ((FWK_RW uint32_t *)(0xE000ED08UL))
+#define SCS_NVIC ((struct nvic *)(0xE000E100UL))
+
+enum exception_num {
+ EXCEPTION_NUM_INVALID = 0U,
+ EXCEPTION_NUM_RESET = 1U,
+ EXCEPTION_NUM_NMI = 2U,
+ EXCEPTION_NUM_HARDFAULT = 3U,
+ EXCEPTION_NUM_SVCALL = 11U,
+ EXCEPTION_NUM_PENDSV = 14U,
+ EXCEPTION_NUM_SYSTICK = 15U,
+ EXCEPTION_NUM_COUNT,
+};
+
+struct nvic {
+ FWK_RW uint32_t ISER; /* Interrupt Set Enabled Register */
+ FWK_RW uint32_t ICER; /* Interrupt Clear Enabled Register */
+ FWK_RW uint32_t ISPR; /* Interrupt Set Pending Register */
+ FWK_RW uint32_t ICPR; /* Interrupt Clear Pending Register */
+ FWK_W uint32_t IPR; /* Interrupt Priority Register */
+};
+
+static uint32_t isr_count;
+static uint32_t irq_count;
+
+/*
+ * For interrupts with parameters, their entry in the vector table points to a
+ * global handler that calls a registered function in the callback table with a
+ * corresponding parameter. Entries in the vector table for interrupts without
+ * parameters point directly to the handler functions.
+ */
+struct callback {
+ void (*func)(uintptr_t param);
+ uintptr_t param;
+};
+
+static void (**vector)(void);
+static struct callback *callback;
+
+static void irq_global(void)
+{
+ struct callback *entry = &callback[__get_IPSR()];
+ entry->func(entry->param);
+}
+
+static int global_enable(void)
+{
+ __enable_irq();
+
+ return FWK_SUCCESS;
+}
+
+static int global_disable(void)
+{
+ __disable_irq();
+
+ return FWK_SUCCESS;
+}
+
+static int is_enabled(unsigned int interrupt, bool *enabled)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ *enabled = SCS_NVIC->ISER & (UINT32_C(1) << (interrupt & 0x1F));
+
+ return FWK_SUCCESS;
+}
+
+static int enable(unsigned int interrupt)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ SCS_NVIC->ISER = UINT32_C(1) << (interrupt & 0x1F);
+
+ return FWK_SUCCESS;
+}
+
+static int disable(unsigned int interrupt)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ SCS_NVIC->ICER = UINT32_C(1) << (interrupt & 0x1F);
+
+ return FWK_SUCCESS;
+}
+
+static int is_pending(unsigned int interrupt, bool *pending)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ *pending = SCS_NVIC->ISPR & (UINT32_C(1) << (interrupt & 0x1F));
+
+ return FWK_SUCCESS;
+}
+
+static int set_pending(unsigned int interrupt)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+
+
+ return FWK_SUCCESS;
+}
+
+static int clear_pending(unsigned int interrupt)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ SCS_NVIC->ICPR = UINT32_C(1) << (interrupt & 0x1F);
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_irq(unsigned int interrupt, void (*isr)(void))
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ vector[EXCEPTION_NUM_COUNT + interrupt] = isr;
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_irq_param(unsigned int interrupt,
+ void (*isr)(uintptr_t param),
+ uintptr_t parameter)
+{
+ struct callback *entry;
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ vector[EXCEPTION_NUM_COUNT + interrupt] = irq_global;
+
+ entry = &callback[EXCEPTION_NUM_COUNT + interrupt];
+ entry->func = isr;
+ entry->param = parameter;
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_nmi(void (*isr)(void))
+{
+ vector[EXCEPTION_NUM_NMI] = isr;
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_nmi_param(void (*isr)(uintptr_t param), uintptr_t parameter)
+{
+ struct callback *entry;
+
+ vector[EXCEPTION_NUM_NMI] = irq_global;
+
+ entry = &callback[EXCEPTION_NUM_NMI];
+ entry->func = isr;
+ entry->param = parameter;
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_fault(void (*isr)(void))
+{
+ vector[EXCEPTION_NUM_HARDFAULT] = isr;
+
+ return FWK_SUCCESS;
+}
+
+static int get_current(unsigned int *interrupt)
+{
+ *interrupt = __get_IPSR();
+
+ /* Not an interrupt */
+ if (*interrupt == 0)
+ return FWK_E_STATE;
+
+ if (*interrupt == EXCEPTION_NUM_NMI)
+ *interrupt = FWK_INTERRUPT_NMI;
+ else if ((*interrupt) < EXCEPTION_NUM_COUNT)
+ *interrupt = FWK_INTERRUPT_EXCEPTION;
+ else
+ *interrupt -= EXCEPTION_NUM_COUNT;
+
+ return FWK_SUCCESS;
+}
+
+static const struct fwk_arch_interrupt_driver arm_nvic_driver = {
+ .global_enable = global_enable,
+ .global_disable = global_disable,
+ .is_enabled = is_enabled,
+ .enable = enable,
+ .disable = disable,
+ .is_pending = is_pending,
+ .set_pending = set_pending,
+ .clear_pending = clear_pending,
+ .set_isr_irq = set_isr_irq,
+ .set_isr_irq_param = set_isr_irq_param,
+ .set_isr_nmi = set_isr_nmi,
+ .set_isr_nmi_param = set_isr_nmi_param,
+ .set_isr_fault = set_isr_fault,
+ .get_current = get_current,
+};
+
+static void irq_invalid(void)
+{
+ static unsigned int spurious = 0;
+
+ spurious++;
+
+ disable(__get_IPSR());
+}
+
+int arm_nvic_init(const struct fwk_arch_interrupt_driver **driver)
+{
+ uint32_t align_entries;
+ uint32_t align_word;
+ unsigned int i;
+
+ if (driver == NULL)
+ return FWK_E_PARAM;
+
+ /* Find the number of interrupt lines implemented in hardware */
+ irq_count = 32;
+ isr_count = irq_count + EXCEPTION_NUM_COUNT;
+
+ /*
+ * Allocate and initialize a table for the callback functions and their
+ * corresponding parameters.
+ */
+ callback = fwk_mm_calloc(isr_count, sizeof(callback[0]));
+ if (callback == NULL)
+ return FWK_E_NOMEM;
+ /*
+ * The base address for the vector table must align on the number of
+ * entries in the table, corresponding to a word boundary rounded up to the
+ * next power of two.
+ *
+ * For example, for a vector table with 48 entries, the base address must be
+ * on a 64-word boundary.
+ */
+
+ /* Calculate the next power of two */
+ align_entries = UINT32_C(1) << (32 - __CLZ(isr_count - 1));
+
+ /* Calculate alignment on a word boundary */
+ align_word = align_entries * sizeof(vector[0]);
+
+ vector = fwk_mm_alloc_aligned(isr_count, sizeof(vector[0]), align_word);
+
+ if (vector == NULL)
+ return FWK_E_NOMEM;
+
+ /*
+ * Initialize all exception entries to point to the 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;
+
+ /* Initialize IRQs */
+ for (i = 0; i < irq_count; i++) {
+ /* Initialize all IRQ entries to point to the irq_invalid() handler */
+ vector[EXCEPTION_NUM_COUNT + i] = irq_invalid;
+
+ /* Ensure IRQs are disabled during boot sequence */
+ disable(i);
+ clear_pending(i);
+ }
+
+#ifdef BUILD_HAS_MULTITHREADING
+ /* Set exception entries that are implemented and handled by RTX */
+ vector[EXCEPTION_NUM_SVCALL] = SVC_Handler;
+ vector[EXCEPTION_NUM_PENDSV] = PendSV_Handler;
+ vector[EXCEPTION_NUM_SYSTICK] = SysTick_Handler;
+#endif
+
+ __DMB();
+
+ /* Switch to the new vector table */
+ *SCB_VTOR = (uint32_t)vector;
+ __DMB();
+
+ *driver = &arm_nvic_driver;
+
+ return FWK_SUCCESS;
+}
diff --git a/arch/src/armv6-m/armv6-crt0.S b/arch/src/armv6-m/armv6-crt0.S
new file mode 100644
index 0000000..26632ad
--- /dev/null
+++ b/arch/src/armv6-m/armv6-crt0.S
@@ -0,0 +1,56 @@
+ /*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * startup file.
+ */
+
+ .syntax unified
+
+ .text
+
+ .global start
+ .thumb_func
+ .func start
+start:
+
+/* Load .data, which is 4-byte aligned */
+ ldr r1, =__DATA_SIZE__
+ cmp r1, #0
+ beq 6f
+ ldr r4, =4
+ ldr r0, =__DATA_LMA_START__
+ ldr r2, =__DATA_START__
+ cmp r0, r2
+ beq 6f
+5:
+ ldr r3, [r0]
+ add r0, r0, r4
+ str r3, [r2]
+ add r2, r2, r4
+ subs r1, r4
+ bne 5b
+6:
+ /* Clear .bss, which is also 4-byte aligned */
+ ldr r1, =__BSS_SIZE__
+ cmp r1, #0
+ beq 8f
+ ldr r0, =__BSS_START__
+ ldr r2, =0
+7:
+ str r2, [r0]
+ add r0, r4
+ subs r1, r4
+ bne 7b
+
+8:
+ dsb
+ bl arm_main
+
+9:
+ wfi
+ b 9b
+ .pool
+ .endfunc
diff --git a/arch/src/armv6-m/exception.S b/arch/src/armv6-m/exception.S
new file mode 100644
index 0000000..9cdd907
--- /dev/null
+++ b/arch/src/armv6-m/exception.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * exceptions.
+ */
+
+
+ .syntax unified
+
+ .section .exception
+
+ .global exceptions
+exceptions:
+ .word __STACK_END__
+ .word exception_reset /* Reset */
+ .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 */
+
+ .section .text
+
+ .global exception_invalid
+ .thumb_func
+ .func exception_invalid
+exception_invalid:
+ wfi
+ b exception_invalid
+ .endfunc
diff --git a/arch/src/armv6-m/ld.S b/arch/src/armv6-m/ld.S
new file mode 100644
index 0000000..98c03e7
--- /dev/null
+++ b/arch/src/armv6-m/ld.S
@@ -0,0 +1,191 @@
+ /*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * scatter file.
+ */
+
+ /*
+ * There are three supported memory layouts for the ARMv6-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 <fmw_memory.ld.S>
+
+#define STACK_ALIGNMENT 8
+
+/*
+ * Input validation
+ */
+
+#ifndef FIRMWARE_MEM_MODE
+ #error "FIRMWARE_MEM_MODE has not been configured"
+#endif
+
+#ifndef FIRMWARE_STACK_SIZE
+ #error "FIRMWARE_STACK_SIZE has not been configured"
+#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
+
+#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
+
+/*
+ * Calculate stack region in the data memory.
+ */
+
+#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION
+ ASSERT(FIRMWARE_STACK_SIZE < FIRMWARE_MEM0_SIZE,
+ "FIRMWARE_STACK_SIZE does not fit in MEM0")
+ #define UNALIGNED_STACK_BASE \
+ (FIRMWARE_MEM0_BASE + FIRMWARE_MEM0_SIZE - FIRMWARE_STACK_SIZE)
+#else
+ ASSERT(FIRMWARE_STACK_SIZE < FIRMWARE_MEM1_SIZE,
+ "FIRMWARE_STACK_SIZE does not fit in MEM1")
+ #define UNALIGNED_STACK_BASE \
+ (FIRMWARE_MEM1_BASE + FIRMWARE_MEM1_SIZE - FIRMWARE_STACK_SIZE)
+#endif
+
+#define STACK_BASE \
+ ( \
+ ((UNALIGNED_STACK_BASE + STACK_ALIGNMENT - 1) / STACK_ALIGNMENT) \
+ * STACK_ALIGNMENT \
+ )
+
+#define STACK_SIZE \
+ (( \
+ ((STACK_BASE + FIRMWARE_STACK_SIZE) / STACK_ALIGNMENT) \
+ * STACK_ALIGNMENT \
+ ) - STACK_BASE)
+
+ASSERT(STACK_SIZE > 0, "FIRMWARE_STACK_SIZE is too small")
+
+ENTRY(exception_reset)
+
+MEMORY {
+#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION
+ /* Only one memory region with read, execute and write attributes */
+ mem0 (rxw): ORIGIN = FIRMWARE_MEM0_BASE, LENGTH = FIRMWARE_MEM0_SIZE - \
+ FIRMWARE_STACK_SIZE
+#else
+ mem0 (rx): ORIGIN = FIRMWARE_MEM0_BASE, LENGTH = FIRMWARE_MEM0_SIZE
+ mem1 (rxw): ORIGIN = FIRMWARE_MEM1_BASE, LENGTH = FIRMWARE_MEM1_SIZE - \
+ FIRMWARE_STACK_SIZE
+#endif
+
+ stack (rw): ORIGIN = STACK_BASE, LENGTH = STACK_SIZE
+}
+
+SECTIONS {
+ .text : {
+ KEEP(*(.exception))
+ *(.text*)
+ *(.rodata*)
+ } > mem0
+
+ .data : {
+ . = ALIGN(4);
+ *(.data*)
+ . = ALIGN(4);
+#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION
+ } > mem0 /* .data follows .text in mem0 */
+#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION
+ } > mem1 /* .data is the first section in mem1 */
+#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_RELOCATION
+ } > mem1 AT>mem0 /* Run-time image is at mem1, but loaded from mem0 */
+#else
+ ASSERT(0, "Unrecognized FIRMWARE_MEM_MODE")
+#endif
+
+ .bss : {
+ . = ALIGN(4);
+ *(.bss*)
+ . = ALIGN(4);
+#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION
+ } > mem0 /* Run-time image is at mem1, but loaded from mem0 */
+#else
+ } > mem1 /* .bss follows .data in mem1 */
+#endif
+
+ .stack : {
+ . = . + STACK_SIZE;
+ } > stack
+
+ __TEXT_START__ = LOADADDR(.text);
+ __TEXT_SIZE__ = SIZEOF(.text);
+ __TEXT_END__ = __TEXT_START__ + __TEXT_SIZE__;
+
+ __STACK_START__ = LOADADDR(.stack);
+ __STACK_SIZE__ = SIZEOF(.stack);
+ __STACK_END__ = __STACK_START__ + __STACK_SIZE__;
+
+ __DATA_LMA_START__ = LOADADDR(.data);
+ __DATA_START__ = ADDR(.data);
+ __DATA_SIZE__ = SIZEOF(.data);
+
+ __BSS_START__ = ADDR(.bss);
+ __BSS_SIZE__ = SIZEOF(.bss);
+ __BSS_END__ = __BSS_START__ + __BSS_SIZE__;
+
+ __HEAP_START__ = __BSS_START__ + __BSS_SIZE__;
+ __HEAP_END__ = __STACK_START__;
+ __HEAP_SIZE__ = __HEAP_END__ - __HEAP_START__;
+}
diff --git a/arch/src/armv6-m/reset-v6.S b/arch/src/armv6-m/reset-v6.S
new file mode 100644
index 0000000..4425081
--- /dev/null
+++ b/arch/src/armv6-m/reset-v6.S
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * reset vector.
+ */
+
+ .syntax unified
+
+ .text
+
+ .global exception_reset
+ .thumb_func
+ .func exception_reset
+exception_reset:
+ bl start
+ .pool
+ .endfunc
diff --git a/arch/src/armv7-m/arm_nvic.c b/arch/src/armv7-m/arm_nvic.c
new file mode 100644
index 0000000..c113ba4
--- /dev/null
+++ b/arch/src/armv7-m/arm_nvic.c
@@ -0,0 +1,352 @@
+ /*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * Interrupt management.
+ */
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdnoreturn.h>
+#include <fwk_arch.h>
+#include <fwk_errno.h>
+#include <fwk_interrupt.h>
+#include <fwk_macros.h>
+#include <fwk_mm.h>
+#include <cmsis_compiler.h>
+
+#ifdef BUILD_HAS_MULTITHREADING
+ #include <rtx_os.h>
+#endif
+
+extern noreturn void exception_invalid(void);
+
+struct nvic;
+
+#define SCB_SHCSR ((FWK_RW uint32_t *)(0xE000ED24UL))
+#define SCB_VTOR ((FWK_RW uint32_t *)(0xE000ED08UL))
+#define SCS_ICTR ((FWK_R uint32_t *)(0xE000E004UL))
+#define SCS_STIR ((FWK_W uint32_t *)(0xE000EF00UL))
+#define SCS_NVIC ((struct nvic *)(0xE000E100UL))
+
+#define SCB_SHCSR_MEMFAULTENA_MASK (1 << 16)
+#define SCB_SHCSR_BUSFAULTENA_MASK (1 << 17)
+#define SCB_SHCSR_USGFAULTENA_MASK (1 << 18)
+
+enum exception_num {
+ EXCEPTION_NUM_INVALID = 0U,
+ EXCEPTION_NUM_RESET = 1U,
+ EXCEPTION_NUM_NMI = 2U,
+ EXCEPTION_NUM_HARDFAULT = 3U,
+ EXCEPTION_NUM_MEMMANAGE = 4U,
+ EXCEPTION_NUM_BUSFAULT = 5U,
+ EXCEPTION_NUM_USAGEFAULT = 6U,
+ EXCEPTION_NUM_SVCALL = 11U,
+ EXCEPTION_NUM_DEBUGMONITOR = 12U,
+ EXCEPTION_NUM_PENDSV = 14U,
+ EXCEPTION_NUM_SYSTICK = 15U,
+ EXCEPTION_NUM_COUNT,
+};
+
+struct nvic {
+ FWK_RW uint32_t ISER[16]; /* Interrupt Set Enabled Register */
+ uint32_t RESERVED0[16];
+ FWK_RW uint32_t ICER[16]; /* Interrupt Clear Enabled Register */
+ uint32_t RESERVED1[16];
+ FWK_RW uint32_t ISPR[16]; /* Interrupt Set Pending Register */
+ uint32_t RESERVED2[16];
+ FWK_RW uint32_t ICPR[16]; /* Interrupt Clear Pending Register */
+ uint32_t RESERVED3[16];
+ FWK_R uint32_t IABR[16]; /* Interrupt Active Bit Register */
+ uint32_t RESERVED4[48];
+ FWK_W uint32_t IPR[16]; /* Interrupt Priority Register */
+ uint32_t RESERVED5[48];
+};
+
+static uint32_t isr_count;
+static uint32_t irq_count;
+
+/*
+ * For interrupts with parameters, their entry in the vector table points to a
+ * global handler that calls a registered function in the callback table with a
+ * corresponding parameter. Entries in the vector table for interrupts without
+ * parameters point directly to the handler functions.
+ */
+struct callback {
+ void (*func)(uintptr_t param);
+ uintptr_t param;
+};
+
+static void (**vector)(void);
+static struct callback *callback;
+
+static void irq_global(void)
+{
+ struct callback *entry = &callback[__get_IPSR()];
+ entry->func(entry->param);
+}
+
+static int global_enable(void)
+{
+ __enable_irq();
+
+ return FWK_SUCCESS;
+}
+
+static int global_disable(void)
+{
+ __disable_irq();
+
+ return FWK_SUCCESS;
+}
+
+static int is_enabled(unsigned int interrupt, bool *enabled)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ *enabled = SCS_NVIC->ISER[interrupt / 32] &
+ (UINT32_C(1) << (interrupt & 0x1F));
+
+ return FWK_SUCCESS;
+}
+
+static int enable(unsigned int interrupt)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ SCS_NVIC->ISER[interrupt / 32] = UINT32_C(1) << (interrupt & 0x1F);
+
+ return FWK_SUCCESS;
+}
+
+static int disable(unsigned int interrupt)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ SCS_NVIC->ICER[interrupt / 32] = UINT32_C(1) << (interrupt & 0x1F);
+
+ return FWK_SUCCESS;
+}
+
+static int is_pending(unsigned int interrupt, bool *pending)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ *pending = SCS_NVIC->ISPR[interrupt / 32] &
+ (UINT32_C(1) << (interrupt & 0x1F));
+
+ return FWK_SUCCESS;
+}
+
+static int set_pending(unsigned int interrupt)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ *SCS_STIR = interrupt;
+
+ return FWK_SUCCESS;
+}
+
+static int clear_pending(unsigned int interrupt)
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ SCS_NVIC->ICPR[interrupt / 32] = UINT32_C(1) << (interrupt & 0x1F);
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_irq(unsigned int interrupt, void (*isr)(void))
+{
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ vector[EXCEPTION_NUM_COUNT + interrupt] = isr;
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_irq_param(unsigned int interrupt,
+ void (*isr)(uintptr_t param),
+ uintptr_t parameter)
+{
+ struct callback *entry;
+ if (interrupt >= irq_count)
+ return FWK_E_PARAM;
+
+ vector[EXCEPTION_NUM_COUNT + interrupt] = irq_global;
+
+ entry = &callback[EXCEPTION_NUM_COUNT + interrupt];
+ entry->func = isr;
+ entry->param = parameter;
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_nmi(void (*isr)(void))
+{
+ vector[EXCEPTION_NUM_NMI] = isr;
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_nmi_param(void (*isr)(uintptr_t param), uintptr_t parameter)
+{
+ struct callback *entry;
+
+ vector[EXCEPTION_NUM_NMI] = irq_global;
+
+ entry = &callback[EXCEPTION_NUM_NMI];
+ entry->func = isr;
+ entry->param = parameter;
+
+ return FWK_SUCCESS;
+}
+
+static int set_isr_fault(void (*isr)(void))
+{
+ vector[EXCEPTION_NUM_HARDFAULT] = isr;
+ vector[EXCEPTION_NUM_MEMMANAGE] = isr;
+ vector[EXCEPTION_NUM_BUSFAULT] = isr;
+ vector[EXCEPTION_NUM_USAGEFAULT] = isr;
+
+ return FWK_SUCCESS;
+}
+
+static int get_current(unsigned int *interrupt)
+{
+ *interrupt = __get_IPSR();
+
+ /* Not an interrupt */
+ if (*interrupt == 0)
+ return FWK_E_STATE;
+
+ if (*interrupt == EXCEPTION_NUM_NMI)
+ *interrupt = FWK_INTERRUPT_NMI;
+ else if ((*interrupt) < EXCEPTION_NUM_COUNT)
+ *interrupt = FWK_INTERRUPT_EXCEPTION;
+ else
+ *interrupt -= EXCEPTION_NUM_COUNT;
+
+ return FWK_SUCCESS;
+}
+
+static const struct fwk_arch_interrupt_driver arm_nvic_driver = {
+ .global_enable = global_enable,
+ .global_disable = global_disable,
+ .is_enabled = is_enabled,
+ .enable = enable,
+ .disable = disable,
+ .is_pending = is_pending,
+ .set_pending = set_pending,
+ .clear_pending = clear_pending,
+ .set_isr_irq = set_isr_irq,
+ .set_isr_irq_param = set_isr_irq_param,
+ .set_isr_nmi = set_isr_nmi,
+ .set_isr_nmi_param = set_isr_nmi_param,
+ .set_isr_fault = set_isr_fault,
+ .get_current = get_current,
+};
+
+static void irq_invalid(void)
+{
+ static unsigned int spurious = 0;
+
+ spurious++;
+
+ disable(__get_IPSR());
+}
+
+int arm_nvic_init(const struct fwk_arch_interrupt_driver **driver)
+{
+ uint32_t ictr_intlinesnum;
+ uint32_t align_entries;
+ uint32_t align_word;
+ unsigned int i;
+
+ if (driver == NULL)
+ return FWK_E_PARAM;
+
+ /* Find the number of interrupt lines implemented in hardware */
+ ictr_intlinesnum = *SCS_ICTR & 0x0000000F;
+ irq_count = (ictr_intlinesnum + 1) * 32;
+ isr_count = irq_count + EXCEPTION_NUM_COUNT;
+
+ /*
+ * Allocate and initialize a table for the callback functions and their
+ * corresponding parameters.
+ */
+ callback = fwk_mm_calloc(isr_count, sizeof(callback[0]));
+ if (callback == NULL)
+ return FWK_E_NOMEM;
+ /*
+ * The base address for the vector table must align on the number of
+ * entries in the table, corresponding to a word boundary rounded up to the
+ * next power of two.
+ *
+ * For example, for a vector table with 48 entries, the base address must be
+ * on a 64-word boundary.
+ */
+
+ /* Calculate the next power of two */
+ align_entries = UINT32_C(1) << (32 - __CLZ(isr_count - 1));
+
+ /* Calculate alignment on a word boundary */
+ align_word = align_entries * sizeof(vector[0]);
+
+ vector = fwk_mm_alloc_aligned(isr_count, sizeof(vector[0]), align_word);
+
+ if (vector == NULL)
+ return FWK_E_NOMEM;
+
+ /*
+ * Initialize all exception entries to point to the 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;
+
+ /* Initialize IRQs */
+ for (i = 0; i < irq_count; i++) {
+ /* Initialize all IRQ entries to point to the irq_invalid() handler */
+ vector[EXCEPTION_NUM_COUNT + i] = irq_invalid;
+
+ /* Ensure IRQs are disabled during boot sequence */
+ disable(i);
+ clear_pending(i);
+ }
+
+#ifdef BUILD_HAS_MULTITHREADING
+ /* Set exception entries that are implemented and handled by RTX */
+ vector[EXCEPTION_NUM_SVCALL] = SVC_Handler;
+ vector[EXCEPTION_NUM_PENDSV] = PendSV_Handler;
+ vector[EXCEPTION_NUM_SYSTICK] = SysTick_Handler;
+#endif
+
+ __DMB();
+
+ /* Switch to the new vector table */
+ *SCB_VTOR = (uint32_t)vector;
+ __DMB();
+
+ /* Enable the Usage, Bus and Memory faults which are disabled by default */
+ *SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA_MASK |
+ SCB_SHCSR_BUSFAULTENA_MASK |
+ SCB_SHCSR_USGFAULTENA_MASK;
+
+ *driver = &arm_nvic_driver;
+
+ return FWK_SUCCESS;
+}
diff --git a/arch/src/armv7-m/armv7-crt0.S b/arch/src/armv7-m/armv7-crt0.S
new file mode 100644
index 0000000..f01ef1a
--- /dev/null
+++ b/arch/src/armv7-m/armv7-crt0.S
@@ -0,0 +1,53 @@
+ /*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * startup file.
+ */
+
+
+ .syntax unified
+
+ .text
+
+ .global start
+ .thumb_func
+ .func start
+start:
+ /* Load .data, which is 4-byte aligned */
+ ldr r1, =__DATA_SIZE__
+ cmp r1, #0
+ beq 6f
+ ldr r0, =__DATA_LMA_START__
+ ldr r2, =__DATA_START__
+ cmp r0, r2
+ beq 6f
+5:
+ ldr r3, [r0], #4
+ str r3, [r2], #4
+ subs r1, #4
+ bne 5b
+
+6:
+ /* Clear .bss, which is also 4-byte aligned */
+ ldr r1, =__BSS_SIZE__
+ cmp r1, #0
+ beq 8f
+ ldr r0, =__BSS_START__
+ mov r2, #0
+7:
+ str r2, [r0], #4
+ subs r1, #4
+ bne 7b
+
+8:
+ dsb
+ bl arm_main
+
+9:
+ wfi
+ b 9b
+ .pool
+ .endfunc
diff --git a/arch/src/armv7-m/exception.S b/arch/src/armv7-m/exception.S
new file mode 100644
index 0000000..1f943f2
--- /dev/null
+++ b/arch/src/armv7-m/exception.S
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * exceptions.
+ */
+
+ .syntax unified
+
+ .section .exception
+
+ .global exceptions
+exceptions:
+ .word __STACK_END__
+ .word exception_reset /* Reset */
+ .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 */
+
+ .section .text
+
+ .global exception_invalid
+ .thumb_func
+ .func exception_invalid
+exception_invalid:
+ wfi
+ b exception_invalid
+ .endfunc
diff --git a/arch/src/armv7-m/ld.S b/arch/src/armv7-m/ld.S
new file mode 100644
index 0000000..068fcca
--- /dev/null
+++ b/arch/src/armv7-m/ld.S
@@ -0,0 +1,191 @@
+ /*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * 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 <fmw_memory.ld.S>
+
+#define STACK_ALIGNMENT 8
+
+/*
+ * Input validation
+ */
+
+#ifndef FIRMWARE_MEM_MODE
+ #error "FIRMWARE_MEM_MODE has not been configured"
+#endif
+
+#ifndef FIRMWARE_STACK_SIZE
+ #error "FIRMWARE_STACK_SIZE has not been configured"
+#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
+
+#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
+
+/*
+ * Calculate stack region in the data memory.
+ */
+
+#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION
+ ASSERT(FIRMWARE_STACK_SIZE < FIRMWARE_MEM0_SIZE,
+ "FIRMWARE_STACK_SIZE does not fit in MEM0")
+ #define UNALIGNED_STACK_BASE \
+ (FIRMWARE_MEM0_BASE + FIRMWARE_MEM0_SIZE - FIRMWARE_STACK_SIZE)
+#else
+ ASSERT(FIRMWARE_STACK_SIZE < FIRMWARE_MEM1_SIZE,
+ "FIRMWARE_STACK_SIZE does not fit in MEM1")
+ #define UNALIGNED_STACK_BASE \
+ (FIRMWARE_MEM1_BASE + FIRMWARE_MEM1_SIZE - FIRMWARE_STACK_SIZE)
+#endif
+
+#define STACK_BASE \
+ ( \
+ ((UNALIGNED_STACK_BASE + STACK_ALIGNMENT - 1) / STACK_ALIGNMENT) \
+ * STACK_ALIGNMENT \
+ )
+
+#define STACK_SIZE \
+ (( \
+ ((STACK_BASE + FIRMWARE_STACK_SIZE) / STACK_ALIGNMENT) \
+ * STACK_ALIGNMENT \
+ ) - STACK_BASE)
+
+ASSERT(STACK_SIZE > 0, "FIRMWARE_STACK_SIZE is too small")
+
+ENTRY(exception_reset)
+
+MEMORY {
+#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION
+ /* Only one memory region with read, execute and write attributes */
+ mem0 (rxw): ORIGIN = FIRMWARE_MEM0_BASE, LENGTH = FIRMWARE_MEM0_SIZE - \
+ FIRMWARE_STACK_SIZE
+#else
+ mem0 (rx): ORIGIN = FIRMWARE_MEM0_BASE, LENGTH = FIRMWARE_MEM0_SIZE
+ mem1 (rxw): ORIGIN = FIRMWARE_MEM1_BASE, LENGTH = FIRMWARE_MEM1_SIZE - \
+ FIRMWARE_STACK_SIZE
+#endif
+
+ stack (rw): ORIGIN = STACK_BASE, LENGTH = STACK_SIZE
+}
+
+SECTIONS {
+ .text : {
+ KEEP(*(.exception))
+ *(.text*)
+ *(.rodata*)
+ } > mem0
+
+ .data : {
+ . = ALIGN(4);
+ *(.data*)
+ . = ALIGN(4);
+#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION
+ } > mem0 /* .data follows .text in mem0 */
+#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_NO_RELOCATION
+ } > mem1 /* .data is the first section in mem1 */
+#elif FIRMWARE_MEM_MODE == FWK_MEM_MODE_DUAL_REGION_RELOCATION
+ } > mem1 AT>mem0 /* Run-time image is at mem1, but loaded from mem0 */
+#else
+ ASSERT(0, "Unrecognized FIRMWARE_MEM_MODE")
+#endif
+
+ .bss : {
+ . = ALIGN(4);
+ *(.bss*)
+ . = ALIGN(4);
+#if FIRMWARE_MEM_MODE == FWK_MEM_MODE_SINGLE_REGION
+ } > mem0 /* Run-time image is at mem1, but loaded from mem0 */
+#else
+ } > mem1 /* .bss follows .data in mem1 */
+#endif
+
+ .stack : {
+ . = . + STACK_SIZE;
+ } > stack
+
+ __TEXT_START__ = LOADADDR(.text);
+ __TEXT_SIZE__ = SIZEOF(.text);
+ __TEXT_END__ = __TEXT_START__ + __TEXT_SIZE__;
+
+ __STACK_START__ = LOADADDR(.stack);
+ __STACK_SIZE__ = SIZEOF(.stack);
+ __STACK_END__ = __STACK_START__ + __STACK_SIZE__;
+
+ __DATA_LMA_START__ = LOADADDR(.data);
+ __DATA_START__ = ADDR(.data);
+ __DATA_SIZE__ = SIZEOF(.data);
+
+ __BSS_START__ = ADDR(.bss);
+ __BSS_SIZE__ = SIZEOF(.bss);
+ __BSS_END__ = __BSS_START__ + __BSS_SIZE__;
+
+ __HEAP_START__ = __BSS_START__ + __BSS_SIZE__;
+ __HEAP_END__ = __STACK_START__;
+ __HEAP_SIZE__ = __HEAP_END__ - __HEAP_START__;
+}
diff --git a/arch/src/armv7-m/reset-v7.S b/arch/src/armv7-m/reset-v7.S
new file mode 100644
index 0000000..4ba1898
--- /dev/null
+++ b/arch/src/armv7-m/reset-v7.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * reset vector.
+ */
+
+ .syntax unified
+
+ .text
+
+ .global exception_reset
+ .thumb_func
+ .func exception_reset
+exception_reset:
+ /*
+ * 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 */
+
+ bl start
+ .pool
+ .endfunc
diff --git a/arch/src/section.h b/arch/src/section.h
new file mode 100644
index 0000000..96447dd
--- /dev/null
+++ b/arch/src/section.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Description:
+ * Section symbols.
+ */
+
+#ifndef ARCH_SECTION_H
+#define ARCH_SECTION_H
+
+#include <stddef.h>
+
+extern unsigned int __TEXT_START__;
+extern unsigned int __TEXT_SIZE__;
+extern unsigned int __TEXT_END__;
+
+extern unsigned int __DATA_START__;
+extern unsigned int __DATA_SIZE__;
+extern unsigned int __DATA_END__;
+
+extern unsigned int __BSS_START__;
+extern unsigned int __BSS_SIZE__;
+extern unsigned int __BSS_END__;
+
+extern unsigned int __STACK_START__;
+extern unsigned int __STACK_SIZE__;
+extern unsigned int __STACK_END__;
+
+/* Beginning of the .text section */
+#define ARCH_SECTION_TEXT_START ((uintptr_t)(&__TEXT_START__))
+
+/* End of the .text section */
+#define ARCH_SECTION_TEXT_END ((uintptr_t)(&__TEXT_END__))
+
+/* Size of the .text section */
+#define ARCH_SECTION_TEXT_SIZE ((size_t)(&__TEXT_SIZE__))
+
+/* Start of the .data section */
+#define ARCH_SECTION_DATA_START ((uintptr_t)(&__DATA_START__))
+
+/* End of the .data section */
+#define ARCH_SECTION_DATA_END ((uintptr_t)(&__DATA_END__))
+
+/* Size of the .data section */
+#define ARCH_SECTION_DATA_SIZE ((size_t)(&__DATA_SIZE__))
+
+/* Start of the .bss section */
+#define ARCH_SECTION_BSS_START ((uintptr_t)(&__BSS_START__))
+
+/* End of the .bss section */
+#define ARCH_SECTION_BSS_END ((uintptr_t)(&__BSS_END__))
+
+/* Size of the .bss section */
+#define ARCH_SECTION_BSS_SIZE ((size_t)(&__BSS_SIZE__))
+
+/* Start of the .heap section */
+#define ARCH_SECTION_HEAP_START ARCH_SECTION_BSS_END
+
+/* End of the .heap section */
+#define ARCH_SECTION_HEAP_END ARCH_SECTION_STACK_START
+
+/* Size of the .heap section */
+#define ARCH_SECTION_HEAP_SIZE ((size_t)(ARCH_SECTION_HEAP_END - \
+ ARCH_SECTION_HEAP_START))
+
+/* Start of the .stack section */
+#define ARCH_SECTION_STACK_START ((uintptr_t)(&__STACK_START__))
+
+/* End of the .stack section */
+#define ARCH_SECTION_STACK_END ((uintptr_t)(&__STACK_END__))
+
+/* Size of the .stack section */
+#define ARCH_SECTION_STACK_SIZE ((size_t)(&__STACK_SIZE__))
+
+#endif /* ARCH_SECTION_H */