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:
patacongo 2011-06-08 18:10:55 +00:00
parent afbfd492af
commit 9801377f7d
20 changed files with 1592 additions and 218 deletions

View File

@ -89,9 +89,14 @@
#define REG_R0 33 /* r0 */
#define REG_R24 34 /* r24 */
/* The program counter is automatically pushed when the interrupt occurs */
#define REG_PCH 35 /* PC */
#define REG_PCL 36
/* Size of the register state save array (in bytes) */
#define XCPTCONTEXT_REGS 35
#define XCPTCONTEXT_REGS 37
/****************************************************************************
* Public Types
@ -111,8 +116,9 @@ struct xcptcontext
/* These are saved copies of PC and SR used during signal processing.*/
uint16_t saved_pc;
uint8_t saved_sr;
uint8_t saved_pcl;
uint8_t saved_pch;
uint8_t saved_sreg;
#endif
/* Register save area */

View File

@ -48,6 +48,12 @@ CMN_CSRCS = up_assert.c up_allocateheap.c up_blocktask.c up_copystate.c \
up_schedulesigaction.c up_sigdeliver.c up_unblocktask.c \
up_usestack.c up_doirq.c
# Configuration-dependent common files
ifeq ($(CONFIG_ARCH_STACKDUMP),y)
CMN_CSRCS += up_dumpstate.c
endif
# Required AT32UC3 files
CHIP_ASRCS =

View File

@ -40,12 +40,20 @@ HEAD_ASRC = at90usb_head.S
# Common AVR files
CMN_ASRCS = up_switchcontext.S
CMN_CSRCS = up_allocateheap.c up_copystate.c up_createstack.c up_exit.c \
up_idle.c up_initialize.c up_interruptcontext.c up_lowputs.c \
up_mdelay.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \
up_puts.c up_releasestack.c up_udelay.c up_usestack.c
CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
up_createstack.c up_doirq.c up_exit.c up_idle.c up_initialize.c \
up_interruptcontext.c up_lowputs.c up_mdelay.c up_modifyreg8.c \
up_modifyreg16.c up_modifyreg32.c up_puts.c up_releasepending.c \
up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \
up_sigdeliver.c up_udelay.c up_unblocktask.c up_usestack.c
# Required aT90USB files
# Configuration-dependent common files
ifeq ($(CONFIG_ARCH_STACKDUMP),y)
CMN_CSRCS += up_dumpstate.c
endif
# Required AT90USB files
CHIP_ASRCS = at90usb_exceptions.S
CHIP_CSRCS =

View File

