/******************************************************************/ \r
.macro portSAVE_CONTEXT\r
\r
- /* Make room for the context. */ \r
-\r
- /* Get interrupts above the kernel priority enabled again ASAP. First\r
- save the current status so we can manipulate it, and the cause and EPC\r
- registers so we capture their original values in case of interrupt nesting. */\r
-\r
+ /* Make room for the context. First save the current status so we can \r
+ manipulate it, and the cause and EPC registers so we capture their \r
+ original values in case of interrupt nesting. */\r
mfc0 k0, _CP0_CAUSE\r
addiu sp, sp, -portCONTEXT_SIZE\r
sw k0, portCAUSE_STACK_LOCATION(sp)\r
mfc0 k1, _CP0_STATUS\r
- /* Also save s6 so we can use it during this interrupt. Any\r
- nesting interrupts should maintain the values of this register\r
+\r
+ /* Also save s6 and s5 so we can use them during this interrupt. Any\r
+ nesting interrupts should maintain the values of these registers\r
accross the ISR. */\r
sw s6, 44(sp)\r
+ sw s5, 40(sp)\r
sw k1, portSTATUS_STACK_LOCATION(sp)\r
\r
+ /* Enable interrupts above the current priority. SysCall interrupts\r
+ enable priorities above configKERNEL_INTERRUPT_PRIORITY, so first \r
+ check if the interrupt was a system call (32). */\r
+ add s6, zero, k0\r
+ and s6, s6, 32\r
+ beq s6, zero, .+20 /* Not a system call, mask up to the current interrupt priority. */\r
+ nop\r
+ addiu k0, zero, configKERNEL_INTERRUPT_PRIORITY /* Was a system call, mask only to kernel priority. */\r
+ beq zero, zero, .+12\r
+ nop\r
+ srl k0, k0, 0xa\r
+ ins k1, k0, 10, 6\r
+ ins k1, zero, 1, 4\r
+\r
+ /* Load, incrmement, then save the interrupt nesting count. */\r
+ la k0, uxInterruptNesting\r
+ lw s6, (k0)\r
+ addiu s6, s6, 1\r
+ sw s6, 0(k0)\r
+\r
+ /* If it was zero, switch to the system stack. If it was not zero then\r
+ we are already using the system stack. s5 holds the old stack value -\r
+ this might be used to determine the cause of a general exception. */\r
+ add s5, zero, sp\r
+ addiu s6, s6, -1\r
+ bne zero, s6, .+20\r
+ nop\r
+ la s6, xISRStackTop\r
+ lw sp, (s6)\r
\r
/* s6 holds the EPC value, we may want this during the context switch. */\r
mfc0 s6, _CP0_EPC\r
\r
- /* Enable interrupts above the kernel priority. */\r
- addiu k0, zero, configKERNEL_INTERRUPT_PRIORITY\r
- ins k1, k0, 10, 6\r
- ins k1, zero, 1, 4\r
+ /* Re-enable interrupts. */\r
mtc0 k1, _CP0_STATUS\r
\r
/* Save the context into the space just created. s6 is saved again\r
here as it now contains the EPC value. */\r
- sw ra, 120(sp)\r
- sw s8, 116(sp)\r
- sw t9, 112(sp)\r
- sw t8, 108(sp)\r
- sw t7, 104(sp)\r
- sw t6, 100(sp)\r
- sw t5, 96(sp)\r
- sw t4, 92(sp)\r
- sw t3, 88(sp)\r
- sw t2, 84(sp)\r
- sw t1, 80(sp)\r
- sw t0, 76(sp)\r
- sw a3, 72(sp)\r
- sw a2, 68(sp)\r
- sw a1, 64(sp)\r
- sw a0, 60(sp)\r
- sw v1, 56(sp)\r
- sw v0, 52(sp)\r
- sw s7, 48(sp)\r
- sw s6, portEPC_STACK_LOCATION(sp)\r
- sw s5, 40(sp)\r
- sw s4, 36(sp)\r
- sw s3, 32(sp)\r
- sw s2, 28(sp)\r
- sw s1, 24(sp)\r
- sw s0, 20(sp)\r
- sw $1, 16(sp)\r
+ sw ra, 120(s5)\r
+ sw s8, 116(s5)\r
+ sw t9, 112(s5)\r
+ sw t8, 108(s5)\r
+ sw t7, 104(s5)\r
+ sw t6, 100(s5)\r
+ sw t5, 96(s5)\r
+ sw t4, 92(s5)\r
+ sw t3, 88(s5)\r
+ sw t2, 84(s5)\r
+ sw t1, 80(s5)\r
+ sw t0, 76(s5)\r
+ sw a3, 72(s5)\r
+ sw a2, 68(s5)\r
+ sw a1, 64(s5)\r
+ sw a0, 60(s5)\r
+ sw v1, 56(s5)\r
+ sw v0, 52(s5)\r
+ sw s7, 48(s5)\r
+ sw s6, portEPC_STACK_LOCATION(s5)\r
+ /* s5 has already been saved. */\r
+ sw s4, 36(s5)\r
+ sw s3, 32(s5)\r
+ sw s2, 28(s5)\r
+ sw s1, 24(s5)\r
+ sw s0, 20(s5)\r
+ sw $1, 16(s5)\r
\r
/* s7 is used as a scratch register. */\r
mfhi s7\r
- sw s7, 12(sp)\r
+ sw s7, 12(s5)\r
mflo s7\r
- sw s7, 8(sp)\r
+ sw s7, 8(s5)\r
\r
/* Each task maintains its own nesting count. */\r
la s7, uxCriticalNesting\r
lw s7, (s7)\r
- sw s7, 4(sp)\r
- \r
- /* Update the TCB stack pointer value */\r
- la s7, pxCurrentTCB\r
+ sw s7, 4(s5)\r
+\r
+ /* Update the TCB stack pointer value if the nesting count is 1. */\r
+ la s7, uxInterruptNesting\r
lw s7, (s7)\r
- sw sp, (s7)\r
+ addiu s7, s7, -1\r
+ bne s7, zero, .+24 /* Dont save the stack pointer to the task or swap stacks. */\r
+ nop\r
\r
- /* Switch to the ISR stack, saving the current stack in s5. This might\r
- be used to determine the cause of a general exception. */\r
- add s5, zero, sp\r
- la s7, xISRStackTop\r
- lw sp, (s7)\r
+ /* Save the stack pointer to the task. */\r
+ la s7, pxCurrentTCB\r
+ lw s7, (s7)\r
+ sw s5, (s7)\r
\r
.endm\r
\r
/******************************************************************/ \r
.macro portRESTORE_CONTEXT\r
\r
- /* Restore the stack pointer from the TCB */\r
+ /* Restore the stack pointer from the TCB. This is only done if the\r
+ nesting count is 1. */\r
+ la s7, uxInterruptNesting\r
+ lw s7, (s7)\r
+ addiu s7, s7, -1\r
+ bne s7, zero, .+24 /* Dont load the stack pointer. */\r
+ nop\r
la s0, pxCurrentTCB\r
- lw s1, (s0)\r
- lw sp, (s1)\r
+ lw s0, (s0)\r
+ lw s5, (s0)\r
\r
/* Restore the context, the first item of which is the critical nesting\r
depth. */\r
la s0, uxCriticalNesting\r
- lw s1, 4(sp)\r
+ lw s1, 4(s5)\r
sw s1, (s0)\r
\r
/* Restore the rest of the context. */\r
- lw s0, 8(sp)\r
+ lw s0, 8(s5)\r
mtlo s0\r
- lw s0, 12(sp)\r
+ lw s0, 12(s5)\r
mthi s0\r
- lw $1, 16(sp)\r
- lw s0, 20(sp)\r
- lw s1, 24(sp)\r
- lw s2, 28(sp)\r
- lw s3, 32(sp)\r
- lw s4, 36(sp)\r
- lw s5, 40(sp)\r
- lw s6, 44(sp)\r
- lw s7, 48(sp)\r
- lw v0, 52(sp)\r
- lw v1, 56(sp)\r
- lw a0, 60(sp)\r
- lw a1, 64(sp)\r
- lw a2, 68(sp)\r
- lw a3, 72(sp)\r
- lw t0, 76(sp)\r
- lw t1, 80(sp)\r
- lw t2, 84(sp)\r
- lw t3, 88(sp)\r
- lw t4, 92(sp)\r
- lw t5, 96(sp)\r
- lw t6, 100(sp)\r
- lw t7, 104(sp)\r
- lw t8, 108(sp)\r
- lw t9, 112(sp)\r
- lw s8, 116(sp)\r
- lw ra, 120(sp)\r
-\r
- /* Protect access to the k registers. */\r
+ lw $1, 16(s5)\r
+ lw s0, 20(s5)\r
+ lw s1, 24(s5)\r
+ lw s2, 28(s5)\r
+ lw s3, 32(s5)\r
+ lw s4, 36(s5)\r
+ /* s5 is loaded later. */\r
+ lw s6, 44(s5)\r
+ lw s7, 48(s5)\r
+ lw v0, 52(s5)\r
+ lw v1, 56(s5)\r
+ lw a0, 60(s5)\r
+ lw a1, 64(s5)\r
+ lw a2, 68(s5)\r
+ lw a3, 72(s5)\r
+ lw t0, 76(s5)\r
+ lw t1, 80(s5)\r
+ lw t2, 84(s5)\r
+ lw t3, 88(s5)\r
+ lw t4, 92(s5)\r
+ lw t5, 96(s5)\r
+ lw t6, 100(s5)\r
+ lw t7, 104(s5)\r
+ lw t8, 108(s5)\r
+ lw t9, 112(s5)\r
+ lw s8, 116(s5)\r
+ lw ra, 120(s5)\r
+\r
+ /* Protect access to the k registers, and others. */\r
di\r
- lw k1, portSTATUS_STACK_LOCATION(sp)\r
- lw k0, portEPC_STACK_LOCATION(sp)\r
\r
- /* Leave the stack how we found it. */\r
+ /* Decrement the nesting count. */\r
+ la k0, uxInterruptNesting\r
+ lw k1, (k0)\r
+ addiu k1, k1, -1\r
+ sw k1, 0(k0)\r
+\r
+ lw k1, portSTATUS_STACK_LOCATION(s5)\r
+ lw k0, portEPC_STACK_LOCATION(s5)\r
+\r
+ /* Leave the stack how we found it. First load sp from s5, then restore\r
+ s5 from the stack. */\r
+ add sp, zero, s5\r
+ lw s5, 40(sp)\r
addiu sp, sp, portCONTEXT_SIZE\r
\r
mtc0 k1, _CP0_STATUS\r
* Implementation of functions defined in portable.h for the PIC32MX port.\r
*----------------------------------------------------------*/\r
\r
+/* Library includes. */\r
+#include <string.h>\r
+\r
/* Scheduler include files. */\r
#include "FreeRTOS.h"\r
#include "task.h"\r
/* Records the nesting depth of calls to portENTER_CRITICAL(). */\r
unsigned portBASE_TYPE uxCriticalNesting = 0x55555555;\r
\r
+/* Records the interrupt nesting depth. This starts at one as it will be\r
+decremented to 0 when the first task starts. */\r
+volatile unsigned portBASE_TYPE uxInterruptNesting = 0x01;\r
+\r
/* The stack used by interrupt service routines that cause a context switch. */\r
portSTACK_TYPE xISRStack[ configISR_STACK_SIZE ] = { 0 };\r
\r
{\r
extern void vPortStartFirstTask( void );\r
\r
+ memset( xISRStack, 0x5a, configISR_STACK_SIZE * sizeof( portSTACK_TYPE ) );\r
+\r
/* Setup the timer to generate the tick. Interrupts will have been \r
disabled by the time we get here. */\r
prvSetupTimerInterrupt();\r