diff --git a/arch/avr/include/avr/irq.h b/arch/avr/include/avr/irq.h index b387be67112..d3026c1853c 100644 --- a/arch/avr/include/avr/irq.h +++ b/arch/avr/include/avr/irq.h @@ -89,9 +89,14 @@ #define REG_R0 33 /* r0 */ #define REG_R24 34 /* r24 */ +/* The program counter is automatically pushed when the interrupt occurs */ + +#define REG_PCH 35 /* PC */ +#define REG_PCL 36 + /* Size of the register state save array (in bytes) */ -#define XCPTCONTEXT_REGS 35 +#define XCPTCONTEXT_REGS 37 /**************************************************************************** * Public Types @@ -111,8 +116,9 @@ struct xcptcontext /* These are saved copies of PC and SR used during signal processing.*/ - uint16_t saved_pc; - uint8_t saved_sr; + uint8_t saved_pcl; + uint8_t saved_pch; + uint8_t saved_sreg; #endif /* Register save area */ diff --git a/arch/avr/src/at32uc3/Make.defs b/arch/avr/src/at32uc3/Make.defs index 94dc5d2dcb6..49d35ed4be9 100644 --- a/arch/avr/src/at32uc3/Make.defs +++ b/arch/avr/src/at32uc3/Make.defs @@ -48,6 +48,12 @@ CMN_CSRCS = up_assert.c up_allocateheap.c up_blocktask.c up_copystate.c \ up_schedulesigaction.c up_sigdeliver.c up_unblocktask.c \ up_usestack.c up_doirq.c +# Configuration-dependent common files + +ifeq ($(CONFIG_ARCH_STACKDUMP),y) +CMN_CSRCS += up_dumpstate.c +endif + # Required AT32UC3 files CHIP_ASRCS = diff --git a/arch/avr/src/at90usb/Make.defs b/arch/avr/src/at90usb/Make.defs index a206f4f6fe0..dcff056b5c7 100644 --- a/arch/avr/src/at90usb/Make.defs +++ b/arch/avr/src/at90usb/Make.defs @@ -40,12 +40,20 @@ HEAD_ASRC = at90usb_head.S # Common AVR files CMN_ASRCS = up_switchcontext.S -CMN_CSRCS = up_allocateheap.c up_copystate.c up_createstack.c up_exit.c \ - up_idle.c up_initialize.c up_interruptcontext.c up_lowputs.c \ - up_mdelay.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \ - up_puts.c up_releasestack.c up_udelay.c up_usestack.c +CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ + up_createstack.c up_doirq.c up_exit.c up_idle.c up_initialize.c \ + up_interruptcontext.c up_lowputs.c up_mdelay.c up_modifyreg8.c \ + up_modifyreg16.c up_modifyreg32.c up_puts.c up_releasepending.c \ + up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \ + up_sigdeliver.c up_udelay.c up_unblocktask.c up_usestack.c -# Required aT90USB files +# Configuration-dependent common files + +ifeq ($(CONFIG_ARCH_STACKDUMP),y) +CMN_CSRCS += up_dumpstate.c +endif + +# Required AT90USB files CHIP_ASRCS = at90usb_exceptions.S CHIP_CSRCS = diff --git a/arch/avr/src/at90usb/at90usb_exceptions.S b/arch/avr/src/at90usb/at90usb_exceptions.S index 748fd5efc84..862ea06ae67 100755 --- a/arch/avr/src/at90usb/at90usb_exceptions.S +++ b/arch/avr/src/at90usb/at90usb_exceptions.S @@ -64,43 +64,43 @@ .section .handlers, "ax", @progbits - HANDLER at90usb_int0, ATMEGA_IRQ_INT0, excpt_common /* External interrupt request 0 */ - HANDLER at90usb_int1, ATMEGA_IRQ_INT1, excpt_common /* External interrupt request 1 */ - HANDLER at90usb_int2, ATMEGA_IRQ_INT2, excpt_common /* External interrupt request 2 */ - HANDLER at90usb_int3, ATMEGA_IRQ_INT3, excpt_common /* External interrupt request 3 */ - HANDLER at90usb_int4, ATMEGA_IRQ_INT4, excpt_common /* External interrupt request 4 */ - HANDLER at90usb_int5, ATMEGA_IRQ_INT5, excpt_common /* External interrupt request 5 */ - HANDLER at90usb_int6, ATMEGA_IRQ_INT6, excpt_common /* External interrupt request 6 */ - HANDLER at90usb_int7, ATMEGA_IRQ_INT7, excpt_common /* External interrupt request 7 */ + HANDLER at90usb_int0, AT90USB_IRQ_INT0, excpt_common /* External interrupt request 0 */ + HANDLER at90usb_int1, AT90USB_IRQ_INT1, excpt_common /* External interrupt request 1 */ + HANDLER at90usb_int2, AT90USB_IRQ_INT2, excpt_common /* External interrupt request 2 */ + HANDLER at90usb_int3, AT90USB_IRQ_INT3, excpt_common /* External interrupt request 3 */ + HANDLER at90usb_int4, AT90USB_IRQ_INT4, excpt_common /* External interrupt request 4 */ + HANDLER at90usb_int5, AT90USB_IRQ_INT5, excpt_common /* External interrupt request 5 */ + HANDLER at90usb_int6, AT90USB_IRQ_INT6, excpt_common /* External interrupt request 6 */ + HANDLER at90usb_int7, AT90USB_IRQ_INT7, excpt_common /* External interrupt request 7 */ HANDLER at90usb_pcint0, AT90USB_IRQ_PCINT0, excpt_common /* Pin Change Interrupt Request 0 */ HANDLER at90usb_usbgen, AT90USB_IRQ_USBGEN, excpt_common /* USB General USB General Interrupt request */ HANDLER at90usb_usbep, AT90USB_IRQ_USBEP, excpt_common /* USB Endpoint/Pipe USB ENdpoint/Pipe Interrupt request */ HANDLER at90usb_wdt, AT90USB_IRQ_WDT, excpt_common /* Watchdog Time-out Interrupt */ HANDLER at90usb_t2compa, AT90USB_IRQ_T2COMPA, excpt_common /* TIMER2 COMPA Timer/Counter2 Compare Match A */ HANDLER at90usb_t2compb, AT90USB_IRQ_T2COMPB, excpt_common /* TIMER2 COMPA Timer/Counter2 Compare Match B */ - HANDLER at90usb_t2ovf, ATMEGA_IRQ_T2OVF, excpt_common /* TIMER2 OVF timer/counter2 overflow */ - HANDLER at90usb_t1capt, ATMEGA_IRQ_T1CAPT, excpt_common /* TIMER1 CAPT timer/counter1 capture event */ - HANDLER at90usb_t1compa, ATMEGA_IRQ_T1COMPA, excpt_common /* TIMER1 COMPA timer/counter1 compare match A */ - HANDLER at90usb_t1compb, ATMEGA_IRQ_T1COMPB, excpt_common /* TIMER1 COMPB timer/counter1 compare match B */ - HANDLER at90usb_t1compc, ATMEGA_IRQ_T1COMPC, excpt_common /* TIMER1 COMPC timer/counter1 compare match C */ - HANDLER at90usb_t1ovf, ATMEGA_IRQ_T1OVF, excpt_common /* TIMER1 OVF timer/counter1 overflow */ + HANDLER at90usb_t2ovf, AT90USB_IRQ_T2OVF, excpt_common /* TIMER2 OVF timer/counter2 overflow */ + HANDLER at90usb_t1capt, AT90USB_IRQ_T1CAPT, excpt_common /* TIMER1 CAPT timer/counter1 capture event */ + HANDLER at90usb_t1compa, AT90USB_IRQ_T1COMPA, excpt_common /* TIMER1 COMPA timer/counter1 compare match A */ + HANDLER at90usb_t1compb, AT90USB_IRQ_T1COMPB, excpt_common /* TIMER1 COMPB timer/counter1 compare match B */ + HANDLER at90usb_t1compc, AT90USB_IRQ_T1COMPC, excpt_common /* TIMER1 COMPC timer/counter1 compare match C */ + HANDLER at90usb_t1ovf, AT90USB_IRQ_T1OVF, excpt_common /* TIMER1 OVF timer/counter1 overflow */ HANDLER at90usb_t0compa, AT90USB_IRQ_T0COMPA, excpt_common /* TIMER0 COMPA Timer/Counter0 Compare Match A */ HANDLER at90usb_t0compb, AT90USB_IRQ_T0COMPB, excpt_common /* TIMER0 COMPB Timer/Counter0 Compare Match B */ - HANDLER at90usb_t0ovf, ATMEGA_IRQ_T0OVF, excpt_common /* TIMER0 OVF timer/counter0 overflow */ - HANDLER at90usb_spi, ATMEGA_IRQ_SPI, excpt_common /* STC SPI serial transfer complete */ - HANDLER at90usb_u1rx, ATMEGA_IRQ_U1RX, excpt_common /* USART1 RX complete */ - HANDLER at90usb_u1dre, ATMEGA_IRQ_U1DRE, excpt_common /* USART1 data register empty */ - HANDLER at90usb_u1tx, ATMEGA_IRQ_U1TX, excpt_common /* USART1 TX complete */ - HANDLER at90usb_anacomp, ATMEGA_IRQ_ANACOMP, excpt_common /* ANALOG COMP analog comparator */ - HANDLER at90usb_adc, ATMEGA_IRQ_ADC, excpt_common /* ADC conversion complete */ - HANDLER at90usb_ee, ATMEGA_IRQ_EE, excpt_common /* EEPROM ready */ - HANDLER at90usb_t3capt, ATMEGA_IRQ_T3CAPT, excpt_common /* TIMER3 CAPT timer/counter3 capture event */ - HANDLER at90usb_t3compa, ATMEGA_IRQ_T3COMPA, excpt_common /* TIMER3 COMPA timer/counter3 compare match a */ - HANDLER at90usb_t3compb, ATMEGA_IRQ_T3COMPB, excpt_common /* TIMER3 COMPB timer/counter3 compare match b */ - HANDLER at90usb_t3compc, ATMEGA_IRQ_T3COMPC, excpt_common /* TIMER3 COMPC timer/counter3 compare match c */ - HANDLER at90usb_t3ovf, ATMEGA_IRQ_T3OVF, excpt_common /* TIMER3 OVF timer/counter3 overflow */ - HANDLER at90usb_twi, ATMEGA_IRQ_TWI, excpt_common /* TWI two-wire serial interface */ - HANDLER at90usb_spmrdy, ATMEGA_IRQ_SPMRDY, excpt_common /* Store program memory ready */ + HANDLER at90usb_t0ovf, AT90USB_IRQ_T0OVF, excpt_common /* TIMER0 OVF timer/counter0 overflow */ + HANDLER at90usb_spi, AT90USB_IRQ_SPI, excpt_common /* STC SPI serial transfer complete */ + HANDLER at90usb_u1rx, AT90USB_IRQ_U1RX, excpt_common /* USART1 RX complete */ + HANDLER at90usb_u1dre, AT90USB_IRQ_U1DRE, excpt_common /* USART1 data register empty */ + HANDLER at90usb_u1tx, AT90USB_IRQ_U1TX, excpt_common /* USART1 TX complete */ + HANDLER at90usb_anacomp, AT90USB_IRQ_ANACOMP, excpt_common /* ANALOG COMP analog comparator */ + HANDLER at90usb_adc, AT90USB_IRQ_ADC, excpt_common /* ADC conversion complete */ + HANDLER at90usb_ee, AT90USB_IRQ_EE, excpt_common /* EEPROM ready */ + HANDLER at90usb_t3capt, AT90USB_IRQ_T3CAPT, excpt_common /* TIMER3 CAPT timer/counter3 capture event */ + HANDLER at90usb_t3compa, AT90USB_IRQ_T3COMPA, excpt_common /* TIMER3 COMPA timer/counter3 compare match a */ + HANDLER at90usb_t3compb, AT90USB_IRQ_T3COMPB, excpt_common /* TIMER3 COMPB timer/counter3 compare match b */ + HANDLER at90usb_t3compc, AT90USB_IRQ_T3COMPC, excpt_common /* TIMER3 COMPC timer/counter3 compare match c */ + HANDLER at90usb_t3ovf, AT90USB_IRQ_T3OVF, excpt_common /* TIMER3 OVF timer/counter3 overflow */ + HANDLER at90usb_twi, AT90USB_IRQ_TWI, excpt_common /* TWI two-wire serial interface */ + HANDLER at90usb_spmrdy, AT90USB_IRQ_SPMRDY, excpt_common /* Store program memory ready */ /* Common exception handling logic. */ diff --git a/arch/avr/src/at90usb/at90usb_head.S b/arch/avr/src/at90usb/at90usb_head.S index 16d4abcc1ea..f951bac1db3 100755 --- a/arch/avr/src/at90usb/at90usb_head.S +++ b/arch/avr/src/at90usb/at90usb_head.S @@ -193,6 +193,9 @@ __start: /* Copy initial global data values from FLASH into RAM */ + .global __do_copy_data; /* Required to suppress dragging in logic from libgcc */ +__do_copy_data: + #ifdef HAVE_RAMPZ ldi r17, hi8(_edata) ldi r26, lo8(_sdata) @@ -230,6 +233,9 @@ __start: /* Clear uninitialized data */ + .global __do_clear_bss; /* Required to suppress dragging in logic from libgcc */ +__do_clear_bss: + ldi r17, hi8(_ebss) ldi r26, lo8(_sbss) ldi r27, hi8(_sbss) diff --git a/arch/avr/src/atmega/Make.defs b/arch/avr/src/atmega/Make.defs index 3699543dda9..9bcf64ea038 100644 --- a/arch/avr/src/atmega/Make.defs +++ b/arch/avr/src/atmega/Make.defs @@ -40,10 +40,18 @@ HEAD_ASRC = atmega_head.S # Common AVR files CMN_ASRCS = up_switchcontext.S -CMN_CSRCS = up_allocateheap.c up_copystate.c up_createstack.c up_exit.c \ - up_idle.c up_initialize.c up_interruptcontext.c up_lowputs.c \ - up_mdelay.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \ - up_puts.c up_releasestack.c up_udelay.c up_usestack.c +CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \ + up_createstack.c up_doirq.c up_exit.c up_idle.c up_initialize.c \ + up_interruptcontext.c up_lowputs.c up_mdelay.c up_modifyreg8.c \ + up_modifyreg16.c up_modifyreg32.c up_puts.c up_releasepending.c \ + up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \ + up_sigdeliver.c up_udelay.c up_unblocktask.c up_usestack.c + +# Configuration-dependent common files + +ifeq ($(CONFIG_ARCH_STACKDUMP),y) +CMN_CSRCS += up_dumpstate.c +endif # Required ATMEGA files diff --git a/arch/avr/src/atmega/atmega_head.S b/arch/avr/src/atmega/atmega_head.S index aff46a39ee4..2ebd8ecec0d 100755 --- a/arch/avr/src/atmega/atmega_head.S +++ b/arch/avr/src/atmega/atmega_head.S @@ -39,6 +39,7 @@ #include +#include #include #include @@ -186,6 +187,9 @@ __start: /* Copy initial global data values from FLASH into RAM */ + .global __do_copy_data; /* Required to suppress dragging in logic from libgcc */ +__do_copy_data: + #ifdef HAVE_RAMPZ ldi r17, hi8(_edata) ldi r26, lo8(_sdata) @@ -223,6 +227,9 @@ __start: /* Clear uninitialized data */ + .global __do_clear_bss; /* Required to suppress dragging in logic from libgcc */ +__do_clear_bss: + ldi r17, hi8(_ebss) ldi r26, lo8(_sbss) ldi r27, hi8(_sbss) diff --git a/arch/avr/src/avr/avr_internal.h b/arch/avr/src/avr/avr_internal.h index 18265332ed1..c66103f0052 100644 --- a/arch/avr/src/avr/avr_internal.h +++ b/arch/avr/src/avr/avr_internal.h @@ -94,7 +94,7 @@ extern void up_copystate(uint8_t *dest, uint8_t *src); extern int up_saveusercontext(uint8_t *saveregs); extern void up_fullcontextrestore(uint8_t *restoreregs) __attribute__ ((noreturn)); extern void up_switchcontext(uint8_t *saveregs, uint8_t *restoreregs); -extern uint8_t *up_doirq(int irq, uint8_t *regs); +extern uint8_t *up_doirq(uint8_t irq, uint8_t *regs); #endif /* __ASSEMBLY__ */ #endif /* __ARCH_AVR_SRC_AVR_AVR_INTERNAL_H */ diff --git a/arch/avr/src/avr/excptmacros.h b/arch/avr/src/avr/excptmacros.h index b4408f28899..463b9529669 100755 --- a/arch/avr/src/avr/excptmacros.h +++ b/arch/avr/src/avr/excptmacros.h @@ -1,22 +1,22 @@ /******************************************************************************************** * arch/avr/src/avr/excptmacros.h * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. + * used to endorse or promote products derived from this software + * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -104,30 +104,39 @@ * RESTORE_STACK rx, ry - Undo the operations of USE_STACK * * EXCPT_EPILOGUE - Return to the context returned by handler() + * reti - Return from interrupt * ********************************************************************************************/ -/**************************************************************************** - * Macros - ****************************************************************************/ /******************************************************************************************** * Name: HANDLER * * Description: - * This macro provides the exception entry logic. It simply saves one register on the - * stack (r24) and passes the IRQ number to to common logic (see EXCPT_PROLOGUE). + * This macro provides the exception entry logic. It is called with the PC already on the + * stack. It simply saves one register on the stack (r24) and passes the IRQ number to + * common logic (see EXCPT_PROLOGUE). * * On Entry: - * sp - Points to the top of the stack - * Only the stack is available for storage + * sp - Points to the top of the stack. The PC is already on the stack. + * Only the stack is available for storage + * + * PCL + * PCH + * --- <- SP * * At completion: - * Stack pointer is incremented by one, the saved r24 is on the stack, r24 now contains the - * IRQ number + * Stack pointer is incremented by one, the saved r24 is on the stack, r24 now contains the + * IRQ number + * + * PCL + * PCH + * R0 + * --- <- SP * ********************************************************************************************/ - .macro HANDLER, label, irqno, common + .macro HANDLER, label, irqno, common + .global \label \label: push r24 ldi r24, \irqno @@ -138,20 +147,26 @@ * Name: EXCPT_PROLOGUE * * Description: - * Provides the common "prologue" logic that should appear at the beginning of the exception - * handler. + * Provides the common "prologue" logic that should appear at the beginning of the exception + * handler. * * On Entry: - * r0 - has already been pushed onto the stack and now holds the IRQ number - * sp - Points to the top of the stack - * Only the stack is available for storage + * r0 - has already been pushed onto the stack and now holds the IRQ number + * sp - Points to the top of the stack + * Only the stack is available for storage + * + * PCL + * PCH + * R0 + * --- <- SP * * At completion: - * Register state is saved on the stack; All registers are available for usage except sp. + * Register state is saved on the stack; All registers are available for usage except sp. * ********************************************************************************************/ .macro EXCPT_PROLOGUE + /* Save R1 - The zero register (but might not be zero) */ push r1 @@ -228,15 +243,16 @@ * Name: EXCPT_EPILOGUE * * Description: - * Provides the "epilogue" logic that should appear at the end of every exception handler. + * Provides the "epilogue" logic that should appear at the end of every exception handler. * * On input: - * sp points to the address of the register save area (just as left by EXCPT_PROLOGUE). - * All registers are available for use. - * Interrupts are disabled. + * sp points to the address of the register save area (just as left by EXCPT_PROLOGUE). + * All registers are available for use. + * Interrupts are disabled. * * On completion: - * All registers restored + * All registers restored except the PC which remains on the stack so that a return + * via reti can be performed. * ********************************************************************************************/ @@ -312,16 +328,17 @@ * Name: USER_SAVE * * Description: - * Similar to EXPCT_PROLOGUE except that (1) this saves values into a register save - * data structure instead of on the stack, (2) the pointer is in r26;r27, and (3) - * Call-used registers are not saved. + * Similar to EXPCT_PROLOGUE except that (1) this saves values into a register save + * data structure instead of on the stack, (2) the pointer is in r26;r27, and (3) + * Call-used registers are not saved. * * On Entry: - * X [r26:r27] - Points to the register save structure. - * Interrupts are disabled. + * X [r26:r27] - Points to the register save structure. + * Return address is already on the stack (due to CALL or RCALL instruction)/. + * Interrupts are disabled. * * At completion: - * Register state is saved on the stack; All registers are available for usage except sp. + * Register state is saved on the stack; All registers are available for usage except sp. * ********************************************************************************************/ @@ -377,35 +394,59 @@ st x+, r0 /* Skip R0 and r24 - These are scratch register and Call-used, "volatile" registers */ + + adiw r26, 2 /* Two registers: r0, r24 */ + + /* Pop and save the return address */ + + pop r0 + st x+, r0 + pop r0 + st x+, r0 .endm /******************************************************************************************** * Name: TCB_RESTORE * * Description: - * Functionally equivalent to EXCPT_EPILOGUE excetp that register save area is not on the - * stack but is held in a data structure. + * Functionally equivalent to EXCPT_EPILOGUE excetp that register save area is not on the + * stack but is held in a data structure. * * On input: - * X [r26:r27] points to the data structure. - * All registers are available for use. - * Interrupts are disabled. + * X [r26:r27] points to the data structure. + * All registers are available for use. + * Interrupts are disabled. * * On completion: - * All registers restored + * All registers restored except for the PC with now resides at the top of the new stack + * so that iret can be used to switch to the new context. * ********************************************************************************************/ .macro TCB_RESTORE, regs - /* Fetch the new stack pointer and the saved values of X [r26:r27]. Save X on the new - * stack where we can recover it later. - */ + /* Fetch the new stack pointer */ ld r24, x+ /* Fetch stack pointer (post-incrementing) */ out __SP_L__, r24 ld r25, x+ out __SP_H__, r25 + + /* Fetch the return address and save it at the bottom of the new stack so + * that we can iret to switch contexts. + */ + + movw r28, r26 /* Get a pointer to the PCH/PCL storage location */ + adiw r28, REG_PCH + ld r25, y+ /* Load PCH and PCL */ + ld r24, y+ + push r24 /* Push PCH and PCL on the stack */ + push r25 + + /* Then get value of X [r26:r27]. Save X on the new stack where we can + * recover it later. + */ + ld r25, x+ /* Fetch r26-r27 and save to the new stack */ ld r24, x+ push r24 @@ -466,7 +507,9 @@ ld r0, x+ ld r24, x+ - /* Finally, recover X [r26-r27] from the the new stack */ + /* Finally, recover X [r26-r27] from the the new stack. The PC remains on the new + * stack so that the user of this macro can return with iret. + */ pop r27 pop r26 @@ -476,18 +519,18 @@ * Name: USE_INTSTACK * * Description: - * Switch to the interrupt stack (if enabled in the configuration) and if the nesting level - * is equal to 0. Increment the nesting level in any event. + * Switch to the interrupt stack (if enabled in the configuration) and if the nesting level + * is equal to 0. Increment the nesting level in any event. * * On Entry: - * sp - Current value of the user stack pointer - * tmp1, tmp2, and tmp3 are registers that can be used temporarily. - * All interrupts should still be disabled. + * sp - Current value of the user stack pointer + * tmp1, tmp2, and tmp3 are registers that can be used temporarily. + * All interrupts should still be disabled. * * At completion: - * If the nesting level is 0, then (1) the user stack pointer is saved at the base of the - * interrupt stack and sp points to the interrupt stack. - * The values of tmp1, tmp2, tmp3, and sp have been altered + * If the nesting level is 0, then (1) the user stack pointer is saved at the base of the + * interrupt stack and sp points to the interrupt stack. + * The values of tmp1, tmp2, tmp3, and sp have been altered * ********************************************************************************************/ @@ -501,16 +544,16 @@ * Name: RESTORE_STACK * * Description: - * Restore the user stack. Not really.. actually only decrements the nesting level. We - * always get the new stack pointer for the register save array. + * Restore the user stack. Not really.. actually only decrements the nesting level. We + * always get the new stack pointer for the register save array. * * On Entry: - * tmp1 and tmp2 are registers that can be used temporarily. - * All interrupts must be disabled. + * tmp1 and tmp2 are registers that can be used temporarily. + * All interrupts must be disabled. * * At completion: - * Current nesting level is decremented - * The values of tmp1 and tmp2 have been altered + * Current nesting level is decremented + * The values of tmp1 and tmp2 have been altered * ********************************************************************************************/ diff --git a/arch/avr/src/avr/up_blocktask.c b/arch/avr/src/avr/up_blocktask.c new file mode 100755 index 00000000000..6444132e026 --- /dev/null +++ b/arch/avr/src/avr/up_blocktask.c @@ -0,0 +1,168 @@ +/**************************************************************************** + * arch/avr/src/avr/up_blocktask.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "os_internal.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_block_task + * + * Description: + * The currently executing task at the head of + * the ready to run list must be stopped. Save its context + * and move it to the inactive list specified by task_state. + * + * Inputs: + * tcb: Refers to a task in the ready-to-run list (normally + * the task at the head of the list). It most be + * stopped, its context saved and moved into one of the + * waiting task lists. It it was the task at the head + * of the ready-to-run list, then a context to the new + * ready to run task must be performed. + * task_state: Specifies which waiting task list should be + * hold the blocked task TCB. + * + ****************************************************************************/ + +void up_block_task(_TCB *tcb, tstate_t task_state) +{ + /* Verify that the context switch can be performed */ + + if ((tcb->task_state < FIRST_READY_TO_RUN_STATE) || + (tcb->task_state > LAST_READY_TO_RUN_STATE)) + { + PANIC(OSERR_BADBLOCKSTATE); + } + else + { + _TCB *rtcb = (_TCB*)g_readytorun.head; + bool switch_needed; + + /* Remove the tcb task from the ready-to-run list. If we + * are blocking the task at the head of the task list (the + * most likely case), then a context switch to the next + * ready-to-run task is needed. In this case, it should + * also be true that rtcb == tcb. + */ + + switch_needed = sched_removereadytorun(tcb); + + /* Add the task to the specified blocked task list */ + + sched_addblocked(tcb, (tstate_t)task_state); + + /* If there are any pending tasks, then add them to the g_readytorun + * task list now + */ + + if (g_pendingtasks.head) + { + switch_needed |= sched_mergepending(); + } + + /* Now, perform the context switch if one is needed */ + + if (switch_needed) + { + /* Are we in an interrupt handler? */ + + if (current_regs) + { + /* Yes, then we have to do things differently. + * Just copy the current_regs into the OLD rtcb. + */ + + up_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the g_readytorun task list. + */ + + rtcb = (_TCB*)g_readytorun.head; + + /* Then switch contexts */ + + up_restorestate(rtcb->xcp.regs); + } + + /* No, then we will need to perform the user context switch */ + + else + { + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + _TCB *nexttcb = (_TCB*)g_readytorun.head; + up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ + } + } + } +} + diff --git a/arch/avr/src/avr/up_doirq.c b/arch/avr/src/avr/up_doirq.c new file mode 100644 index 00000000000..764117abf6e --- /dev/null +++ b/arch/avr/src/avr/up_doirq.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * arch/avr/src/avr/up_doirq.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include "up_arch.h" +#include "os_internal.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +uint8_t *up_doirq(uint8_t irq, uint8_t *regs) +{ + up_ledon(LED_INIRQ); +#ifdef CONFIG_SUPPRESS_INTERRUPTS + PANIC(OSERR_ERREXCEPTION); +#else + uint8_t *savestate; + + /* Nested interrupts are not supported in this implementation. If you want + * implemented nested interrupts, you would have to (1) change the way that + * current regs is handled and (2) the design associated with + * CONFIG_ARCH_INTERRUPTSTACK. + */ + + /* Current regs non-zero indicates that we are processing an interrupt; + * current_regs is also used to manage interrupt level context switches. + */ + + savestate = (uint8_t*)current_regs; + current_regs = regs; + + /* Deliver the IRQ */ + + irq_dispatch((int)irq, (uint32_t*)regs); + + /* If a context switch occurred while processing the interrupt then + * current_regs may have change value. If we return any value different + * from the input regs, then the lower level will know that a context + * switch occurred during interrupt processing. + */ + + regs = current_regs; + + /* Restore the previous value of current_regs. NULL would indicate that + * we are no longer in an interrupt handler. It will be non-NULL if we + * are returning from a nested interrupt. + */ + + current_regs = savestate; +#endif + up_ledoff(LED_INIRQ); + return regs; +} + diff --git a/arch/avr/src/avr/up_dumpstate.c b/arch/avr/src/avr/up_dumpstate.c new file mode 100644 index 00000000000..e9d0859e8ae --- /dev/null +++ b/arch/avr/src/avr/up_dumpstate.c @@ -0,0 +1,263 @@ +/**************************************************************************** + * arch/avr/src/avr/up_dumpstate.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "up_arch.h" +#include "os_internal.h" +#include "up_internal.h" + +#ifdef CONFIG_ARCH_STACKDUMP + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Output debug info if stack dump is selected -- even if debug is not + * selected. + */ + +#undef lldbg +#define lldbg lib_lowprintf + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_getsp + ****************************************************************************/ + +/* There may be a built-in to do this, but I don't know if it is enabled */ + +static inline uint16_t up_getsp(void) +{ + uint8_t spl; + uint8_t sph; + + __asm__ __volatile__ + ( + "in %0, __SP_L__\n\t" + "in %1, __SP_H__\n" + : "=r" (spl), "=r" (sph) + : + ); + return (uint16_t)sph << 8 | spl; +} + +/**************************************************************************** + * Name: up_stackdump + ****************************************************************************/ + +static void up_stackdump(uint16_t sp, uint16_t stack_base) +{ + uint16_t stack ; + + for (stack = sp & ~3; stack < stack_base; stack += 12) + { + uint8_t *ptr = (uint8_t*)stack; + lldbg("%04x: %02x %02x %02x %02x %02x %02x %02x %02x" + " %02x %02x %02x %02x\n", + stack, + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], + ptr[9], ptr[10], ptr[11]); + } +} + +/**************************************************************************** + * Name: up_registerdump + ****************************************************************************/ + +static inline void up_registerdump(void) +{ + /* Are user registers available from interrupt processing? */ + + if (current_regs) + { + lldbg("R%d: %02x %02x %02x %02x %02x %02x %02x %02x\n", + 0, + current_regs[REG_R0], current_regs[REG_R1], + current_regs[REG_R2], current_regs[REG_R3], + current_regs[REG_R4], current_regs[REG_R5], + current_regs[REG_R6], current_regs[REG_R7]); + + lldbg("R%d: %02x %02x %02x %02x %02x %02x %02x %02x\n", + 8, + current_regs[REG_R8], current_regs[REG_R9], + current_regs[REG_R10], current_regs[REG_R11], + current_regs[REG_R12], current_regs[REG_R13], + current_regs[REG_R14], current_regs[REG_R15]); + + lldbg("R%d: %02x %02x %02x %02x %02x %02x %02x %02x\n", + 16, + current_regs[REG_R16], current_regs[REG_R17], + current_regs[REG_R18], current_regs[REG_R19], + current_regs[REG_R20], current_regs[REG_R21], + current_regs[REG_R22], current_regs[REG_R23]); + + lldbg("R%d: %02x %02x %02x %02x %02x %02x %02x %02x\n", + 24, + current_regs[REG_R24], current_regs[REG_R25], + current_regs[REG_R26], current_regs[REG_R27], + current_regs[REG_R28], current_regs[REG_R29], + current_regs[REG_R30], current_regs[REG_R31]); + + lldbg("PC: %02x%02x SP: %02x%02x SREG: %02x\n", + current_regs[REG_PCH], current_regs[REG_PCL], + current_regs[REG_SPH], current_regs[REG_SPL], + current_regs[REG_SREG]); + } +} + +/**************************************************************************** + * Name: _up_assert + ****************************************************************************/ + +/**************************************************************************** + * Name: up_dumpstate + ****************************************************************************/ + +void up_dumpstate(void) +{ + _TCB *rtcb = (_TCB*)g_readytorun.head; + uint16_t sp = up_getsp(); + uint16_t ustackbase; + uint16_t ustacksize; +#if CONFIG_ARCH_INTERRUPTSTACK > 0 + uint16_t istackbase; + uint16_t istacksize; +#endif + + /* Get the limits on the user stack memory */ + + if (rtcb->pid == 0) + { + ustackbase = g_heapbase - 4; + ustacksize = CONFIG_IDLETHREAD_STACKSIZE; + } + else + { + ustackbase = (uint16_t)rtcb->adj_stack_ptr; + ustacksize = (uint16_t)rtcb->adj_stack_size; + } + + /* Get the limits on the interrupt stack memory */ + +#if CONFIG_ARCH_INTERRUPTSTACK > 3 + istackbase = (uint16_t)&g_intstackbase; + istacksize = (CONFIG_ARCH_INTERRUPTSTACK & ~3) - 4; + + /* Show interrupt stack info */ + + lldbg("sp: %04x\n", sp); + lldbg("IRQ stack:\n"); + lldbg(" base: %04x\n", istackbase); + lldbg(" size: %04x\n", istacksize); + + /* Does the current stack pointer lie within the interrupt + * stack? + */ + + if (sp <= istackbase && sp > istackbase - istacksize) + { + /* Yes.. dump the interrupt stack */ + + up_stackdump(sp, istackbase); + } + + /* Extract the user stack pointer if we are in an interrupt handler. + * If we are not in an interrupt handler. Then sp is the user stack + * pointer (and the above range check should have failed). + */ + + if (current_regs) + { + sp = current_regs[REG_R13]; + lldbg("sp: %04x\n", sp); + } + + lldbg("User stack:\n"); + lldbg(" base: %04x\n", ustackbase); + lldbg(" size: %04x\n", ustacksize); + + /* Dump the user stack if the stack pointer lies within the allocated user + * stack memory. + */ + + if (sp <= ustackbase && sp > ustackbase - ustacksize) + { + up_stackdump(sp, ustackbase); + } +#else + lldbg("sp: %04x\n", sp); + lldbg("stack base: %04x\n", ustackbase); + lldbg("stack size: %04x\n", ustacksize); + + /* Dump the user stack if the stack pointer lies within the allocated user + * stack memory. + */ + + if (sp > ustackbase || sp <= ustackbase - ustacksize) + { + lldbg("ERROR: Stack pointer is not within allocated stack\n"); + } + else + { + up_stackdump(sp, ustackbase); + } +#endif + + /* Then dump the registers (if available) */ + + up_registerdump(); +} +#endif diff --git a/arch/avr/src/avr/up_releasepending.c b/arch/avr/src/avr/up_releasepending.c new file mode 100755 index 00000000000..bd35379440a --- /dev/null +++ b/arch/avr/src/avr/up_releasepending.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * arch/avr/src/avr/up_releasepending.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "os_internal.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_release_pending + * + * Description: + * Release and ready-to-run tasks that have + * collected in the pending task list. This can call a + * context switch if a new task is placed at the head of + * the ready to run list. + * + ****************************************************************************/ + +void up_release_pending(void) +{ + _TCB *rtcb = (_TCB*)g_readytorun.head; + + slldbg("From TCB=%p\n", rtcb); + + /* Merge the g_pendingtasks list into the g_readytorun task list */ + + /* sched_lock(); */ + if (sched_mergepending()) + { + /* The currently active task has changed! We will need to + * switch contexts. First check if we are operating in + * interrupt context: + */ + + if (current_regs) + { + /* Yes, then we have to do things differently. + * Just copy the current_regs into the OLD rtcb. + */ + + up_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the g_readytorun task list. + */ + + rtcb = (_TCB*)g_readytorun.head; + slldbg("New Active Task TCB=%p\n", rtcb); + + /* Then switch contexts */ + + up_restorestate(rtcb->xcp.regs); + } + + /* No, then we will need to perform the user context switch */ + + else + { + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + _TCB *nexttcb = (_TCB*)g_readytorun.head; + up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ + } + } +} + diff --git a/arch/avr/src/avr/up_reprioritizertr.c b/arch/avr/src/avr/up_reprioritizertr.c new file mode 100755 index 00000000000..3983b3953ad --- /dev/null +++ b/arch/avr/src/avr/up_reprioritizertr.c @@ -0,0 +1,182 @@ +/**************************************************************************** + * arch/avr/src/avr/up_reprioritizertr.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "os_internal.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_reprioritize_rtr + * + * Description: + * Called when the priority of a running or + * ready-to-run task changes and the reprioritization will + * cause a context switch. Two cases: + * + * 1) The priority of the currently running task drops and the next + * task in the ready to run list has priority. + * 2) An idle, ready to run task's priority has been raised above the + * the priority of the current, running task and it now has the + * priority. + * + * Inputs: + * tcb: The TCB of the task that has been reprioritized + * priority: The new task priority + * + ****************************************************************************/ + +void up_reprioritize_rtr(_TCB *tcb, uint8_t priority) +{ + /* Verify that the caller is sane */ + + if (tcb->task_state < FIRST_READY_TO_RUN_STATE || + tcb->task_state > LAST_READY_TO_RUN_STATE || + priority < SCHED_PRIORITY_MIN || + priority > SCHED_PRIORITY_MAX) + { + PANIC(OSERR_BADREPRIORITIZESTATE); + } + else + { + _TCB *rtcb = (_TCB*)g_readytorun.head; + bool switch_needed; + + slldbg("TCB=%p PRI=%d\n", tcb, priority); + + /* Remove the tcb task from the ready-to-run list. + * sched_removereadytorun will return true if we just + * remove the head of the ready to run list. + */ + + switch_needed = sched_removereadytorun(tcb); + + /* Setup up the new task priority */ + + tcb->sched_priority = (uint8_t)priority; + + /* Return the task to the specified blocked task list. + * sched_addreadytorun will return true if the task was + * added to the new list. We will need to perform a context + * switch only if the EXCLUSIVE or of the two calls is non-zero + * (i.e., one and only one the calls changes the head of the + * ready-to-run list). + */ + + switch_needed ^= sched_addreadytorun(tcb); + + /* Now, perform the context switch if one is needed */ + + if (switch_needed) + { + /* If we are going to do a context switch, then now is the right + * time to add any pending tasks back into the ready-to-run list. + * task list now + */ + + if (g_pendingtasks.head) + { + sched_mergepending(); + } + + /* Are we in an interrupt handler? */ + + if (current_regs) + { + /* Yes, then we have to do things differently. + * Just copy the current_regs into the OLD rtcb. + */ + + up_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the g_readytorun task list. + */ + + rtcb = (_TCB*)g_readytorun.head; + slldbg("New Active Task TCB=%p\n", rtcb); + + /* Then switch contexts */ + + up_restorestate(rtcb->xcp.regs); + } + + /* No, then we will need to perform the user context switch */ + + else + { + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + _TCB *nexttcb = (_TCB*)g_readytorun.head; + up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ + } + } + } +} + diff --git a/arch/avr/src/avr/up_schedulesigaction.c b/arch/avr/src/avr/up_schedulesigaction.c new file mode 100644 index 00000000000..af9e917c6e3 --- /dev/null +++ b/arch/avr/src/avr/up_schedulesigaction.c @@ -0,0 +1,209 @@ +/**************************************************************************** + * arch/avr/src/avr/up_schedulesigaction.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "os_internal.h" +#include "up_internal.h" +#include "up_arch.h" + +#ifndef CONFIG_DISABLE_SIGNALS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_schedule_sigaction + * + * Description: + * This function is called by the OS when one or more + * signal handling actions have been queued for execution. + * The architecture specific code must configure things so + * that the 'igdeliver' callback is executed on the thread + * specified by 'tcb' as soon as possible. + * + * This function may be called from interrupt handling logic. + * + * This operation should not cause the task to be unblocked + * nor should it cause any immediate execution of sigdeliver. + * Typically, a few cases need to be considered: + * + * (1) This function may be called from an interrupt handler + * During interrupt processing, all xcptcontext structures + * should be valid for all tasks. That structure should + * be modified to invoke sigdeliver() either on return + * from (this) interrupt or on some subsequent context + * switch to the recipient task. + * (2) If not in an interrupt handler and the tcb is NOT + * the currently executing task, then again just modify + * the saved xcptcontext structure for the recipient + * task so it will invoke sigdeliver when that task is + * later resumed. + * (3) If not in an interrupt handler and the tcb IS the + * currently executing task -- just call the signal + * handler now. + * + ****************************************************************************/ + +void up_schedule_sigaction(_TCB *tcb, sig_deliver_t sigdeliver) +{ + /* Refuse to handle nested signal actions */ + + sdbg("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver); + + if (!tcb->xcp.sigdeliver) + { + irqstate_t flags; + + /* Make sure that interrupts are disabled */ + + flags = irqsave(); + + /* First, handle some special cases when the signal is + * being delivered to the currently executing task. + */ + + sdbg("rtcb=0x%p current_regs=0x%p\n", g_readytorun.head, current_regs); + + if (tcb == (_TCB*)g_readytorun.head) + { + /* CASE 1: We are not in an interrupt handler and + * a task is signalling itself for some reason. + */ + + if (!current_regs) + { + /* In this case just deliver the signal now. */ + + sigdeliver(tcb); + } + + /* CASE 2: We are in an interrupt handler AND the + * interrupted task is the same as the one that + * must receive the signal, then we will have to modify + * the return state as well as the state in the TCB. + * + * Hmmm... there looks like a latent bug here: The following + * logic would fail in the strange case where we are in an + * interrupt handler, the thread is signalling itself, but + * a context switch to another task has occurred so that + * current_regs does not refer to the thread at g_readytorun.head! + */ + + else + { + /* Save registers that must be protected while the signal handler + * runs. These will be restored by the signal trampoline after + * the signal(s) have been delivered. + */ + + tcb->xcp.sigdeliver = sigdeliver; + tcb->xcp.saved_pcl = current_regs[REG_PCL]; + tcb->xcp.saved_pch = current_regs[REG_PCH]; + tcb->xcp.saved_sreg = current_regs[REG_SREG]; + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + current_regs[REG_PCL] = (uint16_t)up_sigdeliver & 0xff; + current_regs[REG_PCH] = (uint16_t)up_sigdeliver >> 8; + current_regs[REG_SREG] |= (1 << SREG_I); + + /* And make sure that the saved context in the TCB + * is the same as the interrupt return context. + */ + + up_savestate(tcb->xcp.regs); + } + } + + /* Otherwise, we are (1) signaling a task is not running + * from an interrupt handler or (2) we are not in an + * interrupt handler and the running task is signalling + * some non-running task. + */ + + else + { + /* Save registers that must be protected while the signal handler + * runs. These will be restored by the signal trampoline after + * the signals have been delivered. + */ + + tcb->xcp.sigdeliver = sigdeliver; + tcb->xcp.saved_pcl = tcb->xcp.regs[REG_PCL]; + tcb->xcp.saved_pch = tcb->xcp.regs[REG_PCH]; + tcb->xcp.saved_sreg = tcb->xcp.regs[REG_SREG]; + + /* Then set up to vector to the trampoline with interrupts + * disabled + */ + + tcb->xcp.regs[REG_PCL] = (uint16_t)up_sigdeliver & 0xff; + tcb->xcp.regs[REG_PCH] = (uint16_t)up_sigdeliver >> 8; + tcb->xcp.regs[REG_SREG] |= (1 << SREG_I); + } + + irqrestore(flags); + } +} + +#endif /* !CONFIG_DISABLE_SIGNALS */ + diff --git a/arch/avr/src/avr/up_sigdeliver.c b/arch/avr/src/avr/up_sigdeliver.c new file mode 100644 index 00000000000..bef28341408 --- /dev/null +++ b/arch/avr/src/avr/up_sigdeliver.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * arch/avr/src/avr/up_sigdeliver.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "os_internal.h" +#include "up_internal.h" +#include "up_arch.h" + +#ifndef CONFIG_DISABLE_SIGNALS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_sigdeliver + * + * Description: + * This is the a signal handling trampoline. When a signal action was + * posted. The task context was mucked with and forced to branch to this + * location with interrupts disabled. + * + ****************************************************************************/ + +void up_sigdeliver(void) +{ + _TCB *rtcb = (_TCB*)g_readytorun.head; + uint8_t regs[XCPTCONTEXT_REGS]; + sig_deliver_t sigdeliver; + + /* Save the errno. This must be preserved throughout the signal handling + * so that the user code final gets the correct errno value (probably EINTR). + */ + + int saved_errno = rtcb->pterrno; + + up_ledon(LED_SIGNAL); + + sdbg("rtcb=%p sigdeliver=%p sigpendactionq.head=%p\n", + rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); + ASSERT(rtcb->xcp.sigdeliver != NULL); + + /* Save the real return state on the stack. */ + + up_copystate(regs, rtcb->xcp.regs); + regs[REG_PCL] = rtcb->xcp.saved_pcl; + regs[REG_PCH] = rtcb->xcp.saved_pch; + regs[REG_SREG] = rtcb->xcp.saved_sreg; + + /* Get a local copy of the sigdeliver function pointer. We do this so that + * we can nullify the sigdeliver function pointer in the TCB and accept + * more signal deliveries while processing the current pending signals. + */ + + sigdeliver = rtcb->xcp.sigdeliver; + rtcb->xcp.sigdeliver = NULL; + + /* Then restore the task interrupt state */ + + irqrestore(regs[REG_SREG]); + + /* Deliver the signals */ + + sigdeliver(rtcb); + + /* Output any debug messages BEFORE restoring errno (because they may + * alter errno), then disable interrupts again and restore the original + * errno that is needed by the user logic (it is probably EINTR). + */ + + sdbg("Resuming\n"); + (void)irqsave(); + rtcb->pterrno = saved_errno; + + /* Then restore the correct state for this thread of execution. This is an + * unusual case that must be handled by up_fullcontextresore. This case is + * unusal in two ways: + * + * 1. It is not a context switch between threads. Rather, up_fullcontextrestore + * must behave more it more like a longjmp within the same task, using + * he same stack. + * 2. In this case, up_fullcontextrestore is called with r12 pointing to + * a register save area on the stack to be destroyed. This is + * dangerous because there is the very real possibility that the new + * stack pointer might overlap with the register save area and hat stack + * usage in up_fullcontextrestore might corrupt the register save data + * before the state is restored. At present, there does not appear to + * be any stack overlap problems. If there were, then adding 3 words + * to the size of register save structure size will protect its contents. + */ + + up_ledoff(LED_SIGNAL); + up_fullcontextrestore(regs); +} + +#endif /* !CONFIG_DISABLE_SIGNALS */ + diff --git a/arch/avr/src/avr/up_switchcontext.S b/arch/avr/src/avr/up_switchcontext.S index b311734562d..18653d30519 100755 --- a/arch/avr/src/avr/up_switchcontext.S +++ b/arch/avr/src/avr/up_switchcontext.S @@ -129,6 +129,10 @@ up_fullcontextrestore: /* Restore the context from the TCB saved registers */ TCB_RESTORE + + /* And "return" to the new task. */ + + reti .endfunc .end diff --git a/arch/avr/src/avr/up_unblocktask.c b/arch/avr/src/avr/up_unblocktask.c new file mode 100755 index 00000000000..a55b81e2c78 --- /dev/null +++ b/arch/avr/src/avr/up_unblocktask.c @@ -0,0 +1,158 @@ +/**************************************************************************** + * arch/avr/src/avr/up_unblocktask.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "os_internal.h" +#include "clock_internal.h" +#include "up_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_unblock_task + * + * Description: + * A task is currently in an inactive task list + * but has been prepped to execute. Move the TCB to the + * ready-to-run list, restore its context, and start execution. + * + * Inputs: + * tcb: Refers to the tcb to be unblocked. This tcb is + * in one of the waiting tasks lists. It must be moved to + * the ready-to-run list and, if it is the highest priority + * ready to run taks, executed. + * + ****************************************************************************/ + +void up_unblock_task(_TCB *tcb) +{ + /* Verify that the context switch can be performed */ + + if ((tcb->task_state < FIRST_BLOCKED_STATE) || + (tcb->task_state > LAST_BLOCKED_STATE)) + { + PANIC(OSERR_BADUNBLOCKSTATE); + } + else + { + _TCB *rtcb = (_TCB*)g_readytorun.head; + + /* Remove the task from the blocked task list */ + + sched_removeblocked(tcb); + + /* Reset its timeslice. This is only meaningful for round + * robin tasks but it doesn't here to do it for everything + */ + +#if CONFIG_RR_INTERVAL > 0 + tcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK; +#endif + + /* Add the task in the correct location in the prioritized + * g_readytorun task list + */ + + if (sched_addreadytorun(tcb)) + { + /* The currently active task has changed! We need to do + * a context switch to the new task. + * + * Are we in an interrupt handler? + */ + + if (current_regs) + { + /* Yes, then we have to do things differently. + * Just copy the current_regs into the OLD rtcb. + */ + + up_savestate(rtcb->xcp.regs); + + /* Restore the exception context of the rtcb at the (new) head + * of the g_readytorun task list. + */ + + rtcb = (_TCB*)g_readytorun.head; + + /* Then switch contexts */ + + up_restorestate(rtcb->xcp.regs); + } + + /* No, then we will need to perform the user context switch */ + + else + { + /* Switch context to the context of the task at the head of the + * ready to run list. + */ + + _TCB *nexttcb = (_TCB*)g_readytorun.head; + up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + + /* up_switchcontext forces a context switch to the task at the + * head of the ready-to-run list. It does not 'return' in the + * normal sense. When it does return, it is because the blocked + * task is again ready to run and has execution priority. + */ + } + } + } +} + diff --git a/arch/avr/src/avr32/up_assert.c b/arch/avr/src/avr32/up_dumpstate.c similarity index 67% rename from arch/avr/src/avr32/up_assert.c rename to arch/avr/src/avr32/up_dumpstate.c index b335c71b296..71e35eea69e 100644 --- a/arch/avr/src/avr32/up_assert.c +++ b/arch/avr/src/avr32/up_dumpstate.c @@ -1,7 +1,7 @@ /**************************************************************************** - * arch/avr/src/avr32/up_assert.c + * arch/avr/src/avr32/up_dumpstate.c * - * Copyright (C) 2010 Gregory Nutt. All rights reserved. + * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -52,6 +52,8 @@ #include "os_internal.h" #include "up_internal.h" +#ifdef CONFIG_ARCH_STACKDUMP + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -60,23 +62,8 @@ * selected. */ -#ifdef CONFIG_ARCH_STACKDUMP -# undef lldbg -# define lldbg lib_lowprintf -#endif - -/* The following is just intended to keep some ugliness out of the mainline - * code. We are going to print the task name if: - * - * CONFIG_TASK_NAME_SIZE > 0 && <-- The task has a name - * (defined(CONFIG_DEBUG) || <-- And the debug is enabled (lldbg used) - * defined(CONFIG_ARCH_STACKDUMP)) <-- Or lib_lowprintf() is used - */ - -#undef CONFIG_PRINT_TASKNAME -#if CONFIG_TASK_NAME_SIZE > 0 && (defined(CONFIG_DEBUG) || defined(CONFIG_ARCH_STACKDUMP)) -# define CONFIG_PRINT_TASKNAME 1 -#endif +#undef lldbg +#define lldbg lib_lowprintf /**************************************************************************** * Private Data @@ -107,7 +94,6 @@ static inline uint32_t up_getsp(void) * Name: up_stackdump ****************************************************************************/ -#ifdef CONFIG_ARCH_STACKDUMP static void up_stackdump(uint32_t sp, uint32_t stack_base) { uint32_t stack ; @@ -120,15 +106,11 @@ static void up_stackdump(uint32_t sp, uint32_t stack_base) ptr[4], ptr[5], ptr[6], ptr[7]); } } -#else -# define up_stackdump() -#endif /**************************************************************************** * Name: up_registerdump ****************************************************************************/ -#ifdef CONFIG_ARCH_STACKDUMP static inline void up_registerdump(void) { /* Are user registers available from interrupt processing? */ @@ -136,32 +118,32 @@ static inline void up_registerdump(void) if (current_regs) { lldbg("R%d: %08x %08x %08x %08x %08x %08x %08x %08x\n", - 0, - current_regs[REG_R0], current_regs[REG_R1], - current_regs[REG_R2], current_regs[REG_R3], - current_regs[REG_R4], current_regs[REG_R5], - current_regs[REG_R6], current_regs[REG_R7]); + 0, + current_regs[REG_R0], current_regs[REG_R1], + current_regs[REG_R2], current_regs[REG_R3], + current_regs[REG_R4], current_regs[REG_R5], + current_regs[REG_R6], current_regs[REG_R7]); lldbg("R%d: %08x %08x %08x %08x %08x %08x %08x %08x\n", - 8, - current_regs[REG_R8], current_regs[REG_R9], - current_regs[REG_R10], current_regs[REG_R11], - current_regs[REG_R12], current_regs[REG_R13], - current_regs[REG_R14], current_regs[REG_R15]); + 8, + current_regs[REG_R8], current_regs[REG_R9], + current_regs[REG_R10], current_regs[REG_R11], + current_regs[REG_R12], current_regs[REG_R13], + current_regs[REG_R14], current_regs[REG_R15]); lldbg("SR: %08x\n", current_regs[REG_SR]); } } -#else -# define up_registerdump() -#endif + +/**************************************************************************** + * Name: _up_assert + ****************************************************************************/ /**************************************************************************** * Name: up_dumpstate ****************************************************************************/ -#ifdef CONFIG_ARCH_STACKDUMP -static void up_dumpstate(void) +void up_dumpstate(void) { _TCB *rtcb = (_TCB*)g_readytorun.head; uint32_t sp = up_getsp(); @@ -255,82 +237,4 @@ static void up_dumpstate(void) up_registerdump(); } -#else -# define up_dumpstate() #endif - -/**************************************************************************** - * Name: _up_assert - ****************************************************************************/ - -static void _up_assert(int errorcode) /* __attribute__ ((noreturn)) */ -{ - /* Are we in an interrupt handler or the idle task? */ - - if (current_regs || ((_TCB*)g_readytorun.head)->pid == 0) - { - (void)irqsave(); - for(;;) - { -#ifdef CONFIG_ARCH_LEDS - up_ledon(LED_PANIC); - up_mdelay(250); - up_ledoff(LED_PANIC); - up_mdelay(250); -#endif - } - } - else - { - exit(errorcode); - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_assert - ****************************************************************************/ - -void up_assert(const uint8_t *filename, int lineno) -{ -#ifdef CONFIG_PRINT_TASKNAME - _TCB *rtcb = (_TCB*)g_readytorun.head; -#endif - - up_ledon(LED_ASSERTION); -#ifdef CONFIG_PRINT_TASKNAME - lldbg("Assertion failed at file:%s line: %d task: %s\n", - filename, lineno, rtcb->name); -#else - lldbg("Assertion failed at file:%s line: %d\n", - filename, lineno); -#endif - up_dumpstate(); - _up_assert(EXIT_FAILURE); -} - -/**************************************************************************** - * Name: up_assert_code - ****************************************************************************/ - -void up_assert_code(const uint8_t *filename, int lineno, int errorcode) -{ -#ifdef CONFIG_PRINT_TASKNAME - _TCB *rtcb = (_TCB*)g_readytorun.head; -#endif - - up_ledon(LED_ASSERTION); -#ifdef CONFIG_PRINT_TASKNAME - lldbg("Assertion failed at file:%s line: %d task: %s error code: %d\n", - filename, lineno, rtcb->name, errorcode); -#else - lldbg("Assertion failed at file:%s line: %d error code: %d\n", - filename, lineno, errorcode); -#endif - up_dumpstate(); - _up_assert(errorcode); -} - diff --git a/arch/avr/src/common/up_internal.h b/arch/avr/src/common/up_internal.h index c388b615329..e65b5627d94 100644 --- a/arch/avr/src/common/up_internal.h +++ b/arch/avr/src/common/up_internal.h @@ -136,6 +136,7 @@ extern int up_timerisr(int irq, uint32_t *regs); extern void up_lowputc(char ch); extern void up_puts(const char *str); extern void up_lowputs(const char *str); +extern void up_dumpstate(void); /* Defined in common/up_allocateheap.c or chip/xxx_allocateheap.c */