@ -64,43 +64,43 @@
.section .handlers, "ax", @progbits
HANDLER at90usb_int0, ATMEGA_IRQ_INT0, excpt_common /* External interrupt request 0 */
HANDLER at90usb_int1, ATMEGA_IRQ_INT1, excpt_common /* External interrupt request 1 */
HANDLER at90usb_int2, ATMEGA_IRQ_INT2, excpt_common /* External interrupt request 2 */
HANDLER at90usb_int3, ATMEGA_IRQ_INT3, excpt_common /* External interrupt request 3 */
HANDLER at90usb_int4, ATMEGA_IRQ_INT4, excpt_common /* External interrupt request 4 */
HANDLER at90usb_int5, ATMEGA_IRQ_INT5, excpt_common /* External interrupt request 5 */
HANDLER at90usb_int6, ATMEGA_IRQ_INT6, excpt_common /* External interrupt request 6 */
HANDLER at90usb_int7, ATMEGA_IRQ_INT7, excpt_common /* External interrupt request 7 */
HANDLER at90usb_int0, AT90USB_IRQ_INT0, excpt_common /* External interrupt request 0 */
HANDLER at90usb_int1, AT90USB_IRQ_INT1, excpt_common /* External interrupt request 1 */
HANDLER at90usb_int2, AT90USB_IRQ_INT2, excpt_common /* External interrupt request 2 */
HANDLER at90usb_int3, AT90USB_IRQ_INT3, excpt_common /* External interrupt request 3 */
HANDLER at90usb_int4, AT90USB_IRQ_INT4, excpt_common /* External interrupt request 4 */
HANDLER at90usb_int5, AT90USB_IRQ_INT5, excpt_common /* External interrupt request 5 */
HANDLER at90usb_int6, AT90USB_IRQ_INT6, excpt_common /* External interrupt request 6 */
HANDLER at90usb_int7, AT90USB_IRQ_INT7, excpt_common /* External interrupt request 7 */
HANDLER at90usb_pcint0, AT90USB_IRQ_PCINT0, excpt_common /* Pin Change Interrupt Request 0 */
HANDLER at90usb_usbgen, AT90USB_IRQ_USBGEN, excpt_common /* USB General USB General Interrupt request */
HANDLER at90usb_usbep, AT90USB_IRQ_USBEP, excpt_common /* USB Endpoint/Pipe USB ENdpoint/Pipe Interrupt request */
HANDLER at90usb_wdt, AT90USB_IRQ_WDT, excpt_common /* Watchdog Time-out Interrupt */
HANDLER at90usb_t2compa, AT90USB_IRQ_T2COMPA, excpt_common /* TIMER2 COMPA Timer/Counter2 Compare Match A */
HANDLER at90usb_t2compb, AT90USB_IRQ_T2COMPB, excpt_common /* TIMER2 COMPA Timer/Counter2 Compare Match B */
HANDLER at90usb_t2ovf, ATMEGA_IRQ_T2OVF, excpt_common /* TIMER2 OVF timer/counter2 overflow */
HANDLER at90usb_t1capt, ATMEGA_IRQ_T1CAPT, excpt_common /* TIMER1 CAPT timer/counter1 capture event */
HANDLER at90usb_t1compa, ATMEGA_IRQ_T1COMPA, excpt_common /* TIMER1 COMPA timer/counter1 compare match A */
HANDLER at90usb_t1compb, ATMEGA_IRQ_T1COMPB, excpt_common /* TIMER1 COMPB timer/counter1 compare match B */
HANDLER at90usb_t1compc, ATMEGA_IRQ_T1COMPC, excpt_common /* TIMER1 COMPC timer/counter1 compare match C */
HANDLER at90usb_t1ovf, ATMEGA_IRQ_T1OVF, excpt_common /* TIMER1 OVF timer/counter1 overflow */
HANDLER at90usb_t2ovf, AT90USB_IRQ_T2OVF, excpt_common /* TIMER2 OVF timer/counter2 overflow */
HANDLER at90usb_t1capt, AT90USB_IRQ_T1CAPT, excpt_common /* TIMER1 CAPT timer/counter1 capture event */
HANDLER at90usb_t1compa, AT90USB_IRQ_T1COMPA, excpt_common /* TIMER1 COMPA timer/counter1 compare match A */
HANDLER at90usb_t1compb, AT90USB_IRQ_T1COMPB, excpt_common /* TIMER1 COMPB timer/counter1 compare match B */
HANDLER at90usb_t1compc, AT90USB_IRQ_T1COMPC, excpt_common /* TIMER1 COMPC timer/counter1 compare match C */
HANDLER at90usb_t1ovf, AT90USB_IRQ_T1OVF, excpt_common /* TIMER1 OVF timer/counter1 overflow */
HANDLER at90usb_t0compa, AT90USB_IRQ_T0COMPA, excpt_common /* TIMER0 COMPA Timer/Counter0 Compare Match A */
HANDLER at90usb_t0compb, AT90USB_IRQ_T0COMPB, excpt_common /* TIMER0 COMPB Timer/Counter0 Compare Match B */
HANDLER at90usb_t0ovf, ATMEGA_IRQ_T0OVF, excpt_common /* TIMER0 OVF timer/counter0 overflow */
HANDLER at90usb_spi, ATMEGA_IRQ_SPI, excpt_common /* STC SPI serial transfer complete */
HANDLER at90usb_u1rx, ATMEGA_IRQ_U1RX, excpt_common /* USART1 RX complete */
HANDLER at90usb_u1dre, ATMEGA_IRQ_U1DRE, excpt_common /* USART1 data register empty */
HANDLER at90usb_u1tx, ATMEGA_IRQ_U1TX, excpt_common /* USART1 TX complete */
HANDLER at90usb_anacomp, ATMEGA_IRQ_ANACOMP, excpt_common /* ANALOG COMP analog comparator */
HANDLER at90usb_adc, ATMEGA_IRQ_ADC, excpt_common /* ADC conversion complete */
HANDLER at90usb_ee, ATMEGA_IRQ_EE, excpt_common /* EEPROM ready */
HANDLER at90usb_t3capt, ATMEGA_IRQ_T3CAPT, excpt_common /* TIMER3 CAPT timer/counter3 capture event */
HANDLER at90usb_t3compa, ATMEGA_IRQ_T3COMPA, excpt_common /* TIMER3 COMPA timer/counter3 compare match a */
HANDLER at90usb_t3compb, ATMEGA_IRQ_T3COMPB, excpt_common /* TIMER3 COMPB timer/counter3 compare match b */
HANDLER at90usb_t3compc, ATMEGA_IRQ_T3COMPC, excpt_common /* TIMER3 COMPC timer/counter3 compare match c */
HANDLER at90usb_t3ovf, ATMEGA_IRQ_T3OVF, excpt_common /* TIMER3 OVF timer/counter3 overflow */
HANDLER at90usb_twi, ATMEGA_IRQ_TWI, excpt_common /* TWI two-wire serial interface */
HANDLER at90usb_spmrdy, ATMEGA_IRQ_SPMRDY, excpt_common /* Store program memory ready */
HANDLER at90usb_t0ovf, AT90USB_IRQ_T0OVF, excpt_common /* TIMER0 OVF timer/counter0 overflow */
HANDLER at90usb_spi, AT90USB_IRQ_SPI, excpt_common /* STC SPI serial transfer complete */
HANDLER at90usb_u1rx, AT90USB_IRQ_U1RX, excpt_common /* USART1 RX complete */
HANDLER at90usb_u1dre, AT90USB_IRQ_U1DRE, excpt_common /* USART1 data register empty */
HANDLER at90usb_u1tx, AT90USB_IRQ_U1TX, excpt_common /* USART1 TX complete */
HANDLER at90usb_anacomp, AT90USB_IRQ_ANACOMP, excpt_common /* ANALOG COMP analog comparator */
HANDLER at90usb_adc, AT90USB_IRQ_ADC, excpt_common /* ADC conversion complete */
HANDLER at90usb_ee, AT90USB_IRQ_EE, excpt_common /* EEPROM ready */
HANDLER at90usb_t3capt, AT90USB_IRQ_T3CAPT, excpt_common /* TIMER3 CAPT timer/counter3 capture event */
HANDLER at90usb_t3compa, AT90USB_IRQ_T3COMPA, excpt_common /* TIMER3 COMPA timer/counter3 compare match a */
HANDLER at90usb_t3compb, AT90USB_IRQ_T3COMPB, excpt_common /* TIMER3 COMPB timer/counter3 compare match b */
HANDLER at90usb_t3compc, AT90USB_IRQ_T3COMPC, excpt_common /* TIMER3 COMPC timer/counter3 compare match c */
HANDLER at90usb_t3ovf, AT90USB_IRQ_T3OVF, excpt_common /* TIMER3 OVF timer/counter3 overflow */
HANDLER at90usb_twi, AT90USB_IRQ_TWI, excpt_common /* TWI two-wire serial interface */
HANDLER at90usb_spmrdy, AT90USB_IRQ_SPMRDY, excpt_common /* Store program memory ready */
/* Common exception handling logic. */

