Merge pull request #12276 from kenrabold/pr-fe310_intr_cleanup

cpu/fe310: interrupt handling cleanup
This commit is contained in:
benpicco 2019-09-28 19:14:07 +02:00 committed by GitHub
commit 1543a8c438
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 276 additions and 426 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 JP Bonn
* Copyright (C) 2017, 2019 JP Bonn, Ken Rabold
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -40,8 +40,6 @@ static void check_context_switch_frame_alignment(void)
"Stack pointer should be 16 byte aligned");
_Static_assert(sizeof(struct context_switch_frame) == CONTEXT_FRAME_SIZE,
"context_switch_frame size mismatch");
CHECK_OFFSET(pad);
CHECK_OFFSET(pc);
CHECK_OFFSET(s0);
CHECK_OFFSET(s1);
CHECK_OFFSET(s2);
@ -55,7 +53,6 @@ static void check_context_switch_frame_alignment(void)
CHECK_OFFSET(s10);
CHECK_OFFSET(s11);
CHECK_OFFSET(ra);
CHECK_OFFSET(tp);
CHECK_OFFSET(t0);
CHECK_OFFSET(t1);
CHECK_OFFSET(t2);
@ -71,6 +68,8 @@ static void check_context_switch_frame_alignment(void)
CHECK_OFFSET(a5);
CHECK_OFFSET(a6);
CHECK_OFFSET(a7);
CHECK_OFFSET(pc);
CHECK_OFFSET(pad);
/*
* also check the SP offset in the _frame structure

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 Ken Rabold, JP Bonn
* Copyright (C) 2017, 2019 Ken Rabold, JP Bonn
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -18,6 +18,7 @@
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "thread.h"
@ -39,8 +40,8 @@
volatile int __in_isr = 0;
/* ISR trap vector */
void trap_entry(void);
void thread_start(void);
/* PLIC external ISR function list */
static external_isr_ptr_t _ext_isrs[PLIC_NUM_INTERRUPTS];
@ -160,8 +161,12 @@ void external_isr(void)
/**
* @brief Global trap and interrupt handler
*/
void handle_trap(unsigned int mcause)
void handle_trap(unsigned int mcause, unsigned int mepc, unsigned int mtval)
{
#ifndef DEVELHELP
(void) mepc;
(void) mtval;
#endif
/* Tell RIOT to set sched_context_switch_request instead of
* calling thread_yield(). */
__in_isr = 1;
@ -170,6 +175,12 @@ void handle_trap(unsigned int mcause)
if ((mcause & MCAUSE_INT) == MCAUSE_INT) {
/* Cause is an interrupt - determine type */
switch (mcause & MCAUSE_CAUSE) {
case IRQ_M_SOFT:
/* Handle software interrupt - flag for context switch */
sched_context_switch_request = 1;
CLINT_REG(0) = 0;
break;
#ifdef MODULE_PERIPH_TIMER
case IRQ_M_TIMER:
/* Handle timer interrupt */
@ -188,10 +199,21 @@ void handle_trap(unsigned int mcause)
}
}
else {
#ifdef DEVELHELP
printf("Unhandled trap:\n");
printf(" mcause: 0x%08x\n", mcause);
printf(" mepc: 0x%08x\n", mepc);
printf(" mtval: 0x%08x\n", mtval);
#endif
/* Unknown trap */
core_panic(PANIC_GENERAL_ERROR, "Unhandled trap");
}
/* Check if context change was requested */
if (sched_context_switch_request) {
sched_run();
}
/* ISR done - no more changes to thread states */
__in_isr = 0;
}
@ -253,7 +275,6 @@ char *thread_stack_init(thread_task_func_t task_func,
int stack_size)
{
struct context_switch_frame *sf;
uint32_t *reg;
uint32_t *stk_top;
/* calculate the top of the stack */
@ -275,11 +296,10 @@ char *thread_stack_init(thread_task_func_t task_func,
/* populate the stack frame with default values for starting the thread. */
sf = (struct context_switch_frame *) stk_top;
/* a7 is register with highest memory address in frame */
reg = &sf->a7;
while (reg != &sf->pc) {
*reg-- = 0;
}
/* Clear stack frame */
memset(sf, 0, sizeof(*sf));
/* set initial reg values */
sf->pc = (uint32_t) task_func;
sf->a0 = (uint32_t) arg;
@ -292,7 +312,11 @@ char *thread_stack_init(thread_task_func_t task_func,
void thread_print_stack(void)
{
int count = 0;
uint32_t *sp = (uint32_t *) sched_active_thread->sp;
uint32_t *sp = (uint32_t *) ((sched_active_thread) ? sched_active_thread->sp : NULL);
if (sp == NULL) {
return;
}
printf("printing the current stack of thread %" PRIkernel_pid "\n",
thread_getpid());

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 JP Bonn
* Copyright (C) 2017, 2019 JP Bonn, Ken Rabold
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -40,8 +40,6 @@ extern "C" {
*
*/
struct context_switch_frame {
uint32_t pad[2]; /**< padding to maintain 16 byte alignment */
uint32_t pc; /**< program counter */
/* Callee saved registers */
uint32_t s0; /**< s0 register */
uint32_t s1; /**< s1 register */
@ -57,7 +55,6 @@ struct context_switch_frame {
uint32_t s11; /**< s11 register */
/* Caller saved registers */
uint32_t ra; /**< ra register */
uint32_t tp; /**< tp register */
uint32_t t0; /**< t0 register */
uint32_t t1; /**< t1 register */
uint32_t t2; /**< t2 register */
@ -73,6 +70,9 @@ struct context_switch_frame {
uint32_t a5; /**< a5 register */
uint32_t a6; /**< a6 register */
uint32_t a7; /**< a7 register */
/* Saved PC for return from ISR */
uint32_t pc; /**< program counter */
uint32_t pad[3]; /**< padding to maintain 16 byte alignment */
};
#endif /* __ASSEMBLER__ */
@ -83,43 +83,42 @@ struct context_switch_frame {
* @{
*/
/* These values are checked for correctness in context_frame.c */
#define pad_OFFSET 0
#define pc_OFFSET 8
#define s0_OFFSET 12
#define s1_OFFSET 16
#define s2_OFFSET 20
#define s3_OFFSET 24
#define s4_OFFSET 28
#define s5_OFFSET 32
#define s6_OFFSET 36
#define s7_OFFSET 40
#define s8_OFFSET 44
#define s9_OFFSET 48
#define s10_OFFSET 52
#define s11_OFFSET 56
#define ra_OFFSET 60
#define tp_OFFSET 64
#define t0_OFFSET 68
#define t1_OFFSET 72
#define t2_OFFSET 76
#define t3_OFFSET 80
#define t4_OFFSET 84
#define t5_OFFSET 88
#define t6_OFFSET 92
#define a0_OFFSET 96
#define a1_OFFSET 100
#define a2_OFFSET 104
#define a3_OFFSET 108
#define a4_OFFSET 112
#define a5_OFFSET 116
#define a6_OFFSET 120
#define a7_OFFSET 124
#define s0_OFFSET 0
#define s1_OFFSET 4
#define s2_OFFSET 8
#define s3_OFFSET 12
#define s4_OFFSET 16
#define s5_OFFSET 20
#define s6_OFFSET 24
#define s7_OFFSET 28
#define s8_OFFSET 32
#define s9_OFFSET 36
#define s10_OFFSET 40
#define s11_OFFSET 44
#define ra_OFFSET 48
#define t0_OFFSET 52
#define t1_OFFSET 56
#define t2_OFFSET 60
#define t3_OFFSET 64
#define t4_OFFSET 68
#define t5_OFFSET 72
#define t6_OFFSET 76
#define a0_OFFSET 80
#define a1_OFFSET 84
#define a2_OFFSET 88
#define a3_OFFSET 92
#define a4_OFFSET 96
#define a5_OFFSET 100
#define a6_OFFSET 104
#define a7_OFFSET 108
#define pc_OFFSET 112
#define pad_OFFSET 116
/** @} */
/**
* @brief Size of context switch frame
*/
#define CONTEXT_FRAME_SIZE (a7_OFFSET + 4)
#define CONTEXT_FRAME_SIZE (pad_OFFSET + 12)
/**
* @brief Offset of stack pointer in struct _thread

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 JP Bonn
* Copyright (C) 2017, 2019 JP Bonn, Ken Rabold
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -9,22 +9,12 @@
#include "vendor/encoding.h"
#include "context_frame.h"
/* from platform.h TODO:fix this hard code.... */
CLINT_CTRL_ADDR = 0x02000000
.section .text.entry
.align 2
.global trap_entry
trap_entry:
/*
* Save all regs on the currently active stack.
* This coule be the active thread's stack,
* or if no thread is active, it is saved on ISR stack
* (if initial startup) or on the deactivated threads
* stack (in the case of thread exit). In the latter
* two cases the stack is just abandoned.
*/
/* Save registers to stack */
addi sp, sp, -CONTEXT_FRAME_SIZE
sw s0, s0_OFFSET(sp)
@ -40,7 +30,6 @@ trap_entry:
sw s10, s10_OFFSET(sp)
sw s11, s11_OFFSET(sp)
sw ra, ra_OFFSET(sp)
sw tp, tp_OFFSET(sp)
sw t0, t0_OFFSET(sp)
sw t1, t1_OFFSET(sp)
sw t2, t2_OFFSET(sp)
@ -58,33 +47,40 @@ trap_entry:
sw a7, a7_OFFSET(sp)
/* Get the interrupt cause */
/* Get the interrupt cause, PC, and address */
csrr a0, mcause
csrr a1, mepc
csrr a2, mtval
/* Save active thread stack pointer in a callee save register */
mv s1, sp
/* Save return PC in stack frame */
sw a1, pc_OFFSET(sp)
/* Get the active thread (could be NULL) */
lw tp, sched_active_thread
beqz tp, null_thread
/* Save stack pointer of current thread */
sw sp, SP_OFFSET_IN_THREAD(tp)
null_thread:
/* Switch to ISR stack. Interrupts are not nested so use fixed
* starting address and just abandon stack when finished. */
la sp, _sp
addi sp, sp, -4
/* Is it a software interrupt? */
li t0, 0x80000003
beq a0, t0, context_switch
/* Call handle_trap with MCAUSE and MEPC register value as args */
call handle_trap
/* Call handle_trap with MCAUSE register value as arg */
jal handle_trap
/* Get the active thread (guaranteed to be non NULL) */
lw tp, sched_active_thread
/* See if a context switch was requested by the ISR */
lw a0, sched_context_switch_request
bnez a0, context_switch
/* Load the thread SP of scheduled thread */
lw sp, SP_OFFSET_IN_THREAD(tp)
/* Restore active thread stack pointer */
mv sp, s1
/* Set return PC */
lw a1, pc_OFFSET(sp)
csrw mepc, a1
/* Restore remaining registers */
trap_exit:
/* Restore registers from stack */
lw s0, s0_OFFSET(sp)
lw s1, s1_OFFSET(sp)
lw s2, s2_OFFSET(sp)
@ -98,7 +94,6 @@ trap_exit:
lw s10, s10_OFFSET(sp)
lw s11, s11_OFFSET(sp)
lw ra, ra_OFFSET(sp)
lw tp, tp_OFFSET(sp)
lw t0, t0_OFFSET(sp)
lw t1, t1_OFFSET(sp)
lw t2, t2_OFFSET(sp)
@ -117,35 +112,3 @@ trap_exit:
addi sp, sp, CONTEXT_FRAME_SIZE
mret
context_switch:
/* clear the software interrupt */
li t0, CLINT_CTRL_ADDR
sw zero, (t0)
/* save the active thread's PC prior to interrupt on the stack */
csrr a0, mepc
sw a0, pc_OFFSET(s1)
/* get the active thread - it may be 0 if none currently active */
lw t0, sched_active_thread
/* was there a previously running thread? */
beqz t0, no_sp_save
/* if so, save the thread's SP in the _thread structure */
sw s1,SP_OFFSET_IN_THREAD(t0)
no_sp_save:
/* all current thread state is saved - schedule a new thread */
call sched_run
lw tp, sched_active_thread
/* set the threads SP from the newly scheduled thread
* and abandon ISR stack. */
lw sp, SP_OFFSET_IN_THREAD(tp)
/* restore the PC */
lw a0, pc_OFFSET(sp)
csrw mepc, a0
j trap_exit

View File

@ -0,0 +1,177 @@
/*
* Copyright (C) 2017, 2019 Ken Rabold
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @addtogroup cpu_fe310
* @{
*
* @file
* @brief Common linker directives for the SiFive FE310
*
* @author Ken Rabold
*
* @}
*/
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
PHDRS
{
flash PT_LOAD;
ram_init PT_LOAD;
ram PT_NULL;
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 256;
.init :
{
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash :flash
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >flash AT>flash :flash
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >flash AT>flash :flash
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >flash AT>flash :flash
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >flash AT>flash :flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >flash AT>flash :flash
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >flash AT>flash :flash
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >flash AT>flash :flash
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >flash AT>flash :flash
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >flash AT>flash :flash
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>flash :ram_init
.data :
{
*(.ramfunc .ramfunc.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram AT>flash :ram_init
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram :ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
PROVIDE( _heap_start = . );
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
{
PROVIDE( _heap_end = . );
. = __stack_size;
PROVIDE( _sp = . );
} >ram AT>ram :ram
}

View File

@ -18,10 +18,6 @@
* @}
*/
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
MEMORY
{
flash (rxai!w) : ORIGIN = 0x20400000, LENGTH = 0x1fc00000
@ -29,156 +25,4 @@ MEMORY
itim (wxa!ri) : ORIGIN = 0x08000000, LENGTH = 0x00002000
}
PHDRS
{
flash PT_LOAD;
ram_init PT_LOAD;
ram PT_NULL;
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 1K;
.init :
{
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash :flash
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >flash AT>flash :flash
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >flash AT>flash :flash
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >flash AT>flash :flash
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >flash AT>flash :flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >flash AT>flash :flash
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >flash AT>flash :flash
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >flash AT>flash :flash
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >flash AT>flash :flash
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >flash AT>flash :flash
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>flash :ram_init
.data :
{
*(.ramfunc .ramfunc.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram AT>flash :ram_init
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram :ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
PROVIDE( _heap_start = . );
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
{
PROVIDE( _heap_end = . );
. = __stack_size;
PROVIDE( _sp = . );
} >ram AT>ram :ram
}
INCLUDE fe310_base.ld

View File

@ -18,10 +18,6 @@
* @}
*/
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
MEMORY
{
flash (rxai!w) : ORIGIN = 0x20010000, LENGTH = 0x0006a120
@ -29,156 +25,4 @@ MEMORY
itim (wxa!ri) : ORIGIN = 0x08000000, LENGTH = 0x00002000
}
PHDRS
{
flash PT_LOAD;
ram_init PT_LOAD;
ram PT_NULL;
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 1K;
.init :
{
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash :flash
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >flash AT>flash :flash
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >flash AT>flash :flash
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >flash AT>flash :flash
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >flash AT>flash :flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >flash AT>flash :flash
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >flash AT>flash :flash
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >flash AT>flash :flash
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >flash AT>flash :flash
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >flash AT>flash :flash
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>flash :ram_init
.data :
{
*(.ramfunc .ramfunc.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram AT>flash :ram_init
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram :ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
PROVIDE( _heap_start = . );
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
{
PROVIDE( _heap_end = . );
. = __stack_size;
PROVIDE( _sp = . );
} >ram AT>ram :ram
}
INCLUDE fe310_base.ld