]> rtime.felk.cvut.cz Git - arc.git/blob - system/kernel/isr.c
0aae94c49a0405ace4ce39f089cc19c44e80a6f9
[arc.git] / system / kernel / isr.c
1 /* -------------------------------- Arctic Core ------------------------------\r
2  * Arctic Core - the open source AUTOSAR platform http://arccore.com\r
3  *\r
4  * Copyright (C) 2009  ArcCore AB <contact@arccore.com>\r
5  *\r
6  * This source code is free software; you can redistribute it and/or modify it\r
7  * under the terms of the GNU General Public License version 2 as published by the\r
8  * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.\r
9  *\r
10  * This program is distributed in the hope that it will be useful, but\r
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\r
13  * for more details.\r
14  * -------------------------------- Arctic Core ------------------------------*/\r
15 \r
16 \r
17 #if defined(__GNUC__)\r
18 #include <sys/types.h>\r
19 #endif\r
20 #include <stdint.h>\r
21 #include <string.h>\r
22 #include "Os.h"\r
23 #include "Compiler.h"\r
24 #include "internal.h"\r
25 #include "application.h"\r
26 #include "sys.h"\r
27 #include "isr.h"\r
28 #include "irq.h"\r
29 \r
30 #define ILL_VECTOR      0xff\r
31 \r
32 extern uint8_t Os_VectorToIsr[NUMBER_OF_INTERRUPTS_AND_EXCEPTIONS];\r
33 #if OS_ISR_CNT!=0\r
34 extern const OsIsrConstType Os_IsrConstList[OS_ISR_CNT];\r
35 #endif\r
36 \r
37 #if OS_ISR_MAX_CNT!=0\r
38 OsIsrVarType Os_IsrVarList[OS_ISR_MAX_CNT];\r
39 #endif\r
40 \r
41 SECTION_BALIGN(0x10) uint8_t Os_IsrStack[OS_INTERRUPT_STACK_SIZE];\r
42 \r
43 // TODO: remove. Make soft links or whatever\r
44 #if defined(CFG_ARM_CM3)\r
45 #include "irq_types.h"\r
46 //#include "stm32f10x.h"\r
47 //#include "stm32f10x_arc.h"\r
48 #endif\r
49 \r
50 #if 0\r
51 extern caddr_t *sbrk(int);\r
52 \r
53 #define os_alloc(_x)    sbrk(_x)\r
54 \r
55 OsTaskVarType * os_alloc_new_pcb( void ) {\r
56         void *h = os_alloc(sizeof(OsTaskVarType));\r
57         memset(h,0,sizeof(OsTaskVarType));\r
58         assert(h!=NULL);\r
59         return h;\r
60 }\r
61 #endif\r
62 \r
63 \r
64 //extern TaskType Os_AddTask( OsTaskVarType *pcb );\r
65 \r
66 //static uint8 stackTop = 0x42;\r
67 #if OS_ISR_CNT != 0\r
68 static void Os_IsrAddWithId( const OsIsrConstType * restrict isrPtr, int id ) {\r
69         Os_IsrVarList[id].constPtr = isrPtr;\r
70         Os_IsrVarList[id].id = id;\r
71 #if defined(CFG_OS_ISR_HOOKS)\r
72         Os_IsrVarList[id].preemtedId = INVALID_ISR;\r
73 #endif\r
74         Os_VectorToIsr[isrPtr->vector + IRQ_INTERRUPT_OFFSET ] = id;\r
75         Irq_EnableVector( isrPtr->vector, isrPtr->priority, Os_ApplGetCore(isrPtr->appOwner )  );\r
76 }\r
77 #endif\r
78 \r
79 void Os_IsrInit( void ) {\r
80 \r
81         Irq_Init();\r
82 \r
83         Os_Sys.isrCnt = OS_ISR_CNT;\r
84         /* Probably something smarter, but I cant figure out what */\r
85         memset(&Os_VectorToIsr[OS_ISR_CNT],ILL_VECTOR,NUMBER_OF_INTERRUPTS_AND_EXCEPTIONS-OS_ISR_CNT);\r
86 \r
87 #if OS_ISR_CNT != 0\r
88         /* Attach the interrupts */\r
89         for (int i = 0; i < Os_Sys.isrCnt; i++) {\r
90                 Os_IsrAddWithId(&Os_IsrConstList[i],i);\r
91         }\r
92 #endif\r
93 }\r
94 \r
95 /**\r
96  * Adds an ISR to a list of Isr's. The ISRType (id) is returned\r
97  * for the "created" ISR.\r
98  *\r
99  * @param isrPtr Pointer to const data holding ISR information.\r
100  * @return\r
101  */\r
102 ISRType Os_IsrAdd( const OsIsrConstType * restrict isrPtr ) {\r
103         ISRType id;\r
104         ISRType installedId;\r
105 \r
106         assert( isrPtr != NULL );\r
107         assert( (isrPtr->vector + IRQ_INTERRUPT_OFFSET) < NUMBER_OF_INTERRUPTS_AND_EXCEPTIONS );\r
108 \r
109         /* Check if we already have installed it */\r
110         installedId = Os_VectorToIsr[isrPtr->vector + IRQ_INTERRUPT_OFFSET ];\r
111 \r
112         if( installedId != ILL_VECTOR ) {\r
113                 /* The vector is already installed */\r
114                 id = installedId;\r
115         } else {\r
116                 /* It a new vector */\r
117                 id = Os_Sys.isrCnt++;\r
118                 /* Since OS_ISR_MAX_CNT defines the allocation limit for Os_IsrVarList,\r
119                  * we must not allocate more IDs than that */\r
120                 assert(id<OS_ISR_MAX_CNT);\r
121 \r
122                 Os_IsrVarList[id].constPtr = isrPtr;\r
123                 Os_IsrVarList[id].id = id;\r
124 #if defined(CFG_OS_ISR_HOOKS)\r
125                 Os_IsrVarList[id].preemtedId = INVALID_ISR;\r
126 #endif\r
127                 Os_VectorToIsr[isrPtr->vector + IRQ_INTERRUPT_OFFSET ] = id;\r
128                 Irq_EnableVector( isrPtr->vector, isrPtr->priority, Os_ApplGetCore(isrPtr->appOwner )  );\r
129         }\r
130 \r
131         return id;\r
132 }\r
133 \r
134 #if 0\r
135 const OsIsrConstType * Os_IsrGet( int16_t vector) {\r
136         return &Os_IsrConstList[Os_VectorToIsr[vector]];\r
137 }\r
138 #endif\r
139 \r
140 #if 0\r
141 void Os_IsrDisable( ISRType isr) {\r
142 \r
143 }\r
144 \r
145 void Os_IsrEnable( ISRType isr) {\r
146 \r
147 }\r
148 #endif\r
149 \r
150 \r
151 /*\r
152  * Resources:\r
153  *   Irq_VectorTable[]\r
154  *   Irq_IsrTypeTable[]\r
155  *   Irq_PriorityTable[]\r
156  *\r
157  *   exception table\r
158  *   interrupt table\r
159  *\r
160  * Usual HW resources.\r
161  * - prio in HW (ppc and arm (even cortex m4))\r
162  *\r
163  *\r
164  * TOOL GENERATES ALL\r
165  *   Irq_VectorTable   CONST\r
166  *   Irq_IsrTypeTable  CONST\r
167  *   Irq_PriorityTable CONST  Can probably be a table with ISR_MAX number\r
168  *                            of for a CPU with prio registers.  For masking\r
169  *                            CPUs it's better to keep an array to that indexing\r
170  *                            can be used.\r
171  *\r
172  *   The problem with this approach is that the tool needs to know everything.\r
173  *\r
174  * TOOL GENERATES PART\r
175  *   Irq_VectorTable   VAR     Since we must add vectors later\r
176  *   Irq_IsrTypeTable  VAR     Since we must add vectors later\r
177  *   Irq_PriorityTable VAR\r
178  *\r
179  *   We move the\r
180  *\r
181  */\r
182 \r
183 \r
184 \r
185 /**\r
186  * Before we have proper editor for ISR2 use this function to add resources\r
187  * to an ISR2\r
188  *\r
189  * @param isr\r
190  * @param resource\r
191  * @return\r
192  */\r
193 StatusType Os_IsrAddResource( TaskType isr, ResourceType resource ) {\r
194         (void)isr;\r
195         (void)resource;\r
196 \r
197         return E_OK;\r
198 }\r
199 \r
200 #if defined(CFG_ARM_CM3)\r
201 extern void Irq_EOI2( void );\r
202 \r
203 void TailChaining(void *stack)\r
204 {\r
205         struct OsTaskVar *pPtr = NULL;\r
206 \r
207         POSTTASKHOOK();\r
208 \r
209         /* Save info for preempted pcb */\r
210         pPtr = Os_SysTaskGetCurr();\r
211         pPtr->stack.curr = stack;\r
212         pPtr->state = ST_READY;\r
213         OS_DEBUG(D_TASK,"Preempted %s\n",pPtr->name);\r
214 \r
215         Os_StackPerformCheck(pPtr);\r
216 \r
217         /* We interrupted a task */\r
218         OsTaskVarType *new_pcb  = Os_TaskGetTop();\r
219 \r
220         Os_StackPerformCheck(new_pcb);\r
221 \r
222         if(     (new_pcb == Os_Sys.currTaskPtr) ||\r
223                         (Os_Sys.currTaskPtr->constPtr->scheduling == NON) ||\r
224                         !Os_SchedulerResourceIsFree() )\r
225         {\r
226                 /* Just bring the preempted task back to running */\r
227                 Os_TaskSwapContextTo(NULL,Os_Sys.currTaskPtr);\r
228         } else {\r
229                 OS_DEBUG(D_TASK,"Found candidate %s\n",new_pcb->name);\r
230                 Os_TaskSwapContextTo(NULL,new_pcb);\r
231         }\r
232 }\r
233 \r
234 void Os_Isr_cm3( int16_t vector ) {\r
235 \r
236         OsIsrVarType *isrPtr =  &Os_IsrVarList[Os_VectorToIsr[vector]];\r
237 \r
238         assert( isrPtr != NULL );\r
239 \r
240         if( isrPtr->constPtr->type == ISR_TYPE_1) {\r
241                 isrPtr->constPtr->entry();\r
242                 return;\r
243         }\r
244 \r
245         Os_Sys.intNestCnt++;\r
246         isrPtr->state = ST_ISR_RUNNING;\r
247 \r
248         Irq_Enable();\r
249         isrPtr->constPtr->entry();\r
250         Irq_Disable();\r
251 \r
252         /* Check so that ISR2 haven't disabled the interrupts */\r
253         /** @req OS368 */\r
254         if( Os_SysIntAnyDisabled() ) {\r
255                 Os_SysIntClearAll();\r
256                 ERRORHOOK(E_OS_DISABLEDINT);\r
257         }\r
258 \r
259         /* Check so that the ISR2 have called ReleaseResource() for each GetResource() */\r
260         /** @req OS369 */\r
261         if( Os_IsrOccupiesResources(isrPtr) ) {\r
262                 Os_IsrResourceFreeAll(isrPtr);\r
263                 ERRORHOOK(E_OS_RESOURCE);\r
264         }\r
265 \r
266         isrPtr->state = ST_SUSPENDED;\r
267 \r
268         Irq_EOI();\r
269 \r
270         --Os_Sys.intNestCnt;\r
271 \r
272         /* Scheduling is done in PendSV handler for ARM CM3 */\r
273         *((uint32_t volatile *)0xE000ED04) = 0x10000000; // PendSV\r
274 }\r
275 #endif\r
276 \r
277 /*-----------------------------------------------------------------*/\r
278 \r
279 void Os_IsrGetStackInfo( OsIsrStackType *stack ) {\r
280         stack->top = Os_IsrStack;\r
281         stack->size = sizeof(Os_IsrStack);\r
282 }\r
283 \r
284 \r
285 #if defined(CFG_ARM_CR4)\r
286 void *Os_Isr_cr4( void *stack, int16_t virtualVector, int16_t vector ) {\r
287         OsIsrVarType *isrPtr =  &Os_IsrVarList[Os_VectorToIsr[virtualVector]];\r
288         isrPtr->activeVector = vector;\r
289         return Os_Isr(stack, virtualVector);\r
290 }\r
291 #endif\r
292 \r
293 /**\r
294  * Handle ISR type 2 interrupts from interrupt controller.\r
295  *\r
296  * @param stack Pointer to the current stack\r
297  * @param vector\r
298  */\r
299 void *Os_Isr( void *stack, int16_t vector ) {\r
300 \r
301         OsIsrVarType *isrPtr =  &Os_IsrVarList[Os_VectorToIsr[vector]];\r
302         OsTaskVarType *taskPtr = NULL;\r
303         OsIsrVarType *oldIsrPtr;\r
304 \r
305         assert( isrPtr != NULL );\r
306 \r
307         if( isrPtr->constPtr->type == ISR_TYPE_1) {\r
308                 isrPtr->constPtr->entry();\r
309                 Irq_EOI();\r
310                 return stack;\r
311         }\r
312 \r
313         /* Check if we interrupted a task or ISR */\r
314         if( Os_Sys.intNestCnt == 0 ) {\r
315                 /* We interrupted a task */\r
316                 POSTTASKHOOK();\r
317 \r
318                 /* Save info for preempted pcb */\r
319                 taskPtr = Os_SysTaskGetCurr();\r
320                 taskPtr->stack.curr = stack;\r
321                 taskPtr->state = ST_READY;\r
322                 OS_DEBUG(D_TASK,"Preempted %s\n",taskPtr->constPtr->name);\r
323 \r
324                 Os_StackPerformCheck(taskPtr);\r
325         } else {\r
326                 /* We interrupted an ISR, save it */\r
327                 oldIsrPtr = Os_Sys.currIsrPtr;\r
328 #if defined(CFG_OS_ISR_HOOKS)\r
329                 isrPtr->preemtedId = oldIsrPtr->id;\r
330                 Os_PostIsrHook(oldIsrPtr->id);\r
331 #endif\r
332         }\r
333 \r
334         Os_Sys.intNestCnt++;\r
335 \r
336         isrPtr->state = ST_ISR_RUNNING;\r
337         Os_Sys.currIsrPtr = isrPtr;\r
338 \r
339         Irq_SOI();\r
340 \r
341 #if defined(CFG_OS_ISR_HOOKS)\r
342         Os_PreIsrHook(isrPtr->id);\r
343 #endif\r
344 \r
345 \r
346 #if defined(CFG_HCS12D)\r
347         isrPtr->constPtr->entry();\r
348 #else\r
349         Irq_Enable();\r
350         isrPtr->constPtr->entry();\r
351         Irq_Disable();\r
352 #endif\r
353 \r
354 #if defined(CFG_OS_ISR_HOOKS)\r
355         Os_PostIsrHook(isrPtr->id );\r
356         if( isrPtr->preemtedId != INVALID_ISR ) {\r
357                 Os_Sys.currIsrPtr = &Os_IsrVarList[isrPtr->preemtedId];\r
358                 Os_PreIsrHook(isrPtr->preemtedId );\r
359                 isrPtr->preemtedId = INVALID_ISR;\r
360         }\r
361 #endif\r
362 \r
363 \r
364         /* Check so that ISR2 haven't disabled the interrupts */\r
365         /** @req OS368 */\r
366         if( Os_SysIntAnyDisabled() ) {\r
367                 Os_SysIntClearAll();\r
368                 ERRORHOOK(E_OS_DISABLEDINT);\r
369         }\r
370 \r
371         /* Check so that the ISR2 have called ReleaseResource() for each GetResource() */\r
372         /** @req OS369 */\r
373         if( Os_IsrOccupiesResources(isrPtr) ) {\r
374                 Os_IsrResourceFreeAll(isrPtr);\r
375                 ERRORHOOK(E_OS_RESOURCE);\r
376         }\r
377 \r
378         isrPtr->state = ST_ISR_NOT_RUNNING;\r
379         Os_Sys.currIsrPtr = isrPtr;\r
380 \r
381         Irq_EOI();\r
382 \r
383         --Os_Sys.intNestCnt;\r
384 \r
385 #if defined(CFG_ARM_CM3)\r
386                 /* Scheduling is done in PendSV handler for ARM CM3 */\r
387                 *((uint32_t volatile *)0xE000ED04) = 0x10000000; // PendSV\r
388 #else\r
389         // We have preempted a task\r
390         if( (Os_Sys.intNestCnt == 0) ) {\r
391                 OsTaskVarType *new_pcb  = Os_TaskGetTop();\r
392 \r
393                 Os_StackPerformCheck(new_pcb);\r
394 \r
395                 if(     (new_pcb == Os_Sys.currTaskPtr) ||\r
396                                 (Os_Sys.currTaskPtr->constPtr->scheduling == NON) ||\r
397                                 !Os_SchedulerResourceIsFree() )\r
398                 {\r
399                         /* Just bring the preempted task back to running */\r
400                         Os_Sys.currTaskPtr->state = ST_RUNNING;\r
401                         PRETASKHOOK();\r
402                 } else {\r
403                         OS_DEBUG(D_TASK,"Found candidate %s\n",new_pcb->constPtr->name);\r
404                         Os_TaskSwapContextTo(NULL,new_pcb);\r
405                 }\r
406         } else {\r
407                 /* We have a nested interrupt */\r
408 \r
409                 /* Restore current running ISR from stack */\r
410                 Os_Sys.currIsrPtr = oldIsrPtr;\r
411         }\r
412 #endif\r
413 \r
414         return stack;\r
415 }\r