View File

@ -193,6 +193,9 @@ __start:
/* Copy initial global data values from FLASH into RAM */
.global __do_copy_data; /* Required to suppress dragging in logic from libgcc */
__do_copy_data:
#ifdef HAVE_RAMPZ
ldi r17, hi8(_edata)
ldi r26, lo8(_sdata)
@ -230,6 +233,9 @@ __start:
/* Clear uninitialized data */
.global __do_clear_bss; /* Required to suppress dragging in logic from libgcc */
__do_clear_bss:
ldi r17, hi8(_ebss)
ldi r26, lo8(_sbss)
ldi r27, hi8(_sbss)

View File

@ -40,10 +40,18 @@ HEAD_ASRC = atmega_head.S
# Common AVR files
CMN_ASRCS = up_switchcontext.S
CMN_CSRCS = up_allocateheap.c up_copystate.c up_createstack.c up_exit.c \
up_idle.c up_initialize.c up_interruptcontext.c up_lowputs.c \
up_mdelay.c up_modifyreg8.c up_modifyreg16.c up_modifyreg32.c \
up_puts.c up_releasestack.c up_udelay.c up_usestack.c
CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c up_copystate.c \
up_createstack.c up_doirq.c up_exit.c up_idle.c up_initialize.c \
up_interruptcontext.c up_lowputs.c up_mdelay.c up_modifyreg8.c \
up_modifyreg16.c up_modifyreg32.c up_puts.c up_releasepending.c \
up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c \
up_sigdeliver.c up_udelay.c up_unblocktask.c up_usestack.c
# Configuration-dependent common files
ifeq ($(CONFIG_ARCH_STACKDUMP),y)
CMN_CSRCS += up_dumpstate.c
endif
# Required ATMEGA files

