Improve Cortex-A5 context switching so that a little less copying is done
This commit is contained in:
parent
d6ae8db987
commit
3860fc17f0
9
TODO
9
TODO
@ -1,4 +1,4 @@
|
|||||||
NuttX TODO List (Last updated July 23, 2013)
|
NuttX TODO List (Last updated July 24, 2013)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
||||||
@ -1390,8 +1390,11 @@ o ARM (arch/arm/)
|
|||||||
Description: ARM interrupt handling performance could be improved in some
|
Description: ARM interrupt handling performance could be improved in some
|
||||||
ways. One easy way is to use a pointer to the context save
|
ways. One easy way is to use a pointer to the context save
|
||||||
area in current_regs instead of using up_copystate so much.
|
area in current_regs instead of using up_copystate so much.
|
||||||
see handling of 'current_regs" in arch/arm/src/armv7-m/* for
|
|
||||||
examples of how this might be done.
|
This approach is already implemented for the ARM Cortex-M0,
|
||||||
|
Cortex-M3, Cortex-M4, and Cortex-A5 families. But still needs
|
||||||
|
to be back-ported to the ARM7 and ARM9 (which are nearly
|
||||||
|
identical to the Cortex-A5 in this regard).
|
||||||
Status: Open
|
Status: Open
|
||||||
Priority: Low
|
Priority: Low
|
||||||
|
|
||||||
|
@ -113,6 +113,7 @@ config ARCH_CHIP_SAMA5
|
|||||||
bool "Atmel AT91SAMA5"
|
bool "Atmel AT91SAMA5"
|
||||||
select ARCH_CORTEXA5
|
select ARCH_CORTEXA5
|
||||||
select ARCH_HAVE_FPU
|
select ARCH_HAVE_FPU
|
||||||
|
select ARCH_HAVE_LOWVECTORS
|
||||||
---help---
|
---help---
|
||||||
Atmel AT91SAMA5 (ARM Cortex-A5)
|
Atmel AT91SAMA5 (ARM Cortex-A5)
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ static bool g_pgwrap;
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: up_allocpage()
|
* Name: arm_allocpage()
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* This architecture-specific function will set aside page in memory and map
|
* This architecture-specific function will set aside page in memory and map
|
||||||
@ -136,9 +136,9 @@ static bool g_pgwrap;
|
|||||||
* NOTE 2: If an in-use page is un-mapped, it may be necessary to flush the
|
* NOTE 2: If an in-use page is un-mapped, it may be necessary to flush the
|
||||||
* instruction cache in some architectures.
|
* instruction cache in some architectures.
|
||||||
*
|
*
|
||||||
* NOTE 3: Allocating and filling a page is a two step process. up_allocpage()
|
* NOTE 3: Allocating and filling a page is a two step process. arm_allocpage()
|
||||||
* allocates the page, and up_fillpage() fills it with data from some non-
|
* allocates the page, and up_fillpage() fills it with data from some non-
|
||||||
* volatile storage device. This distinction is made because up_allocpage()
|
* volatile storage device. This distinction is made because arm_allocpage()
|
||||||
* can probably be implemented in board-independent logic whereas up_fillpage()
|
* can probably be implemented in board-independent logic whereas up_fillpage()
|
||||||
* probably must be implemented as board-specific logic.
|
* probably must be implemented as board-specific logic.
|
||||||
*
|
*
|
||||||
@ -165,7 +165,7 @@ static bool g_pgwrap;
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
int up_allocpage(FAR struct tcb_s *tcb, FAR void **vpage)
|
int arm_allocpage(FAR struct tcb_s *tcb, FAR void **vpage)
|
||||||
{
|
{
|
||||||
uintptr_t vaddr;
|
uintptr_t vaddr;
|
||||||
uintptr_t paddr;
|
uintptr_t paddr;
|
||||||
@ -203,7 +203,7 @@ int up_allocpage(FAR struct tcb_s *tcb, FAR void **vpage)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
uintptr_t oldvaddr = PG_POOL_NDX2VA(g_ptemap[pgndx]);
|
uintptr_t oldvaddr = PG_POOL_NDX2VA(g_ptemap[pgndx]);
|
||||||
pte = up_va2pte(oldvaddr);
|
pte = arm_va2pte(oldvaddr);
|
||||||
*pte = 0;
|
*pte = 0;
|
||||||
|
|
||||||
/* Invalidate the instruction TLB corresponding to the virtual address */
|
/* Invalidate the instruction TLB corresponding to the virtual address */
|
||||||
@ -227,7 +227,7 @@ int up_allocpage(FAR struct tcb_s *tcb, FAR void **vpage)
|
|||||||
* non-cached (MMU_L2_ALLOCFLAGS)
|
* non-cached (MMU_L2_ALLOCFLAGS)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pte = up_va2pte(vaddr);
|
pte = arm_va2pte(vaddr);
|
||||||
*pte = (paddr | MMU_L2_ALLOCFLAGS);
|
*pte = (paddr | MMU_L2_ALLOCFLAGS);
|
||||||
|
|
||||||
/* And save the new L1 index */
|
/* And save the new L1 index */
|
||||||
|
@ -68,10 +68,10 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: up_checkmapping()
|
* Name: arm_checkmapping()
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* The function up_checkmapping() returns an indication if the page fill
|
* The function arm_checkmapping() returns an indication if the page fill
|
||||||
* still needs to performed or not. In certain conditions, the page fault
|
* still needs to performed or not. In certain conditions, the page fault
|
||||||
* may occur on several threads and be queued multiple times. This function
|
* may occur on several threads and be queued multiple times. This function
|
||||||
* will prevent the same page from be filled multiple times.
|
* will prevent the same page from be filled multiple times.
|
||||||
@ -97,7 +97,7 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
bool up_checkmapping(FAR struct tcb_s *tcb)
|
bool arm_checkmapping(FAR struct tcb_s *tcb)
|
||||||
{
|
{
|
||||||
uintptr_t vaddr;
|
uintptr_t vaddr;
|
||||||
uint32_t *pte;
|
uint32_t *pte;
|
||||||
@ -113,7 +113,7 @@ bool up_checkmapping(FAR struct tcb_s *tcb)
|
|||||||
|
|
||||||
/* Get the PTE associated with this virtual address */
|
/* Get the PTE associated with this virtual address */
|
||||||
|
|
||||||
pte = up_va2pte(vaddr);
|
pte = arm_va2pte(vaddr);
|
||||||
|
|
||||||
/* Return true if this virtual address is mapped. */
|
/* Return true if this virtual address is mapped. */
|
||||||
|
|
||||||
|
@ -71,8 +71,6 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* A little faster than most memcpy's */
|
|
||||||
|
|
||||||
void up_copyarmstate(uint32_t *dest, uint32_t *src)
|
void up_copyarmstate(uint32_t *dest, uint32_t *src)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -101,7 +101,7 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_PAGING
|
#ifdef CONFIG_PAGING
|
||||||
|
|
||||||
void arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr)
|
uint32_t *arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr)
|
||||||
{
|
{
|
||||||
DFAR struct tcb_s *tcb = (DFAR struct tcb_s *)g_readytorun.head;
|
DFAR struct tcb_s *tcb = (DFAR struct tcb_s *)g_readytorun.head;
|
||||||
uint32_t *savestate;
|
uint32_t *savestate;
|
||||||
@ -110,7 +110,6 @@ void arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr)
|
|||||||
* for register dumps and possibly context switching.
|
* for register dumps and possibly context switching.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
savestate = (uint32_t*)current_regs;
|
savestate = (uint32_t*)current_regs;
|
||||||
current_regs = regs;
|
current_regs = regs;
|
||||||
|
|
||||||
@ -172,17 +171,18 @@ void arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
current_regs = savestate;
|
current_regs = savestate;
|
||||||
return;
|
return regs;
|
||||||
|
|
||||||
segfault:
|
segfault:
|
||||||
lldbg("Data abort. PC: %08x DFAR: %08x DFSR: %08x\n",
|
lldbg("Data abort. PC: %08x DFAR: %08x DFSR: %08x\n",
|
||||||
regs[REG_PC], dfar, dfsr);
|
regs[REG_PC], dfar, dfsr);
|
||||||
PANIC();
|
PANIC();
|
||||||
|
return regs; /* To keep the compiler happy */
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* CONFIG_PAGING */
|
#else /* CONFIG_PAGING */
|
||||||
|
|
||||||
void arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr)
|
uint32_t *arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr)
|
||||||
{
|
{
|
||||||
/* Save the saved processor context in current_regs where it can be accessed
|
/* Save the saved processor context in current_regs where it can be accessed
|
||||||
* for register dumps and possibly context switching.
|
* for register dumps and possibly context switching.
|
||||||
@ -195,6 +195,7 @@ void arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr)
|
|||||||
lldbg("Data abort. PC: %08x DFAR: %08x DFSR: %08x\n",
|
lldbg("Data abort. PC: %08x DFAR: %08x DFSR: %08x\n",
|
||||||
regs[REG_PC], dfar, dfsr);
|
regs[REG_PC], dfar, dfsr);
|
||||||
PANIC();
|
PANIC();
|
||||||
|
return regs; /* To keep the compiler happy */
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_PAGING */
|
#endif /* CONFIG_PAGING */
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void up_doirq(int irq, uint32_t *regs)
|
uint32_t *arm_doirq(int irq, uint32_t *regs)
|
||||||
{
|
{
|
||||||
up_ledon(LED_INIRQ);
|
up_ledon(LED_INIRQ);
|
||||||
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
#ifdef CONFIG_SUPPRESS_INTERRUPTS
|
||||||
@ -100,22 +100,27 @@ void up_doirq(int irq, uint32_t *regs)
|
|||||||
* point state before returning from the interrupt.
|
* point state before returning from the interrupt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARCH_FPU
|
||||||
if (regs != current_regs)
|
if (regs != current_regs)
|
||||||
{
|
{
|
||||||
/* Restore floating point registers */
|
/* Restore floating point registers */
|
||||||
|
|
||||||
up_restorefpu((uint32_t*)current_regs);
|
up_restorefpu((uint32_t*)current_regs);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set current_regs to NULL to indicate that we are no longer in an
|
/* Set current_regs to NULL to indicate that we are no longer in an
|
||||||
* interrupt handler.
|
* interrupt handler.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
regs = current_regs;
|
||||||
current_regs = NULL;
|
current_regs = NULL;
|
||||||
|
|
||||||
/* Unmask the last interrupt (global interrupts are still disabled) */
|
/* Unmask the last interrupt (global interrupts are still disabled) */
|
||||||
|
|
||||||
up_enable_irq(irq);
|
up_enable_irq(irq);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
up_ledoff(LED_INIRQ);
|
up_ledoff(LED_INIRQ);
|
||||||
|
return regs;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_PAGING
|
#ifdef CONFIG_PAGING
|
||||||
|
|
||||||
void arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr)
|
uint32_t *arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr)
|
||||||
{
|
{
|
||||||
uint32_t *savestate;
|
uint32_t *savestate;
|
||||||
|
|
||||||
@ -150,11 +150,13 @@ void arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr)
|
|||||||
regs[REG_PC], ifar, ifsr);
|
regs[REG_PC], ifar, ifsr);
|
||||||
PANIC();
|
PANIC();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* CONFIG_PAGING */
|
#else /* CONFIG_PAGING */
|
||||||
|
|
||||||
void arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr)
|
uint32_t *arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr)
|
||||||
{
|
{
|
||||||
/* Save the saved processor context in current_regs where it can be accessed
|
/* Save the saved processor context in current_regs where it can be accessed
|
||||||
* for register dumps and possibly context switching.
|
* for register dumps and possibly context switching.
|
||||||
@ -167,6 +169,7 @@ void arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr)
|
|||||||
lldbg("Prefetch abort. PC: %08x IFAR: %08x IFSR: %08x\n",
|
lldbg("Prefetch abort. PC: %08x IFAR: %08x IFSR: %08x\n",
|
||||||
regs[REG_PC], ifar, ifsr);
|
regs[REG_PC], ifar, ifsr);
|
||||||
PANIC();
|
PANIC();
|
||||||
|
return regs; /* To keep the compiler happy */
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_PAGING */
|
#endif /* CONFIG_PAGING */
|
||||||
|
@ -76,19 +76,18 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: up_syscall
|
* Name: arm_syscall
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* SWI interrupts will vection here with insn=the SWI
|
* SWI interrupts will vection here with insn=the SWI instruction and
|
||||||
* instruction and xcp=the interrupt context
|
* xcp=the interrupt context
|
||||||
*
|
*
|
||||||
* The handler may get the SWI number be de-referencing
|
* The handler may get the SWI number be de-referencing the return
|
||||||
* the return address saved in the xcp and decoding
|
* address saved in the xcp and decoding the SWI instruction
|
||||||
* the SWI instruction
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void up_syscall(uint32_t *regs)
|
uint32_t *arm_syscall(uint32_t *regs)
|
||||||
{
|
{
|
||||||
lldbg("Syscall from 0x%x\n", regs[REG_PC]);
|
lldbg("Syscall from 0x%x\n", regs[REG_PC]);
|
||||||
current_regs = regs;
|
current_regs = regs;
|
||||||
|
@ -73,9 +73,10 @@
|
|||||||
* Name: arm_undefinedinsn
|
* Name: arm_undefinedinsn
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void arm_undefinedinsn(uint32_t *regs)
|
uint32_t *arm_undefinedinsn(uint32_t *regs)
|
||||||
{
|
{
|
||||||
lldbg("Undefined instruction at 0x%x\n", regs[REG_PC]);
|
lldbg("Undefined instruction at 0x%x\n", regs[REG_PC]);
|
||||||
current_regs = regs;
|
current_regs = regs;
|
||||||
PANIC();
|
PANIC();
|
||||||
|
return regs; /* To keep the compiler happy */
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: up_va2pte
|
* Name: arm_va2pte
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Convert a virtual address within the paged text region into a pointer to
|
* Convert a virtual address within the paged text region into a pointer to
|
||||||
@ -89,7 +89,7 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
uint32_t *up_va2pte(uintptr_t vaddr)
|
uint32_t *arm_va2pte(uintptr_t vaddr)
|
||||||
{
|
{
|
||||||
uint32_t L1;
|
uint32_t L1;
|
||||||
uint32_t *L2;
|
uint32_t *L2;
|
||||||
|
@ -136,20 +136,27 @@ arm_vectorirq:
|
|||||||
str r0, [sp] /* Save the user stack pointer */
|
str r0, [sp] /* Save the user stack pointer */
|
||||||
mov r4, sp /* Save the SP in a preserved register */
|
mov r4, sp /* Save the SP in a preserved register */
|
||||||
bic sp, sp, #7 /* Force 8-byte alignement */
|
bic sp, sp, #7 /* Force 8-byte alignement */
|
||||||
bl up_decodeirq /* Call the handler */
|
bl arm_decodeirq /* Call the handler */
|
||||||
ldr sp, [r4] /* Restore the user stack pointer */
|
ldr sp, [r4] /* Restore the user stack pointer */
|
||||||
#else
|
#else
|
||||||
mov r4, sp /* Save the SP in a preserved register */
|
mov r4, sp /* Save the SP in a preserved register */
|
||||||
bic sp, sp, #7 /* Force 8-byte alignement */
|
bic sp, sp, #7 /* Force 8-byte alignement */
|
||||||
bl up_decodeirq /* Call the handler */
|
bl arm_decodeirq /* Call the handler */
|
||||||
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Restore the CPSR, SVC modr registers and return */
|
/* Upon return from arm_decodeirq, r0 holds the pointer to the register
|
||||||
|
* state save area to use to restore the registers. This may or may not
|
||||||
|
* be the same value that was passed to arm_decodeirq: It will differ if a
|
||||||
|
* context switch is required.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Restore the CPSR, SVC mode registers and return */
|
||||||
|
|
||||||
.Lnoirqset:
|
.Lnoirqset:
|
||||||
ldr r0, [sp, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
||||||
msr spsr, r0
|
msr spsr, r1
|
||||||
ldmia sp, {r0-r15}^ /* Return */
|
ldmia r0, {r0-r15}^ /* Return */
|
||||||
|
|
||||||
.Lirqtmp:
|
.Lirqtmp:
|
||||||
.word g_irqtmp
|
.word g_irqtmp
|
||||||
@ -162,7 +169,7 @@ arm_vectorirq:
|
|||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Function: arm_vectorswi
|
* Function: arm_vectorswi
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* SWI interrupt. We enter the SWI in SVC mode.
|
* SWI interrupt. We enter the SWI in SVC mode.
|
||||||
*
|
*
|
||||||
@ -192,21 +199,27 @@ arm_vectorswi:
|
|||||||
stmia r0, {r1-r4}
|
stmia r0, {r1-r4}
|
||||||
|
|
||||||
/* Then call the SWI handler with interrupts disabled.
|
/* Then call the SWI handler with interrupts disabled.
|
||||||
* void up_syscall(struct xcptcontext *xcp)
|
* void arm_syscall(struct xcptcontext *xcp)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mov fp, #0 /* Init frame pointer */
|
mov fp, #0 /* Init frame pointer */
|
||||||
mov r0, sp /* Get r0=xcp */
|
mov r0, sp /* Get r0=xcp */
|
||||||
mov r4, sp /* Save the SP in a preserved register */
|
mov r4, sp /* Save the SP in a preserved register */
|
||||||
bic sp, sp, #7 /* Force 8-byte alignement */
|
bic sp, sp, #7 /* Force 8-byte alignement */
|
||||||
bl up_syscall /* Call the handler */
|
bl arm_syscall /* Call the handler */
|
||||||
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
||||||
|
|
||||||
|
/* Upon return from arm_syscall, r0 holds the pointer to the register
|
||||||
|
* state save area to use to restore the registers. This may or may not
|
||||||
|
* be the same value that was passed to arm_syscall: It will differ if a
|
||||||
|
* context switch is required.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Restore the CPSR, SVC modr registers and return */
|
/* Restore the CPSR, SVC modr registers and return */
|
||||||
|
|
||||||
ldr r0, [sp, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
||||||
msr spsr, r0
|
msr spsr, r1
|
||||||
ldmia sp, {r0-r15}^ /* Return */
|
ldmia r0, {r0-r15}^ /* Return */
|
||||||
.size arm_vectorswi, . - arm_vectorswi
|
.size arm_vectorswi, . - arm_vectorswi
|
||||||
|
|
||||||
.align 5
|
.align 5
|
||||||
@ -275,11 +288,17 @@ arm_vectordata:
|
|||||||
bl arm_dataabort /* Call the handler */
|
bl arm_dataabort /* Call the handler */
|
||||||
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
||||||
|
|
||||||
|
/* Upon return from arm_dataabort, r0 holds the pointer to the register
|
||||||
|
* state save area to use to restore the registers. This may or may not
|
||||||
|
* be the same value that was passed to arm_dataabort: It will differ if a
|
||||||
|
* context switch is required.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Restore the CPSR, SVC modr registers and return */
|
/* Restore the CPSR, SVC modr registers and return */
|
||||||
|
|
||||||
ldr r0, [sp, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
||||||
msr spsr_cxsf, r0
|
msr spsr_cxsf, r1
|
||||||
ldmia sp, {r0-r15}^ /* Return */
|
ldmia r0, {r1-r15}^ /* Return */
|
||||||
|
|
||||||
.Ldaborttmp:
|
.Ldaborttmp:
|
||||||
.word g_aborttmp
|
.word g_aborttmp
|
||||||
@ -351,11 +370,17 @@ arm_vectorprefetch:
|
|||||||
bl arm_prefetchabort /* Call the handler */
|
bl arm_prefetchabort /* Call the handler */
|
||||||
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
||||||
|
|
||||||
|
/* Upon return from arm_prefetchabort, r0 holds the pointer to the register
|
||||||
|
* state save area to use to restore the registers. This may or may not
|
||||||
|
* be the same value that was passed to arm_prefetchabort: It will differ if a
|
||||||
|
* context switch is required.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Restore the CPSR, SVC modr registers and return */
|
/* Restore the CPSR, SVC modr registers and return */
|
||||||
|
|
||||||
ldr r0, [sp, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
||||||
msr spsr_cxsf, r0
|
msr spsr_cxsf, r1
|
||||||
ldmia sp, {r0-r15}^ /* Return */
|
ldmia r0, {r0-r15}^ /* Return */
|
||||||
|
|
||||||
.Lpaborttmp:
|
.Lpaborttmp:
|
||||||
.word g_aborttmp
|
.word g_aborttmp
|
||||||
@ -422,11 +447,17 @@ arm_vectorundefinsn:
|
|||||||
bl arm_undefinedinsn /* Call the handler */
|
bl arm_undefinedinsn /* Call the handler */
|
||||||
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
mov sp, r4 /* Restore the possibly unaligned stack pointer */
|
||||||
|
|
||||||
|
/* Upon return from arm_undefinedinsn, r0 holds the pointer to the register
|
||||||
|
* state save area to use to restore the registers. This may or may not
|
||||||
|
* be the same value that was passed to arm_undefinedinsn: It will differ if a
|
||||||
|
* context switch is required.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Restore the CPSR, SVC modr registers and return */
|
/* Restore the CPSR, SVC modr registers and return */
|
||||||
|
|
||||||
ldr r0, [sp, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
ldr r1, [r0, #(4*REG_CPSR)] /* Setup the SVC mode SPSR */
|
||||||
msr spsr_cxsf, r0
|
msr spsr_cxsf, r1
|
||||||
ldmia sp, {r0-r15}^ /* Return */
|
ldmia r0, {r0-r15}^ /* Return */
|
||||||
|
|
||||||
.Lundeftmp:
|
.Lundeftmp:
|
||||||
.word g_undeftmp
|
.word g_undeftmp
|
||||||
|
@ -99,7 +99,8 @@ void up_copyarmstate(uint32_t *dest, uint32_t *src)
|
|||||||
|
|
||||||
/* Skip over the floating point registers and save the block of ARM
|
/* Skip over the floating point registers and save the block of ARM
|
||||||
* registers that were saved by the hardware when the interrupt was
|
* registers that were saved by the hardware when the interrupt was
|
||||||
* taken. Indices: (SW_INT_REGS+SW_FPU_REGS) through (HW_XCPT_REGS-1)
|
* taken. Indices: (SW_INT_REGS+SW_FPU_REGS) through
|
||||||
|
* (XCPTCONTEXT_REGS-1)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
src += SW_FPU_REGS;
|
src += SW_FPU_REGS;
|
||||||
|
@ -134,8 +134,25 @@
|
|||||||
# endif
|
# endif
|
||||||
# define up_restorestate(regs) (current_regs = regs)
|
# define up_restorestate(regs) (current_regs = regs)
|
||||||
|
|
||||||
/* Otherwise, for the ARM7, ARM9, and Cortex-A5. The state is copied in full
|
/* The Cortex-A5 supports the same mechanism, but only lazy floating point
|
||||||
* from stack to stack. This is not very efficient.
|
* register save/restore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#elif defined(CONFIG_ARCH_CORTEXA5)
|
||||||
|
|
||||||
|
/* If the floating point unit is present and enabled, then save the
|
||||||
|
* floating point registers as well as normal ARM registers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# if defined(CONFIG_ARCH_FPU)
|
||||||
|
# define up_savestate(regs) up_copyarmstate(regs, (uint32_t*)current_regs)
|
||||||
|
# else
|
||||||
|
# define up_savestate(regs) up_copyfullstate(regs, (uint32_t*)current_regs)
|
||||||
|
# endif
|
||||||
|
# define up_restorestate(regs) (current_regs = regs)
|
||||||
|
|
||||||
|
/* Otherwise, for the ARM7 and ARM9. The state is copied in full from stack
|
||||||
|
* to stack. This is not very efficient and should be fixed to match Cortex-A5.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -289,10 +306,17 @@ void up_systemreset(void) noreturn_function;
|
|||||||
void up_irqinitialize(void);
|
void up_irqinitialize(void);
|
||||||
void up_maskack_irq(int irq);
|
void up_maskack_irq(int irq);
|
||||||
|
|
||||||
|
/* Exception handling logic unique to the Cortex-M family */
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_CORTEXM0) || defined(CONFIG_ARCH_CORTEXM3) || \
|
#if defined(CONFIG_ARCH_CORTEXM0) || defined(CONFIG_ARCH_CORTEXM3) || \
|
||||||
defined(CONFIG_ARCH_CORTEXM4)
|
defined(CONFIG_ARCH_CORTEXM4)
|
||||||
|
|
||||||
|
/* Interrupt dispatch */
|
||||||
|
|
||||||
uint32_t *up_doirq(int irq, uint32_t *regs);
|
uint32_t *up_doirq(int irq, uint32_t *regs);
|
||||||
|
|
||||||
|
/* Exception Handlers */
|
||||||
|
|
||||||
int up_svcall(int irq, FAR void *context);
|
int up_svcall(int irq, FAR void *context);
|
||||||
int up_hardfault(int irq, FAR void *context);
|
int up_hardfault(int irq, FAR void *context);
|
||||||
|
|
||||||
@ -301,9 +325,43 @@ int up_hardfault(int irq, FAR void *context);
|
|||||||
int up_memfault(int irq, FAR void *context);
|
int up_memfault(int irq, FAR void *context);
|
||||||
|
|
||||||
# endif /* CONFIG_ARCH_CORTEXM3 || CONFIG_ARCH_CORTEXM4 */
|
# endif /* CONFIG_ARCH_CORTEXM3 || CONFIG_ARCH_CORTEXM4 */
|
||||||
#else /* CONFIG_ARCH_CORTEXM0 || CONFIG_ARCH_CORTEXM3 || CONFIG_ARCH_CORTEXM4 */
|
|
||||||
|
/* Exception handling logic unique to the Cortex-A family (but should be
|
||||||
|
* back-ported to the ARM7 and ARM9 families).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#elif defined(CONFIG_ARCH_CORTEXA5)
|
||||||
|
|
||||||
|
/* Interrupt dispatch */
|
||||||
|
|
||||||
|
uint32_t *arm_doirq(int irq, uint32_t *regs);
|
||||||
|
|
||||||
|
/* Paging support */
|
||||||
|
|
||||||
|
#ifdef CONFIG_PAGING
|
||||||
|
void arm_pginitialize(void);
|
||||||
|
uint32_t *arm_va2pte(uintptr_t vaddr);
|
||||||
|
#else /* CONFIG_PAGING */
|
||||||
|
# define up_pginitialize()
|
||||||
|
#endif /* CONFIG_PAGING */
|
||||||
|
|
||||||
|
/* Exception Handlers */
|
||||||
|
|
||||||
|
uint32_t *arm_dataabort(uint32_t *regs, uint32_t dfar, uint32_t dfsr);
|
||||||
|
uint32_t *arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr);
|
||||||
|
uint32_t *arm_syscall(uint32_t *regs);
|
||||||
|
uint32_t *arm_undefinedinsn(uint32_t *regs);
|
||||||
|
|
||||||
|
/* Exception handling logic common to other ARM7 and ARM9 family. */
|
||||||
|
|
||||||
|
#else /* ARM7 | ARM9 */
|
||||||
|
|
||||||
|
/* Interrupt dispatch */
|
||||||
|
|
||||||
void up_doirq(int irq, uint32_t *regs);
|
void up_doirq(int irq, uint32_t *regs);
|
||||||
|
|
||||||
|
/* Paging support (and exception handlers) */
|
||||||
|
|
||||||
#ifdef CONFIG_PAGING
|
#ifdef CONFIG_PAGING
|
||||||
void up_pginitialize(void);
|
void up_pginitialize(void);
|
||||||
uint32_t *up_va2pte(uintptr_t vaddr);
|
uint32_t *up_va2pte(uintptr_t vaddr);
|
||||||
@ -312,6 +370,9 @@ void up_dataabort(uint32_t *regs, uint32_t far, uint32_t fsr);
|
|||||||
# define up_pginitialize()
|
# define up_pginitialize()
|
||||||
void up_dataabort(uint32_t *regs);
|
void up_dataabort(uint32_t *regs);
|
||||||
#endif /* CONFIG_PAGING */
|
#endif /* CONFIG_PAGING */
|
||||||
|
|
||||||
|
/* Exception handlers */
|
||||||
|
|
||||||
void up_prefetchabort(uint32_t *regs);
|
void up_prefetchabort(uint32_t *regs);
|
||||||
void up_syscall(uint32_t *regs);
|
void up_syscall(uint32_t *regs);
|
||||||
void up_undefinedinsn(uint32_t *regs);
|
void up_undefinedinsn(uint32_t *regs);
|
||||||
|
@ -283,6 +283,7 @@ void up_irqinitialize(void)
|
|||||||
|
|
||||||
putreg32(AIC_WPMR_WPKEY | AIC_WPMR_WPEN, SAM_AIC_WPMR);
|
putreg32(AIC_WPMR_WPKEY | AIC_WPMR_WPEN, SAM_AIC_WPMR);
|
||||||
|
|
||||||
|
#ifndef CONFIG_ARCH_LOWVECTORS
|
||||||
/* Set remap state 0:
|
/* Set remap state 0:
|
||||||
*
|
*
|
||||||
* Boot state: ROM is seen at address 0x00000000
|
* Boot state: ROM is seen at address 0x00000000
|
||||||
@ -290,10 +291,15 @@ void up_irqinitialize(void)
|
|||||||
* interface) instead of ROM.
|
* interface) instead of ROM.
|
||||||
* Remap State 1: HEBI is seen at address 0x00000000 (through AHB slave
|
* Remap State 1: HEBI is seen at address 0x00000000 (through AHB slave
|
||||||
* interface) instead of ROM for external boot.
|
* interface) instead of ROM for external boot.
|
||||||
|
*
|
||||||
|
* Here we are assuming that vectors reside in the lower end of ISRAM.
|
||||||
|
* Hmmm... this probably does not matter since we will map a page to
|
||||||
|
* address 0x0000:0000 in that case anyway.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
putreg32(MATRIX_MRCR_RCB0, SAM_MATRIX_MRCR); /* Enable remap */
|
putreg32(MATRIX_MRCR_RCB0, SAM_MATRIX_MRCR); /* Enable remap */
|
||||||
putreg32(AXIMX_REMAP_REMAP0, SAM_AXIMX_REMAP); /* Remap SRAM */
|
putreg32(AXIMX_REMAP_REMAP0, SAM_AXIMX_REMAP); /* Remap SRAM */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* currents_regs is non-NULL only while processing an interrupt */
|
/* currents_regs is non-NULL only while processing an interrupt */
|
||||||
|
|
||||||
@ -315,13 +321,13 @@ void up_irqinitialize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: up_decodeirq
|
* Name: arm_decodeirq
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* This function is called from the IRQ vector handler in arm_vectors.S.
|
* This function is called from the IRQ vector handler in arm_vectors.S.
|
||||||
* At this point, the interrupt has been taken and the registers have
|
* At this point, the interrupt has been taken and the registers have
|
||||||
* been saved on the stack. This function simply needs to determine the
|
* been saved on the stack. This function simply needs to determine the
|
||||||
* the irq number of the interrupt and then to call up_doirq to dispatch
|
* the irq number of the interrupt and then to call arm_doirq to dispatch
|
||||||
* the interrupt.
|
* the interrupt.
|
||||||
*
|
*
|
||||||
* Input paramters:
|
* Input paramters:
|
||||||
@ -329,7 +335,7 @@ void up_irqinitialize(void)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void up_decodeirq(uint32_t *regs)
|
uint32_t *arm_decodeirq(uint32_t *regs)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
@ -376,11 +382,12 @@ void up_decodeirq(uint32_t *regs)
|
|||||||
|
|
||||||
/* Dispatch the interrupt */
|
/* Dispatch the interrupt */
|
||||||
|
|
||||||
up_doirq((int)regval, regs);
|
regs = arm_doirq((int)regval, regs);
|
||||||
|
|
||||||
/* Acknowledge interrupt */
|
/* Acknowledge interrupt */
|
||||||
|
|
||||||
putreg32(AIC_EOICR_ENDIT, SAM_AIC_EOICR);
|
putreg32(AIC_EOICR_ENDIT, SAM_AIC_EOICR);
|
||||||
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -93,6 +93,8 @@ CONFIG_ARCH_CHIP="sama5"
|
|||||||
CONFIG_ARCH_HAVE_FPU=y
|
CONFIG_ARCH_HAVE_FPU=y
|
||||||
CONFIG_ARCH_FPU=y
|
CONFIG_ARCH_FPU=y
|
||||||
# CONFIG_ARCH_HAVE_MPU is not set
|
# CONFIG_ARCH_HAVE_MPU is not set
|
||||||
|
CONFIG_ARCH_HAVE_LOWVECTORS=y
|
||||||
|
CONFIG_ARCH_LOWVECTORS=y
|
||||||
CONFIG_PGTABLE_VADDR=0x20000000
|
CONFIG_PGTABLE_VADDR=0x20000000
|
||||||
# CONFIG_ARCH_ROMPGTABLE is not set
|
# CONFIG_ARCH_ROMPGTABLE is not set
|
||||||
# CONFIG_PAGING is not set
|
# CONFIG_PAGING is not set
|
||||||
|
@ -36,11 +36,14 @@
|
|||||||
/* The SAMA5D3 has 128 KB of ISRAM beginning at virtual address 0x0030:0000.
|
/* The SAMA5D3 has 128 KB of ISRAM beginning at virtual address 0x0030:0000.
|
||||||
* This memory configuration, however, loads into the 64 MB SDRAM on board
|
* This memory configuration, however, loads into the 64 MB SDRAM on board
|
||||||
* the SAMA5D3x-EK which lies at 0x2000:0000
|
* the SAMA5D3x-EK which lies at 0x2000:0000
|
||||||
|
*
|
||||||
|
* Vectors in low memory are assumed and 16KB of ISRAM is reserved at the
|
||||||
|
* high end of ISRAM for the page table.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
isram (W!RX) : ORIGIN = 0x300000, LENGTH = 128K
|
isram (W!RX) : ORIGIN = 0x300000, LENGTH = 128K - 16K
|
||||||
sdram (W!RX) : ORIGIN = 0x20000000, LENGTH = 64M
|
sdram (W!RX) : ORIGIN = 0x20000000, LENGTH = 64M
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +33,15 @@
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* The SAMA5D3 has 128 KB of ISRAM beginning at virtual address 0x0030:0000. */
|
/* The SAMA5D3 has 128 KB of ISRAM beginning at virtual address 0x0030:0000.
|
||||||
|
*
|
||||||
|
* Vectors in low memory are assumed and 16KB of ISRAM is reserved at the
|
||||||
|
* high end of ISRAM for the page table.
|
||||||
|
*/
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
isram (W!RX) : ORIGIN = 0x300000, LENGTH = 128K
|
isram (W!RX) : ORIGIN = 0x300000, LENGTH = 128K - 16K
|
||||||
}
|
}
|
||||||
|
|
||||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||||
|
@ -60,6 +60,9 @@
|
|||||||
* get a link time error saying that the locked region is full, you may have to
|
* get a link time error saying that the locked region is full, you may have to
|
||||||
* re-organize this memory layout (here and in defconfig) to make the locked
|
* re-organize this memory layout (here and in defconfig) to make the locked
|
||||||
* region even bigger.
|
* region even bigger.
|
||||||
|
*
|
||||||
|
* NOTE 3: Vectors in low memory are assumed and 16KB of ISRAM is reserved at
|
||||||
|
* the high end of ISRAM for the page table (?).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
|
Loading…
Reference in New Issue
Block a user