1 /*
2  * FreeRTOS Kernel V11.1.0
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28 
29 #include "FreeRTOSConfig.h"
30 
31 #define portCONTEXT_SIZE 132
32 #define portEPC_STACK_LOCATION 124
33 #define portSTATUS_STACK_LOCATION 128
34 
35 #ifdef __LANGUAGE_ASSEMBLY__
36 
37 /******************************************************************/
38 .macro  portSAVE_CONTEXT
39 
40     /* Make room for the context. First save the current status so it can be
41     manipulated, and the cause and EPC registers so their original values are
42     captured. */
43     mfc0    k0, _CP0_CAUSE
44     addiu   sp, sp, -portCONTEXT_SIZE
45     mfc0    k1, _CP0_STATUS
46 
47     /* Also save s6 and s5 so they can be used.  Any nesting interrupts should
48     maintain the values of these registers across the ISR. */
49     sw      s6, 44(sp)
50     sw      s5, 40(sp)
51     sw      k1, portSTATUS_STACK_LOCATION(sp)
52 
53     /* Prepare to enable interrupts above the current priority.
54     k0 = k0 >> 10. Moves RIPL[17:10] to [7:0] */
55     srl     k0, k0, 0xa
56 
57     /* Insert bit field. 7 bits k0[6:0] to k1[16:10] */
58     ins     k1, k0, 10, 7
59 
60     /* Sets CP0.Status.IPL = CP0.Cause.RIPL
61     Copy the MSB of the IPL, but it would be an error if it was set anyway. */
62     srl     k0, k0, 0x7
63 
64     /* MSB of IPL is bit[18] of CP0.Status */
65     ins     k1, k0, 18, 1
66 
67     /* CP0.Status[5:1] = 0 b[5]=Rsvd, b[4]=UM,
68        b[3]=Rsvd, b[2]=ERL, b[1]=EXL
69        Setting EXL=0 allows higher priority interrupts
70        to preempt this handler */
71     ins     k1, zero, 1, 4
72 
73 
74     /* s5 is used as the frame pointer. */
75     add     s5, zero, sp
76 
77     /* Check the nesting count value. */
78     la      k0, uxInterruptNesting
79     lw      s6, (k0)
80 
81     /* If the nesting count is 0 then swap to the the system stack, otherwise
82     the system stack is already being used. */
83     bne     s6, zero, 1f
84     nop
85 
86     /* Swap to the system stack. */
87     la      sp, xISRStackTop
88     lw      sp, (sp)
89 
90     /* Increment and save the nesting count. */
91 1:  addiu   s6, s6, 1
92     sw      s6, 0(k0)
93 
94     /* s6 holds the EPC value, this is saved after interrupts are re-enabled. */
95     mfc0    s6, _CP0_EPC
96 
97     /* Re-enable interrupts. */
98     mtc0    k1, _CP0_STATUS
99 
100     /* Save the context into the space just created.  s6 is saved again
101     here as it now contains the EPC value.  No other s registers need be
102     saved. */
103     sw      ra, 120(s5) /* Return address (RA=R31) */
104     sw      s8, 116(s5) /* Frame Pointer (FP=R30) */
105     sw      t9, 112(s5)
106     sw      t8, 108(s5)
107     sw      t7, 104(s5)
108     sw      t6, 100(s5)
109     sw      t5, 96(s5)
110     sw      t4, 92(s5)
111     sw      t3, 88(s5)
112     sw      t2, 84(s5)
113     sw      t1, 80(s5)
114     sw      t0, 76(s5)
115     sw      a3, 72(s5)
116     sw      a2, 68(s5)
117     sw      a1, 64(s5)
118     sw      a0, 60(s5)
119     sw      v1, 56(s5)
120     sw      v0, 52(s5)
121     sw      s6, portEPC_STACK_LOCATION(s5)
122     sw      $1, 16(s5)
123 
124     /* MEC14xx does not have DSP, removed 7 words */
125     mfhi    s6
126     sw      s6, 12(s5)
127     mflo    s6
128     sw      s6, 8(s5)
129 
130     /* Update the task stack pointer value if nesting is zero. */
131     la      s6, uxInterruptNesting
132     lw      s6, (s6)
133     addiu   s6, s6, -1
134     bne     s6, zero, 1f
135     nop
136 
137     /* Save the stack pointer. */
138     la      s6, uxSavedTaskStackPointer
139     sw      s5, (s6)
140 1:
141     .endm
142 
143 /******************************************************************/
144 .macro  portRESTORE_CONTEXT
145 
146     /* Restore the stack pointer from the TCB.  This is only done if the
147     nesting count is 1. */
148     la      s6, uxInterruptNesting
149     lw      s6, (s6)
150     addiu   s6, s6, -1
151     bne     s6, zero, 1f
152     nop
153     la      s6, uxSavedTaskStackPointer
154     lw      s5, (s6)
155 
156     /* Restore the context.
157     MCHP MEC14xx does not include DSP */
158 1:
159     lw      s6, 8(s5)
160     mtlo    s6
161     lw      s6, 12(s5)
162     mthi    s6
163     lw      $1, 16(s5)
164 
165     /* s6 is loaded as it was used as a scratch register and therefore saved
166     as part of the interrupt context. */
167     lw      s6, 44(s5)
168     lw      v0, 52(s5)
169     lw      v1, 56(s5)
170     lw      a0, 60(s5)
171     lw      a1, 64(s5)
172     lw      a2, 68(s5)
173     lw      a3, 72(s5)
174     lw      t0, 76(s5)
175     lw      t1, 80(s5)
176     lw      t2, 84(s5)
177     lw      t3, 88(s5)
178     lw      t4, 92(s5)
179     lw      t5, 96(s5)
180     lw      t6, 100(s5)
181     lw      t7, 104(s5)
182     lw      t8, 108(s5)
183     lw      t9, 112(s5)
184     lw      s8, 116(s5)
185     lw      ra, 120(s5)
186 
187     /* Protect access to the k registers, and others. */
188     di
189     ehb
190 
191     /* Decrement the nesting count. */
192     la      k0, uxInterruptNesting
193     lw      k1, (k0)
194     addiu   k1, k1, -1
195     sw      k1, 0(k0)
196 
197     lw      k0, portSTATUS_STACK_LOCATION(s5)
198     lw      k1, portEPC_STACK_LOCATION(s5)
199 
200     /* Leave the stack in its original state.  First load sp from s5, then
201     restore s5 from the stack. */
202     add     sp, zero, s5
203     lw      s5, 40(sp)
204     addiu   sp, sp, portCONTEXT_SIZE
205 
206     mtc0    k0, _CP0_STATUS
207     mtc0    k1, _CP0_EPC
208     ehb
209     eret
210     nop
211 
212     .endm
213 
214 #endif /* #ifdef __LANGUAGE_ASSEMBLY__ */
215