View File

@ -39,6 +39,7 @@
#include <nuttx/config.h>
#include <arch/irq.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
@ -186,6 +187,9 @@ __start:
/* Copy initial global data values from FLASH into RAM */
.global __do_copy_data; /* Required to suppress dragging in logic from libgcc */
__do_copy_data:
#ifdef HAVE_RAMPZ
ldi r17, hi8(_edata)
ldi r26, lo8(_sdata)
@ -223,6 +227,9 @@ __start:
/* Clear uninitialized data */
.global __do_clear_bss; /* Required to suppress dragging in logic from libgcc */
__do_clear_bss:
ldi r17, hi8(_ebss)
ldi r26, lo8(_sbss)
ldi r27, hi8(_sbss)

View File

@ -94,7 +94,7 @@ extern void up_copystate(uint8_t *dest, uint8_t *src);
extern int up_saveusercontext(uint8_t *saveregs);
extern void up_fullcontextrestore(uint8_t *restoreregs) __attribute__ ((noreturn));
extern void up_switchcontext(uint8_t *saveregs, uint8_t *restoreregs);
extern uint8_t *up_doirq(int irq, uint8_t *regs);
extern uint8_t *up_doirq(uint8_t irq, uint8_t *regs);
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_AVR_SRC_AVR_AVR_INTERNAL_H */

View File

