mirror of
https://github.com/apache/nuttx.git
synced 2026-06-06 08:36:24 +08:00
More AVR context switching logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3683 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
@@ -89,9 +89,14 @@
|
|||||||
#define REG_R0 33 /* r0 */
|
#define REG_R0 33 /* r0 */
|
||||||
#define REG_R24 34 /* r24 */
|
#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) */
|
/* Size of the register state save array (in bytes) */
|
||||||
|
|
||||||
#define XCPTCONTEXT_REGS 35
|
#define XCPTCONTEXT_REGS 37
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Types
|
* Public Types
|
||||||
@@ -111,8 +116,9 @@ struct xcptcontext
|
|||||||
|
|
||||||
/* These are saved copies of PC and SR used during signal processing.*/
|
/* These are saved copies of PC and SR used during signal processing.*/
|
||||||
|
|
||||||
uint16_t saved_pc;
|
uint8_t saved_pcl;
|
||||||
uint8_t saved_sr;
|
uint8_t saved_pch;
|
||||||
|
uint8_t saved_sreg;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Register save area */
|
/* Register save area */
|
||||||
|
|||||||
@@ -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_schedulesigaction.c up_sigdeliver.c up_unblocktask.c \
|
||||||
up_usestack.c up_doirq.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
|
# Required AT32UC3 files
|
||||||
|
|
||||||
CHIP_ASRCS =
|
CHIP_ASRCS =
|
||||||
|
|||||||
@@ -40,12 +40,20 @@ HEAD_ASRC = at90usb_head.S
|
|||||||
# Common AVR files
|
# Common AVR files
|
||||||
|
|
||||||
CMN_ASRCS = up_switchcontext.S
|
CMN_ASRCS = up_switchcontext.S
|
||||||
CMN_CSRCS = up_allocateheap.c up_copystate.c up_createstack.c up_exit.c \
|
CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
|
||||||
up_idle.c up_initialize.c up_interruptcontext.c up_lowputs.c \
|
up_createstack.c up_doirq.c up_exit.c up_idle.c up_initialize.c \
|
||||||
up_mdelay.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \
|
up_interruptcontext.c up_lowputs.c up_mdelay.c up_modifyreg8.c \
|
||||||
up_puts.c up_releasestack.c up_udelay.c up_usestack.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_ASRCS = at90usb_exceptions.S
|
||||||
CHIP_CSRCS =
|
CHIP_CSRCS =
|
||||||
|
|||||||
@@ -64,43 +64,43 @@
|
|||||||
|
|
||||||
.section .handlers, "ax", @progbits
|
.section .handlers, "ax", @progbits
|
||||||
|
|
||||||
HANDLER at90usb_int0, ATMEGA_IRQ_INT0, excpt_common /* External interrupt request 0 */
|
HANDLER at90usb_int0, AT90USB_IRQ_INT0, excpt_common /* External interrupt request 0 */
|
||||||
HANDLER at90usb_int1, ATMEGA_IRQ_INT1, excpt_common /* External interrupt request 1 */
|
HANDLER at90usb_int1, AT90USB_IRQ_INT1, excpt_common /* External interrupt request 1 */
|
||||||
HANDLER at90usb_int2, ATMEGA_IRQ_INT2, excpt_common /* External interrupt request 2 */
|
HANDLER at90usb_int2, AT90USB_IRQ_INT2, excpt_common /* External interrupt request 2 */
|
||||||
HANDLER at90usb_int3, ATMEGA_IRQ_INT3, excpt_common /* External interrupt request 3 */
|
HANDLER at90usb_int3, AT90USB_IRQ_INT3, excpt_common /* External interrupt request 3 */
|
||||||
HANDLER at90usb_int4, ATMEGA_IRQ_INT4, excpt_common /* External interrupt request 4 */
|
HANDLER at90usb_int4, AT90USB_IRQ_INT4, excpt_common /* External interrupt request 4 */
|
||||||
HANDLER at90usb_int5, ATMEGA_IRQ_INT5, excpt_common /* External interrupt request 5 */
|
HANDLER at90usb_int5, AT90USB_IRQ_INT5, excpt_common /* External interrupt request 5 */
|
||||||
HANDLER at90usb_int6, ATMEGA_IRQ_INT6, excpt_common /* External interrupt request 6 */
|
HANDLER at90usb_int6, AT90USB_IRQ_INT6, excpt_common /* External interrupt request 6 */
|
||||||
HANDLER at90usb_int7, ATMEGA_IRQ_INT7, excpt_common /* External interrupt request 7 */
|
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_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_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_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_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_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_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_t2ovf, AT90USB_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_t1capt, AT90USB_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_t1compa, AT90USB_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_t1compb, AT90USB_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_t1compc, AT90USB_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_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_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_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_t0ovf, AT90USB_IRQ_T0OVF, excpt_common /* TIMER0 OVF timer/counter0 overflow */
|
||||||
HANDLER at90usb_spi, ATMEGA_IRQ_SPI, excpt_common /* STC SPI serial transfer complete */
|
HANDLER at90usb_spi, AT90USB_IRQ_SPI, excpt_common /* STC SPI serial transfer complete */
|
||||||
HANDLER at90usb_u1rx, ATMEGA_IRQ_U1RX, excpt_common /* USART1 RX complete */
|
HANDLER at90usb_u1rx, AT90USB_IRQ_U1RX, excpt_common /* USART1 RX complete */
|
||||||
HANDLER at90usb_u1dre, ATMEGA_IRQ_U1DRE, excpt_common /* USART1 data register empty */
|
HANDLER at90usb_u1dre, AT90USB_IRQ_U1DRE, excpt_common /* USART1 data register empty */
|
||||||
HANDLER at90usb_u1tx, ATMEGA_IRQ_U1TX, excpt_common /* USART1 TX complete */
|
HANDLER at90usb_u1tx, AT90USB_IRQ_U1TX, excpt_common /* USART1 TX complete */
|
||||||
HANDLER at90usb_anacomp, ATMEGA_IRQ_ANACOMP, excpt_common /* ANALOG COMP analog comparator */
|
HANDLER at90usb_anacomp, AT90USB_IRQ_ANACOMP, excpt_common /* ANALOG COMP analog comparator */
|
||||||
HANDLER at90usb_adc, ATMEGA_IRQ_ADC, excpt_common /* ADC conversion complete */
|
HANDLER at90usb_adc, AT90USB_IRQ_ADC, excpt_common /* ADC conversion complete */
|
||||||
HANDLER at90usb_ee, ATMEGA_IRQ_EE, excpt_common /* EEPROM ready */
|
HANDLER at90usb_ee, AT90USB_IRQ_EE, excpt_common /* EEPROM ready */
|
||||||
HANDLER at90usb_t3capt, ATMEGA_IRQ_T3CAPT, excpt_common /* TIMER3 CAPT timer/counter3 capture event */
|
HANDLER at90usb_t3capt, AT90USB_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_t3compa, AT90USB_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_t3compb, AT90USB_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_t3compc, AT90USB_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_t3ovf, AT90USB_IRQ_T3OVF, excpt_common /* TIMER3 OVF timer/counter3 overflow */
|
||||||
HANDLER at90usb_twi, ATMEGA_IRQ_TWI, excpt_common /* TWI two-wire serial interface */
|
HANDLER at90usb_twi, AT90USB_IRQ_TWI, excpt_common /* TWI two-wire serial interface */
|
||||||
HANDLER at90usb_spmrdy, ATMEGA_IRQ_SPMRDY, excpt_common /* Store program memory ready */
|
HANDLER at90usb_spmrdy, AT90USB_IRQ_SPMRDY, excpt_common /* Store program memory ready */
|
||||||
|
|
||||||
/* Common exception handling logic. */
|
/* Common exception handling logic. */
|
||||||
|
|
||||||
|
|||||||
@@ -193,6 +193,9 @@ __start:
|
|||||||
|
|
||||||
/* Copy initial global data values from FLASH into RAM */
|
/* 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
|
#ifdef HAVE_RAMPZ
|
||||||
ldi r17, hi8(_edata)
|
ldi r17, hi8(_edata)
|
||||||
ldi r26, lo8(_sdata)
|
ldi r26, lo8(_sdata)
|
||||||
@@ -230,6 +233,9 @@ __start:
|
|||||||
|
|
||||||
/* Clear uninitialized data */
|
/* Clear uninitialized data */
|
||||||
|
|
||||||
|
.global __do_clear_bss; /* Required to suppress dragging in logic from libgcc */
|
||||||
|
__do_clear_bss:
|
||||||
|
|
||||||
ldi r17, hi8(_ebss)
|
ldi r17, hi8(_ebss)
|
||||||
ldi r26, lo8(_sbss)
|
ldi r26, lo8(_sbss)
|
||||||
ldi r27, hi8(_sbss)
|
ldi r27, hi8(_sbss)
|
||||||
|
|||||||
@@ -40,10 +40,18 @@ HEAD_ASRC = atmega_head.S
|
|||||||
# Common AVR files
|
# Common AVR files
|
||||||
|
|
||||||
CMN_ASRCS = up_switchcontext.S
|
CMN_ASRCS = up_switchcontext.S
|
||||||
CMN_CSRCS = up_allocateheap.c up_copystate.c up_createstack.c up_exit.c \
|
CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
|
||||||
up_idle.c up_initialize.c up_interruptcontext.c up_lowputs.c \
|
up_createstack.c up_doirq.c up_exit.c up_idle.c up_initialize.c \
|
||||||
up_mdelay.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \
|
up_interruptcontext.c up_lowputs.c up_mdelay.c up_modifyreg8.c \
|
||||||
up_puts.c up_releasestack.c up_udelay.c up_usestack.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
|
# Required ATMEGA files
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
#include <nuttx/config.h>
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <arch/irq.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <avr/sfr_defs.h>
|
#include <avr/sfr_defs.h>
|
||||||
|
|
||||||
@@ -186,6 +187,9 @@ __start:
|
|||||||
|
|
||||||
/* Copy initial global data values from FLASH into RAM */
|
/* 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
|
#ifdef HAVE_RAMPZ
|
||||||
ldi r17, hi8(_edata)
|
ldi r17, hi8(_edata)
|
||||||
ldi r26, lo8(_sdata)
|
ldi r26, lo8(_sdata)
|
||||||
@@ -223,6 +227,9 @@ __start:
|
|||||||
|
|
||||||
/* Clear uninitialized data */
|
/* Clear uninitialized data */
|
||||||
|
|
||||||
|
.global __do_clear_bss; /* Required to suppress dragging in logic from libgcc */
|
||||||
|
__do_clear_bss:
|
||||||
|
|
||||||
ldi r17, hi8(_ebss)
|
ldi r17, hi8(_ebss)
|
||||||
ldi r26, lo8(_sbss)
|
ldi r26, lo8(_sbss)
|
||||||
ldi r27, hi8(_sbss)
|
ldi r27, hi8(_sbss)
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ extern void up_copystate(uint8_t *dest, uint8_t *src);
|
|||||||
extern int up_saveusercontext(uint8_t *saveregs);
|
extern int up_saveusercontext(uint8_t *saveregs);
|
||||||
extern void up_fullcontextrestore(uint8_t *restoreregs) __attribute__ ((noreturn));
|
extern void up_fullcontextrestore(uint8_t *restoreregs) __attribute__ ((noreturn));
|
||||||
extern void up_switchcontext(uint8_t *saveregs, uint8_t *restoreregs);
|
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 /* __ASSEMBLY__ */
|
||||||
#endif /* __ARCH_AVR_SRC_AVR_AVR_INTERNAL_H */
|
#endif /* __ARCH_AVR_SRC_AVR_AVR_INTERNAL_H */
|
||||||
|
|||||||
+102
-59
@@ -1,22 +1,22 @@
|
|||||||
/********************************************************************************************
|
/********************************************************************************************
|
||||||
* arch/avr/src/avr/excptmacros.h
|
* arch/avr/src/avr/excptmacros.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
*
|
*
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
* 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
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in
|
* notice, this list of conditions and the following disclaimer in
|
||||||
* the documentation and/or other materials provided with the
|
* the documentation and/or other materials provided with the
|
||||||
* distribution.
|
* distribution.
|
||||||
* 3. Neither the name NuttX nor the names of its contributors may be
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||||||
* used to endorse or promote products derived from this software
|
* used to endorse or promote products derived from this software
|
||||||
* without specific prior written permission.
|
* without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
* "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
|
* RESTORE_STACK rx, ry - Undo the operations of USE_STACK
|
||||||
*
|
*
|
||||||
* EXCPT_EPILOGUE - Return to the context returned by handler()
|
* EXCPT_EPILOGUE - Return to the context returned by handler()
|
||||||
|
* reti - Return from interrupt
|
||||||
*
|
*
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
/****************************************************************************
|
|
||||||
* Macros
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/********************************************************************************************
|
/********************************************************************************************
|
||||||
* Name: HANDLER
|
* Name: HANDLER
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* This macro provides the exception entry logic. It simply saves one register on the
|
* This macro provides the exception entry logic. It is called with the PC already on the
|
||||||
* stack (r24) and passes the IRQ number to to common logic (see EXCPT_PROLOGUE).
|
* stack. It simply saves one register on the stack (r24) and passes the IRQ number to
|
||||||
|
* common logic (see EXCPT_PROLOGUE).
|
||||||
*
|
*
|
||||||
* On Entry:
|
* On Entry:
|
||||||
* sp - Points to the top of the stack
|
* sp - Points to the top of the stack. The PC is already on the stack.
|
||||||
* Only the stack is available for storage
|
* Only the stack is available for storage
|
||||||
|
*
|
||||||
|
* PCL
|
||||||
|
* PCH
|
||||||
|
* --- <- SP
|
||||||
*
|
*
|
||||||
* At completion:
|
* At completion:
|
||||||
* Stack pointer is incremented by one, the saved r24 is on the stack, r24 now contains the
|
* Stack pointer is incremented by one, the saved r24 is on the stack, r24 now contains the
|
||||||
* IRQ number
|
* IRQ number
|
||||||
|
*
|
||||||
|
* PCL
|
||||||
|
* PCH
|
||||||
|
* R0
|
||||||
|
* --- <- SP
|
||||||
*
|
*
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
|
|
||||||
.macro HANDLER, label, irqno, common
|
.macro HANDLER, label, irqno, common
|
||||||
|
.global \label
|
||||||
\label:
|
\label:
|
||||||
push r24
|
push r24
|
||||||
ldi r24, \irqno
|
ldi r24, \irqno
|
||||||
@@ -138,20 +147,26 @@
|
|||||||
* Name: EXCPT_PROLOGUE
|
* Name: EXCPT_PROLOGUE
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Provides the common "prologue" logic that should appear at the beginning of the exception
|
* Provides the common "prologue" logic that should appear at the beginning of the exception
|
||||||
* handler.
|
* handler.
|
||||||
*
|
*
|
||||||
* On Entry:
|
* On Entry:
|
||||||
* r0 - has already been pushed onto the stack and now holds the IRQ number
|
* r0 - has already been pushed onto the stack and now holds the IRQ number
|
||||||
* sp - Points to the top of the stack
|
* sp - Points to the top of the stack
|
||||||
* Only the stack is available for storage
|
* Only the stack is available for storage
|
||||||
|
*
|
||||||
|
* PCL
|
||||||
|
* PCH
|
||||||
|
* R0
|
||||||
|
* --- <- SP
|
||||||
*
|
*
|
||||||
* At completion:
|
* 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
|
.macro EXCPT_PROLOGUE
|
||||||
|
|
||||||
/* Save R1 - The zero register (but might not be zero) */
|
/* Save R1 - The zero register (but might not be zero) */
|
||||||
|
|
||||||
push r1
|
push r1
|
||||||
@@ -228,15 +243,16 @@
|
|||||||
* Name: EXCPT_EPILOGUE
|
* Name: EXCPT_EPILOGUE
|
||||||
*
|
*
|
||||||
* Description:
|
* 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:
|
* On input:
|
||||||
* sp points to the address of the register save area (just as left by EXCPT_PROLOGUE).
|
* sp points to the address of the register save area (just as left by EXCPT_PROLOGUE).
|
||||||
* All registers are available for use.
|
* All registers are available for use.
|
||||||
* Interrupts are disabled.
|
* Interrupts are disabled.
|
||||||
*
|
*
|
||||||
* On completion:
|
* 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
|
* Name: USER_SAVE
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Similar to EXPCT_PROLOGUE except that (1) this saves values into a register save
|
* 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)
|
* data structure instead of on the stack, (2) the pointer is in r26;r27, and (3)
|
||||||
* Call-used registers are not saved.
|
* Call-used registers are not saved.
|
||||||
*
|
*
|
||||||
* On Entry:
|
* On Entry:
|
||||||
* X [r26:r27] - Points to the register save structure.
|
* X [r26:r27] - Points to the register save structure.
|
||||||
* Interrupts are disabled.
|
* Return address is already on the stack (due to CALL or RCALL instruction)/.
|
||||||
|
* Interrupts are disabled.
|
||||||
*
|
*
|
||||||
* At completion:
|
* 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
|
st x+, r0
|
||||||
|
|
||||||
/* Skip R0 and r24 - These are scratch register and Call-used, "volatile" registers */
|
/* 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
|
.endm
|
||||||
|
|
||||||
/********************************************************************************************
|
/********************************************************************************************
|
||||||
* Name: TCB_RESTORE
|
* Name: TCB_RESTORE
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Functionally equivalent to EXCPT_EPILOGUE excetp that register save area is not on the
|
* Functionally equivalent to EXCPT_EPILOGUE excetp that register save area is not on the
|
||||||
* stack but is held in a data structure.
|
* stack but is held in a data structure.
|
||||||
*
|
*
|
||||||
* On input:
|
* On input:
|
||||||
* X [r26:r27] points to the data structure.
|
* X [r26:r27] points to the data structure.
|
||||||
* All registers are available for use.
|
* All registers are available for use.
|
||||||
* Interrupts are disabled.
|
* Interrupts are disabled.
|
||||||
*
|
*
|
||||||
* On completion:
|
* 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
|
.macro TCB_RESTORE, regs
|
||||||
|
|
||||||
/* Fetch the new stack pointer and the saved values of X [r26:r27]. Save X on the new
|
/* Fetch the new stack pointer */
|
||||||
* stack where we can recover it later.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ld r24, x+ /* Fetch stack pointer (post-incrementing) */
|
ld r24, x+ /* Fetch stack pointer (post-incrementing) */
|
||||||
out __SP_L__, r24
|
out __SP_L__, r24
|
||||||
ld r25, x+
|
ld r25, x+
|
||||||
out __SP_H__, r25
|
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 r25, x+ /* Fetch r26-r27 and save to the new stack */
|
||||||
ld r24, x+
|
ld r24, x+
|
||||||
push r24
|
push r24
|
||||||
@@ -466,7 +507,9 @@
|
|||||||
ld r0, x+
|
ld r0, x+
|
||||||
ld r24, 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 r27
|
||||||
pop r26
|
pop r26
|
||||||
@@ -476,18 +519,18 @@
|
|||||||
* Name: USE_INTSTACK
|
* Name: USE_INTSTACK
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Switch to the interrupt stack (if enabled in the configuration) and if the nesting level
|
* 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.
|
* is equal to 0. Increment the nesting level in any event.
|
||||||
*
|
*
|
||||||
* On Entry:
|
* On Entry:
|
||||||
* sp - Current value of the user stack pointer
|
* sp - Current value of the user stack pointer
|
||||||
* tmp1, tmp2, and tmp3 are registers that can be used temporarily.
|
* tmp1, tmp2, and tmp3 are registers that can be used temporarily.
|
||||||
* All interrupts should still be disabled.
|
* All interrupts should still be disabled.
|
||||||
*
|
*
|
||||||
* At completion:
|
* At completion:
|
||||||
* If the nesting level is 0, then (1) the user stack pointer is saved at the base of the
|
* 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.
|
* interrupt stack and sp points to the interrupt stack.
|
||||||
* The values of tmp1, tmp2, tmp3, and sp have been altered
|
* The values of tmp1, tmp2, tmp3, and sp have been altered
|
||||||
*
|
*
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
|
|
||||||
@@ -501,16 +544,16 @@
|
|||||||
* Name: RESTORE_STACK
|
* Name: RESTORE_STACK
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Restore the user stack. Not really.. actually only decrements the nesting level. We
|
* Restore the user stack. Not really.. actually only decrements the nesting level. We
|
||||||
* always get the new stack pointer for the register save array.
|
* always get the new stack pointer for the register save array.
|
||||||
*
|
*
|
||||||
* On Entry:
|
* On Entry:
|
||||||
* tmp1 and tmp2 are registers that can be used temporarily.
|
* tmp1 and tmp2 are registers that can be used temporarily.
|
||||||
* All interrupts must be disabled.
|
* All interrupts must be disabled.
|
||||||
*
|
*
|
||||||
* At completion:
|
* At completion:
|
||||||
* Current nesting level is decremented
|
* Current nesting level is decremented
|
||||||
* The values of tmp1 and tmp2 have been altered
|
* The values of tmp1 and tmp2 have been altered
|
||||||
*
|
*
|
||||||
********************************************************************************************/
|
********************************************************************************************/
|
||||||
|
|
||||||
|
|||||||
Executable
+168
@@ -0,0 +1,168 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/avr/src/avr/up_blocktask.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
|
||||||
|
#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.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/avr/src/avr/up_doirq.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/avr/src/avr/up_dumpstate.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#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
|
||||||
Executable
+131
@@ -0,0 +1,131 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/avr/src/avr/up_releasepending.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
|
||||||
|
#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.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Executable
+182
@@ -0,0 +1,182 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/avr/src/avr/up_reprioritizertr.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
|
||||||
|
#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.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/avr/src/avr/up_schedulesigaction.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/avr/src/avr/up_sigdeliver.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/irq.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
|
#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 */
|
||||||
|
|
||||||
@@ -129,6 +129,10 @@ up_fullcontextrestore:
|
|||||||
/* Restore the context from the TCB saved registers */
|
/* Restore the context from the TCB saved registers */
|
||||||
|
|
||||||
TCB_RESTORE
|
TCB_RESTORE
|
||||||
|
|
||||||
|
/* And "return" to the new task. */
|
||||||
|
|
||||||
|
reti
|
||||||
.endfunc
|
.endfunc
|
||||||
.end
|
.end
|
||||||
|
|
||||||
|
|||||||
Executable
+158
@@ -0,0 +1,158 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/avr/src/avr/up_unblocktask.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
|
*
|
||||||
|
* 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 <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
|
#include <debug.h>
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
|
||||||
|
#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.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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 <spudmonkey@racsa.co.cr>
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -52,6 +52,8 @@
|
|||||||
#include "os_internal.h"
|
#include "os_internal.h"
|
||||||
#include "up_internal.h"
|
#include "up_internal.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARCH_STACKDUMP
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -60,23 +62,8 @@
|
|||||||
* selected.
|
* selected.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_STACKDUMP
|
#undef lldbg
|
||||||
# undef lldbg
|
#define lldbg lib_lowprintf
|
||||||
# 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
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
@@ -107,7 +94,6 @@ static inline uint32_t up_getsp(void)
|
|||||||
* Name: up_stackdump
|
* Name: up_stackdump
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_STACKDUMP
|
|
||||||
static void up_stackdump(uint32_t sp, uint32_t stack_base)
|
static void up_stackdump(uint32_t sp, uint32_t stack_base)
|
||||||
{
|
{
|
||||||
uint32_t stack ;
|
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]);
|
ptr[4], ptr[5], ptr[6], ptr[7]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
# define up_stackdump()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: up_registerdump
|
* Name: up_registerdump
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_STACKDUMP
|
|
||||||
static inline void up_registerdump(void)
|
static inline void up_registerdump(void)
|
||||||
{
|
{
|
||||||
/* Are user registers available from interrupt processing? */
|
/* Are user registers available from interrupt processing? */
|
||||||
@@ -136,32 +118,32 @@ static inline void up_registerdump(void)
|
|||||||
if (current_regs)
|
if (current_regs)
|
||||||
{
|
{
|
||||||
lldbg("R%d: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
lldbg("R%d: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||||
0,
|
0,
|
||||||
current_regs[REG_R0], current_regs[REG_R1],
|
current_regs[REG_R0], current_regs[REG_R1],
|
||||||
current_regs[REG_R2], current_regs[REG_R3],
|
current_regs[REG_R2], current_regs[REG_R3],
|
||||||
current_regs[REG_R4], current_regs[REG_R5],
|
current_regs[REG_R4], current_regs[REG_R5],
|
||||||
current_regs[REG_R6], current_regs[REG_R7]);
|
current_regs[REG_R6], current_regs[REG_R7]);
|
||||||
|
|
||||||
lldbg("R%d: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
lldbg("R%d: %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||||
8,
|
8,
|
||||||
current_regs[REG_R8], current_regs[REG_R9],
|
current_regs[REG_R8], current_regs[REG_R9],
|
||||||
current_regs[REG_R10], current_regs[REG_R11],
|
current_regs[REG_R10], current_regs[REG_R11],
|
||||||
current_regs[REG_R12], current_regs[REG_R13],
|
current_regs[REG_R12], current_regs[REG_R13],
|
||||||
current_regs[REG_R14], current_regs[REG_R15]);
|
current_regs[REG_R14], current_regs[REG_R15]);
|
||||||
|
|
||||||
lldbg("SR: %08x\n", current_regs[REG_SR]);
|
lldbg("SR: %08x\n", current_regs[REG_SR]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
# define up_registerdump()
|
/****************************************************************************
|
||||||
#endif
|
* Name: _up_assert
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: up_dumpstate
|
* Name: up_dumpstate
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_ARCH_STACKDUMP
|
void up_dumpstate(void)
|
||||||
static void up_dumpstate(void)
|
|
||||||
{
|
{
|
||||||
_TCB *rtcb = (_TCB*)g_readytorun.head;
|
_TCB *rtcb = (_TCB*)g_readytorun.head;
|
||||||
uint32_t sp = up_getsp();
|
uint32_t sp = up_getsp();
|
||||||
@@ -255,82 +237,4 @@ static void up_dumpstate(void)
|
|||||||
|
|
||||||
up_registerdump();
|
up_registerdump();
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
# define up_dumpstate()
|
|
||||||
#endif
|
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -136,6 +136,7 @@ extern int up_timerisr(int irq, uint32_t *regs);
|
|||||||
extern void up_lowputc(char ch);
|
extern void up_lowputc(char ch);
|
||||||
extern void up_puts(const char *str);
|
extern void up_puts(const char *str);
|
||||||
extern void up_lowputs(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 */
|
/* Defined in common/up_allocateheap.c or chip/xxx_allocateheap.c */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user