Mercurial > ecos
changeset 3173:afb59e9b7339
* cdl/hal_arm.cdl: Add CDL to control whether both IRQs and FIQs
are disabled in critical sections, or only IRQs. The default is to
disable both and translate any FIQs into IRQs for delivery. The
alternative is for FIQs to essentially exist outside eCos.
* include/hal_arch.h (CPSR_THREAD_INITIAL):
* include/hal_intr.h (CPSR_INTR_MASK, HAL_*_INTERRUPTS)
(HAL_*_FIQ): Add definitions for separating FIQ from IRQ.
* src/hal_mk_defs.c (main):
* src/vectors.S (start, FIQ, IRQ, spurious_IRQ):
(hal_*_interrupts, hal_*_FIQ, __fiq_stack_base): Add support for
separating FIQ from IRQ in critical section processing.
| author | nickg |
|---|---|
| date | Fri, 11 May 2012 10:24:33 +0000 |
| parents | beb3e075b6ea |
| children | 7446751761c7 |
| files | packages/hal/arm/arch/current/ChangeLog packages/hal/arm/arch/current/cdl/hal_arm.cdl packages/hal/arm/arch/current/include/hal_arch.h packages/hal/arm/arch/current/include/hal_intr.h packages/hal/arm/arch/current/src/hal_mk_defs.c packages/hal/arm/arch/current/src/vectors.S |
| diffstat | 6 files changed, 186 insertions(+), 26 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/hal/arm/arch/current/ChangeLog +++ b/packages/hal/arm/arch/current/ChangeLog @@ -1,3 +1,19 @@ +2011-11-23 Nick Garnett <nickg@ecoscentric.com> + + * cdl/hal_arm.cdl: Add CDL to control whether both IRQs and FIQs + are disabled in critical sections, or only IRQs. The default is to + disable both and translate any FIQs into IRQs for delivery. The + alternative is for FIQs to essentially exist outside eCos. + + * include/hal_arch.h (CPSR_THREAD_INITIAL): + * include/hal_intr.h (CPSR_INTR_MASK, HAL_*_INTERRUPTS) + (HAL_*_FIQ): Add definitions for separating FIQ from IRQ. + + * src/hal_mk_defs.c (main): + * src/vectors.S (start, FIQ, IRQ, spurious_IRQ): + (hal_*_interrupts, hal_*_FIQ, __fiq_stack_base): Add support for + separating FIQ from IRQ in critical section processing. + 2009-03-06 John Dallaway <john@dallaway.org.uk> * cdl/hal_arm.cdl: Merge goals for CYGHWR_THUMB and @@ -153,6 +169,13 @@ 2006-01-18 Jay Foster <jay@systech.c * src/context.S (hal_thread_switch_context): Close race condition that could cause corruption of the sp or lr registers. +2005-12-12 Jonathan Larmour <jifl@eCosCentric.com> + + * include/hal_intr.h (HAL_QUERY_INTERRUPTS): Long-standing + bug: this is meant to return an old state acceptable to + HAL_RESTORE_INTERRUPTS. + (HAL_DISABLE_INTERRUPTS): Small but simple optimisation. + 2005-04-21 Ian Campbell <icampbell@arcom.com> * src/redboot_linux_exec.c: Added -t option which takes the
--- a/packages/hal/arm/arch/current/cdl/hal_arm.cdl +++ b/packages/hal/arm/arch/current/cdl/hal_arm.cdl @@ -292,6 +292,33 @@ cdl_package CYGPKG_HAL_ARM { handlers." } + cdl_option CYGOPT_HAL_ARM_FIQ_DISABLE { + display "Disable FIQs" + default_value 1 + description "This option causes the HAL to disable both IRQ and FIQ + interrupts during critical sections. Disabling this option + causes eCos to only disable IRQs and puts FIQ + interrupts outside the eCos world where they cannot interact + with eCos in any way. Disabling this option also enables + a set of macros, HAL_DISABLE|ENABLE|RESTORE|QUERY_FIQ, + that provide control over the delivery of FIQs. + The default is for this option to be enabled, which provides + backward compatibility with previous versions of the ARM HAL." + } + + cdl_option CYGNUM_HAL_ARM_FIQ_STACK_SIZE { + display "FIQ stack size" + active_if !CYGOPT_HAL_ARM_FIQ_DISABLE + flavor data + legal_values 32 to 0x80000000 + default_value 512 + description "This option set the size of the stack used to handle FIQ + interrupts. It is only used if the HAL is not disabling + FIQs during critical sections. Otherwise FIQs are translated + into IRQs and delivered on the standard interrupt stack." + } + + cdl_component CYGPKG_REDBOOT_ARM_OPTIONS { display "Redboot for ARM options" flavor none
--- a/packages/hal/arm/arch/current/include/hal_arch.h +++ b/packages/hal/arm/arch/current/include/hal_arch.h @@ -88,8 +88,11 @@ #define CPSR_MODE_BITS 0x1F #define CPSR_INITIAL (CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SUPERVISOR_MODE) +#ifdef CYGOPT_HAL_ARM_FIQ_DISABLE #define CPSR_THREAD_INITIAL (CPSR_SUPERVISOR_MODE) - +#else +#define CPSR_THREAD_INITIAL (CPSR_SUPERVISOR_MODE|CPSR_FIQ_DISABLE) +#endif // // Vector table offsets //
--- a/packages/hal/arm/arch/current/include/hal_intr.h +++ b/packages/hal/arm/arch/current/include/hal_intr.h @@ -62,6 +62,8 @@ #include <cyg/infra/cyg_type.h> +#include <cyg/hal/hal_arch.h> + // This is to allow a variant to decide that there is no platform-specific // interrupts file; and that in turn can be overridden by a platform that // refines the variant's ideas. @@ -151,51 +153,58 @@ externC cyg_uint32 hal_default_isr(CYG_A typedef cyg_uint32 CYG_INTERRUPT_STATE; //-------------------------------------------------------------------------- +// Interrupt disable mask +// +// This is used to control which of IRQ and FIQ is enabled/disabled by +// the HAL interrupt control macros, and other places in the HAL. + +#ifdef CYGOPT_HAL_ARM_FIQ_DISABLE +#define CPSR_INTR_MASK (CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE) +#else +#define CPSR_INTR_MASK (CPSR_IRQ_DISABLE) +#endif + +//-------------------------------------------------------------------------- // Interrupt control macros #ifndef __thumb__ -// Note: This disables both FIQ and IRQ interrupts! #define HAL_DISABLE_INTERRUPTS(_old_) \ asm volatile ( \ "mrs %0,cpsr;" \ - "mrs r4,cpsr;" \ - "orr r4,r4,#0xC0;" \ + "orr r4,%0,%1;" \ "msr cpsr,r4" \ : "=r"(_old_) \ - : \ + : "i"(CPSR_INTR_MASK) \ : "r4" \ ); #define HAL_ENABLE_INTERRUPTS() \ asm volatile ( \ "mrs r3,cpsr;" \ - "bic r3,r3,#0xC0;" \ + "bic r3,r3,%0;" \ "msr cpsr,r3" \ : \ - : \ + : "i"(CPSR_INTR_MASK) \ : "r3" \ ); #define HAL_RESTORE_INTERRUPTS(_old_) \ asm volatile ( \ "mrs r3,cpsr;" \ - "and r4,%0,#0xC0;" \ - "bic r3,r3,#0xC0;" \ + "and r4,%0,%1;" \ + "bic r3,r3,%1;" \ "orr r3,r3,r4;" \ "msr cpsr,r3" \ : \ - : "r"(_old_) \ + : "r"(_old_),"i"(CPSR_INTR_MASK) \ : "r3", "r4" \ ); #define HAL_QUERY_INTERRUPTS(_old_) \ asm volatile ( \ - "mrs r4,cpsr;" \ - "and r4,r4,#0xC0;" \ - "eor %0,r4,#0xC0;" \ + "mrs %0,cpsr;" \ : "=r"(_old_) \ - : \ - : "r4" \ + : "i"(CPSR_INTR_MASK) \ ); #else // __thumb__ @@ -299,6 +308,26 @@ externC cyg_uint32 hal_query_interrupts( #endif // __thumb__ //-------------------------------------------------------------------------- +// FIQ interrupt control +// +// If eCos is not masking FIQs then the user can enable/disable them +// independently. + +#ifndef CYGOPT_HAL_ARM_FIQ_DISABLE + +externC cyg_uint32 hal_disable_FIQ(void); +externC void hal_enable_FIQ(void); +externC void hal_restore_FIQ(cyg_uint32); +externC cyg_uint32 hal_query_FIQ(void); + +#define HAL_DISABLE_FIQ(_old_) _old_ = hal_disable_FIQ() +#define HAL_ENABLE_FIQ() hal_enable_FIQ() +#define HAL_RESTORE_FIQ(_old_) hal_restore_FIQ(_old_) +#define HAL_QUERY_FIQ(_old_) _old_ = hal_query_FIQ() + +#endif + +//-------------------------------------------------------------------------- // Routine to execute DSRs using separate interrupt stack #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
--- a/packages/hal/arm/arch/current/src/hal_mk_defs.c +++ b/packages/hal/arm/arch/current/src/hal_mk_defs.c @@ -140,6 +140,8 @@ main(void) DEFINE(HAL_BREAKINST_THUMB, HAL_BREAKINST_THUMB); DEFINE(HAL_BREAKINST_ARM, HAL_BREAKINST_ARM); + DEFINE(CPSR_INTR_MASK, CPSR_INTR_MASK); + return 0; }
--- a/packages/hal/arm/arch/current/src/vectors.S +++ b/packages/hal/arm/arch/current/src/vectors.S @@ -428,7 +428,12 @@ 2: mov r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_UNDEF_MODE) msr cpsr,r0 ldr sp,.__exception_stack - +#ifndef CYGOPT_HAL_ARM_FIQ_DISABLE + mov r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_FIQ_MODE) + msr cpsr,r0 + ldr sp,.__fiq_stack +#endif + // initialize CPSR (machine state register) mov r0,#(CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE|CPSR_SUPERVISOR_MODE) msr cpsr,r0 @@ -770,6 +775,18 @@ 2: .code 32 FIQ: +#ifndef CYGOPT_HAL_ARM_FIQ_DISABLE + // If we are not disabling FIQs as part of eCos, these will be under + // user control. In theory the user should have installed their own + // FIQ VSR before enabling them and we should never come here. If + // we do there is nothing eCos itself can do because we are outside + // the scope of the system. The default action here, then, is to simply + // mask FIQs and return. + mrs r8,spsr // CPSR at time of interrupt + orr r8,r8,#CPSR_FIQ_DISABLE + msr spsr,r8 + subs pc,lr,#4 +#else // We can get here from any non-user mode. mrs r8,spsr // CPSR at time of interrupt and r9,r8,#CPSR_MODE_BITS // isolate pre-interrupt mode @@ -793,6 +810,7 @@ FIQ: // now it looks like we got an IRQ instead of an FIQ except that // FIQ is disabled so we don't recurse. +#endif IRQ: // Note: I use this exception stack while saving the context because // the current SP does not seem to be always valid in this CPU mode. @@ -804,6 +822,17 @@ IRQ: mov r3,sp mrs r4,cpsr // switch to Supervisor Mode + +#ifdef CYGOPT_HAL_ARM_FIQ_DISABLE + // Due to a small chance of contention with FIQ, + // we should disable FIQ while still in IRQ mode and then + // change to SVC mode. This only applies when eCos is masking + // FIQ alongside IRQ, otherwise FIQs are outside eCos' control + // and the FIQ to IRQ translation doesn't happen. + orr r4,r4,#CPSR_FIQ_DISABLE + msr cpsr,r4 +#endif + bic r4,r4,#CPSR_MODE_BITS // When handling an IRQ we must disable FIQ unless the current // mode in CPSR is IRQ. If we were to get a FIQ while in another @@ -812,7 +841,10 @@ IRQ: // for example, the stack pointer would be set to the beginning // of the exception_stack clobbering the registers we have just // saved. - orr r4,r4,#CPSR_SUPERVISOR_MODE|CPSR_FIQ_DISABLE + // However, if we are allowing the user to handle their own + // FIQs, we don't need to do that, since FIQ will not be + // translated to IRQ. + orr r4,r4,#CPSR_SUPERVISOR_MODE|CPSR_INTR_MASK msr cpsr,r4 mov r5,sp // save original svc sp @@ -990,8 +1022,8 @@ FUNC_START_ARM(hal_interrupt_stack_call_ stmfd sp!,{r4,r5,lr} // Disable interrupts mrs r4,cpsr // disable IRQ's - orr r2,r4,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE - bic r5,r4,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE + orr r2,r4,#CPSR_INTR_MASK + bic r5,r4,#CPSR_INTR_MASK msr cpsr,r2 // Switch to interrupt stack mov r3,sp // save old stack pointer @@ -1012,7 +1044,7 @@ FUNC_START_ARM(hal_interrupt_stack_call_ // Disable interrupts mrs r1,cpsr // disable IRQ's - orr r2,r1,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE + orr r2,r1,#CPSR_INTR_MASK msr cpsr,r2 // Move back to the thread stack. @@ -1036,21 +1068,21 @@ FUNC_START_ARM(hal_interrupt_stack_call_ FUNC_START_ARM(hal_disable_interrupts, r1) mrs r0,cpsr // current state - orr r1,r0,#0xC0 // mask both FIQ and IRQ + orr r1,r0,#CPSR_INTR_MASK // mask interrupts msr cpsr,r1 bx lr // exit, _old_ in r0 FUNC_START_ARM(hal_enable_interrupts, r1) mrs r0,cpsr // current state - bic r1,r0,#0xC0 // mask both FIQ and IRQ + bic r1,r0,#CPSR_INTR_MASK // mask interrupts msr cpsr,r1 bx lr // exit FUNC_START_ARM(hal_restore_interrupts, r1) mrs r1,cpsr // current state - bic r1,r1,#0xC0 // mask out FIQ/IRQ bits - and r0,r0,#0xC0 // keep only FIQ/IRQ - orr r1,r1,r0 // mask both FIQ and IRQ + bic r1,r1,#CPSR_INTR_MASK // mask out interrupts + and r0,r0,#CPSR_INTR_MASK // keep only interrupts + orr r1,r1,r0 // mask interrupts msr cpsr,r1 bx lr // exit @@ -1060,6 +1092,38 @@ FUNC_START_ARM(hal_query_interrupts, r1) #endif // __thumb__ +#ifndef CYGOPT_HAL_ARM_FIQ_DISABLE + +// Functions for controlling FIQ independently of IRQ. +// These are only present if we are not manipulating FIQs +// alongside IRQs in the standard interrupt control macros. + +FUNC_START_ARM(hal_disable_FIQ, r1) + mrs r0,cpsr // current state + orr r1,r0,#CPSR_FIQ_DISABLE // mask FIQs + msr cpsr,r1 + bx lr // exit, _old_ in r0 + +FUNC_START_ARM(hal_enable_FIQ, r1) + mrs r0,cpsr // current state + bic r1,r0,#CPSR_FIQ_DISABLE // mask FIQs + msr cpsr,r1 + bx lr // exit + +FUNC_START_ARM(hal_restore_FIQ, r1) + mrs r1,cpsr // current state + bic r1,r1,#CPSR_FIQ_DISABLE // mask out FIQs + and r0,r0,#CPSR_FIQ_DISABLE // keep only FIQs + orr r1,r1,r0 // mask FIQs + msr cpsr,r1 + bx lr // exit + +FUNC_START_ARM(hal_query_FIQ, r1) + mrs r0,cpsr // current state + bx lr // exit, state in r0 + +#endif + // Dummy/support functions .global __gccmain @@ -1129,7 +1193,9 @@ PTR(__interrupt_stack) #ifdef CYGHWR_HAL_ARM_DUMP_EXCEPTIONS PTR(__dump_procs) #endif - +#ifndef CYGOPT_HAL_ARM_FIQ_DISABLE +PTR(__fiq_stack) +#endif // // Identification - useful to find out when a system was configured _eCos_id: @@ -1187,6 +1253,16 @@ hal_interrupt_objects: .endr __undef_exception_stack: +#ifndef CYGOPT_HAL_ARM_FIQ_DISABLE + .balign 16 +__fiq_stack_base: + .rept CYGNUM_HAL_ARM_FIQ_STACK_SIZE + .byte 0 + .endr + .balign 16 +__fiq_stack: +#endif + // Runtime stack used during all interrupt processing #ifndef CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE #define CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE 4096