@ -104,30 +104,39 @@
* RESTORE_STACK rx, ry - Undo the operations of USE_STACK
*
* EXCPT_EPILOGUE - Return to the context returned by handler()
* reti - Return from interrupt
*
********************************************************************************************/
/****************************************************************************
* Macros
****************************************************************************/
/********************************************************************************************
* Name: HANDLER
*
* Description:
* This macro provides the exception entry logic. It simply saves one register on the
* stack (r24) and passes the IRQ number to to common logic (see EXCPT_PROLOGUE).
* This macro provides the exception entry logic. It is called with the PC already on the
* stack. It simply saves one register on the stack (r24) and passes the IRQ number to
* common logic (see EXCPT_PROLOGUE).
*
* On Entry:
* sp - Points to the top of the stack
* sp - Points to the top of the stack. The PC is already on the stack.
* Only the stack is available for storage
*
* PCL
* PCH
* --- <- SP
*
* At completion:
* Stack pointer is incremented by one, the saved r24 is on the stack, r24 now contains the
* IRQ number
*
* PCL
* PCH
* R0
* --- <- SP
*
********************************************************************************************/
.macro HANDLER, label, irqno, common
.global \label
\label:
push r24
ldi r24, \irqno
@ -146,12 +155,18 @@
* sp - Points to the top of the stack
* Only the stack is available for storage
*
* PCL
* PCH
* R0
* --- <- SP
*
* At completion:
* Register state is saved on the stack; All registers are available for usage except sp.
*
********************************************************************************************/
.macro EXCPT_PROLOGUE
/* Save R1 - The zero register (but might not be zero) */
push r1
@ -236,7 +251,8 @@
* Interrupts are disabled.
*
* On completion:
* All registers restored
* All registers restored except the PC which remains on the stack so that a return
* via reti can be performed.
*
********************************************************************************************/
@ -318,6 +334,7 @@
*
* On Entry:
* X [r26:r27] - Points to the register save structure.
* Return address is already on the stack (due to CALL or RCALL instruction)/.
* Interrupts are disabled.
*
* At completion:
@ -377,6 +394,15 @@
st x+, r0
/* Skip R0 and r24 - These are scratch register and Call-used, "volatile" registers */
adiw r26, 2 /* Two registers: r0, r24 */
/* Pop and save the return address */
pop r0
st x+, r0
pop r0
st x+, r0
.endm
/********************************************************************************************
@ -392,20 +418,35 @@
* Interrupts are disabled.
*
* On completion:
* All registers restored
* All registers restored except for the PC with now resides at the top of the new stack
* so that iret can be used to switch to the new context.
*
********************************************************************************************/
.macro TCB_RESTORE, regs
/* Fetch the new stack pointer and the saved values of X [r26:r27]. Save X on the new
* stack where we can recover it later.
*/
/* Fetch the new stack pointer */
ld r24, x+ /* Fetch stack pointer (post-incrementing) */
out __SP_L__, r24
ld r25, x+
out __SP_H__, r25
/* Fetch the return address and save it at the bottom of the new stack so
* that we can iret to switch contexts.
*/
movw r28, r26 /* Get a pointer to the PCH/PCL storage location */
adiw r28, REG_PCH
ld r25, y+ /* Load PCH and PCL */
ld r24, y+
push r24 /* Push PCH and PCL on the stack */
push r25
/* Then get value of X [r26:r27]. Save X on the new stack where we can
* recover it later.
*/
ld r25, x+ /* Fetch r26-r27 and save to the new stack */
ld r24, x+
push r24
@ -466,7 +507,9 @@
ld r0, x+
ld r24, x+
/* Finally, recover X [r26-r27] from the the new stack */
/* Finally, recover X [r26-r27] from the the new stack. The PC remains on the new
* stack so that the user of this macro can return with iret.
*/
pop r27
pop r26

168
arch/avr/src/avr/up_blocktask.c Executable file
View File

@ -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.
*/
}
}
}
}

116
arch/avr/src/avr/up_doirq.c Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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.
*/
}
}
}

View File

@ -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.
*/
}
}
}
}

View File

@ -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 */

View File

@ -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 */

View File

@ -129,6 +129,10 @@ up_fullcontextrestore:
/* Restore the context from the TCB saved registers */
TCB_RESTORE
/* And "return" to the new task. */
reti
.endfunc
.end

158
arch/avr/src/avr/up_unblocktask.c Executable file
View File

@ -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.
*/
}
}
}
}

View File

@ -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>
*
* Redistribution and use in source and binary forms, with or without
@ -52,6 +52,8 @@
#include "os_internal.h"
#include "up_internal.h"
#ifdef CONFIG_ARCH_STACKDUMP
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -60,23 +62,8 @@
* selected.
*/
#ifdef CONFIG_ARCH_STACKDUMP
# undef lldbg
# define lldbg lib_lowprintf
#endif
/* The following is just intended to keep some ugliness out of the mainline
* code. We are going to print the task name if:
*
* CONFIG_TASK_NAME_SIZE > 0 && <-- The task has a name
* (defined(CONFIG_DEBUG) || <-- And the debug is enabled (lldbg used)
* defined(CONFIG_ARCH_STACKDUMP)) <-- Or lib_lowprintf() is used
*/
#undef CONFIG_PRINT_TASKNAME
#if CONFIG_TASK_NAME_SIZE > 0 && (defined(CONFIG_DEBUG) || defined(CONFIG_ARCH_STACKDUMP))
# define CONFIG_PRINT_TASKNAME 1
#endif
#undef lldbg
#define lldbg lib_lowprintf
/****************************************************************************
* Private Data
@ -107,7 +94,6 @@ static inline uint32_t up_getsp(void)
* Name: up_stackdump
****************************************************************************/
#ifdef CONFIG_ARCH_STACKDUMP
static void up_stackdump(uint32_t sp, uint32_t stack_base)
{
uint32_t stack ;
@ -120,15 +106,11 @@ static void up_stackdump(uint32_t sp, uint32_t stack_base)
ptr[4], ptr[5], ptr[6], ptr[7]);
}
}
#else
# define up_stackdump()
#endif
/****************************************************************************
* Name: up_registerdump
****************************************************************************/
#ifdef CONFIG_ARCH_STACKDUMP
static inline void up_registerdump(void)
{
/* Are user registers available from interrupt processing? */
@ -152,16 +134,16 @@ static inline void up_registerdump(void)
lldbg("SR: %08x\n", current_regs[REG_SR]);
}
}
#else
# define up_registerdump()
#endif
/****************************************************************************
* Name: _up_assert
****************************************************************************/
/****************************************************************************
* Name: up_dumpstate
****************************************************************************/
#ifdef CONFIG_ARCH_STACKDUMP
static void up_dumpstate(void)
void up_dumpstate(void)
{
_TCB *rtcb = (_TCB*)g_readytorun.head;
uint32_t sp = up_getsp();
@ -255,82 +237,4 @@ static void up_dumpstate(void)
up_registerdump();
}
#else
# define up_dumpstate()
#endif
/****************************************************************************
* Name: _up_assert
****************************************************************************/
static void _up_assert(int errorcode) /* __attribute__ ((noreturn)) */
{
/* Are we in an interrupt handler or the idle task? */
if (current_regs || ((_TCB*)g_readytorun.head)->pid == 0)
{
(void)irqsave();
for(;;)
{
#ifdef CONFIG_ARCH_LEDS
up_ledon(LED_PANIC);
up_mdelay(250);
up_ledoff(LED_PANIC);
up_mdelay(250);
#endif
}
}
else
{
exit(errorcode);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_assert
****************************************************************************/
void up_assert(const uint8_t *filename, int lineno)
{
#ifdef CONFIG_PRINT_TASKNAME
_TCB *rtcb = (_TCB*)g_readytorun.head;
#endif
up_ledon(LED_ASSERTION);
#ifdef CONFIG_PRINT_TASKNAME
lldbg("Assertion failed at file:%s line: %d task: %s\n",
filename, lineno, rtcb->name);
#else
lldbg("Assertion failed at file:%s line: %d\n",
filename, lineno);
#endif
up_dumpstate();
_up_assert(EXIT_FAILURE);
}
/****************************************************************************
* Name: up_assert_code
****************************************************************************/
void up_assert_code(const uint8_t *filename, int lineno, int errorcode)
{
#ifdef CONFIG_PRINT_TASKNAME
_TCB *rtcb = (_TCB*)g_readytorun.head;
#endif
up_ledon(LED_ASSERTION);
#ifdef CONFIG_PRINT_TASKNAME
lldbg("Assertion failed at file:%s line: %d task: %s error code: %d\n",
filename, lineno, rtcb->name, errorcode);
#else
lldbg("Assertion failed at file:%s line: %d error code: %d\n",
filename, lineno, errorcode);
#endif
up_dumpstate();
_up_assert(errorcode);
}

View File

@ -136,6 +136,7 @@ extern int up_timerisr(int irq, uint32_t *regs);
extern void up_lowputc(char ch);
extern void up_puts(const char *str);
extern void up_lowputs(const char *str);
extern void up_dumpstate(void);
/* Defined in common/up_allocateheap.c or chip/xxx_allocateheap.c */