1: /*
2: *----------------------------------------------------------------------
3: * micro T-Kernel 3.00.05
4: *
5: * Copyright (C) 2006-2020 by Ken Sakamura.
6: * This software is distributed under the T-License 2.2.
7: *----------------------------------------------------------------------
8: *
9: * Released by TRON Forum(http://www.tron.org) at 2021/11.
10: *
11: *----------------------------------------------------------------------
12: */
13:
14: #include <sys/machine.h>
15: #ifdef CPU_CORE_ARMV7A
16:
17: /*
18: * exc_entry.S (ARMv7-A)
19: * Exception entry routine
20: */
21:
22: #define _in_asm_source_
23: #include <sys/knldef.h>
24: #include "offset.h"
25:
26: /* GIC Register definition */
27: #define GIC_ICC_BASE 0xE8222000
28: #define GIC_ICC_IAR 0x000C // Interrupt Acknowledge Register
29: #define GIC_ICC_EOIR 0x0010 // End of Interrupt Register
30:
31: .section EXC_ENTRY, "ax"
32: .arm
33:
34: /* ---------------------------------------------------------------------------------
35: * IRQ exception
36: */
37: .global Csym(irq_entry)
38: .extern Csym(knl_intvec_tbl)
39: .extern Csym(Default_Handler)
40:
41: Csym(irq_entry):
42: sub lr, lr, #4 // Return address adjustment
43: srsdb sp!, #PSR_SVC // Save SPSR_irq & R14_irq to SVC stack
44: CPS #PSR_SVC // Change to SVC mode
45: stmfd sp!, {r0-r3, ip, lr} // Save R0-R3,R12,LR to SVC stack
46:
47: /* Stack image by exception handling
48: * +---------------+
49: * SP_svc ->|R0 |
50: * |R1 |
51: * |R2 |
52: * |R3 |
53: * |R12(ip) |
54: * |R14_svc(lr) |
55: * |R14_irq(lr) | <- return address from interrupt
56: * |SPSR_irq |
57: * +---------------+
58: */
59:
60: ldr lr, =GIC_ICC_BASE
61: ldr r3, [lr, #GIC_ICC_IAR] // Read interrupt response register
62: mov r3, r3, lsl #22
63: mov r3, r3, lsr #22 // r3 <- Interrupt ID (& 0x3ff)
64:
65: ldr r0, =N_INTVEC
66: cmp r3, r0 // Is the interrupt number correct?
67: bge l_irq1 // NO => Jump
68:
69: mov r0, r3
70: ldr lr, =Csym(knl_intvec_tbl)
71: add lr, r3, lsl #2
72: ldr lr, [lr] // lr <- Interrupt handler address
73: cmp lr, #0 // Is an interrupt handler registered?
74: bxne lr // YES => jump r0: Interrupt ID
75: b l_irq2 // NO => default_entry
76:
77: l_irq1: // Interrupt ID is an abnormal value
78: ldr r0, =0x3ff
79: cmp r3, r0 // If Interrupt ID is 0x3ff,
80: beq l_irq3 // it is a false positive and returns.
81:
82: l_irq2: // Call the default handler
83: ldr lr, =GIC_ICC_BASE
84: str r3, [lr, #GIC_ICC_EOIR] // Writing the interrupt end register
85:
86: ldr lr, =Csym(Default_Handler)
87: bx lr
88:
89: l_irq3: // Return without doing anything.
90: ldmfd sp!, {r0-r3, ip, lr} // restore registers
91: rfefd sp! // restore SPSR_irq, R14_irq (return from exception)
92:
93:
94: /* ---------------------------------------------------------------------------------
95: * Supervisor call (SVC)
96: */
97: .global Csym(svc_entry)
98: .extern Csym(knl_svcvec_tbl)
99: .extern Csym(SVC_default_Handler)
100: Csym(svc_entry):
101: srsdb sp!, #PSR_SVC // Save SPSR_svc and R14_svc on SVC stack.
102: stmfd sp!, {r0-r3, ip, lr} // Save R0-R3,R12,LR on SVC stack.
103: mov r0, #0xffffffff
104: str r0, [sp, #(5 * 4)] // Change the value of LR on the stack.
105:
106: /*
107: * Stack image
108: * +---------------+
109: * SP_svc ->|R0 |
110: * |R1 |
111: * |R2 |
112: * |R3 |
113: * |R12(ip) |
114: * |0xffffffff |
115: * |R14_svc(lr) | <- return address from exception
116: * |SPSR_svc |
117: * +---------------+
118: */
119:
120: mrs r0, spsr
121: tst r0, #PSR_T
122: ldrneh r0, [lr, #-2] // Thumb instruction
123: ldreq r0, [lr, #-4] // ARM instruction
124: bicne r0, r0, #0xff00
125: biceq r0, r0, #0xff000000
126: // r0 = SVC No.
127:
128: cmp r0, #N_SVCHDR
129: bge SVC_default_Handler // SVC No. >= N_SVC => SVC default_entry
130:
131: ldr lr, =knl_svcvec_tbl
132: add lr, r0, lsl #2
133: ldr lr, [lr] // lr: SVC handler address
134: cmp lr, #0 // Registered?
135: bxne lr // YES -> jump r0: SVC No.
136: b SVC_default_Handler // NO -> SVC default_entry
137:
138:
139: /* ---------------------------------------------------------------------------------
140: * FIQ exception
141: */
142: .global Csym(fiq_entry)
143: .extern Csym(FIQ_Handler)
144: Csym(fiq_entry):
145: sub lr, lr, #4 // Return address adjustment
146: ldr sp, =__fiq_stack_start // Switch to exception stack
147: stmfd sp!, {r0-r3, ip, lr} // Save R0-R3,R12,LR to FIQ stack
148:
149: /* Stack image
150: * +---------------+
151: * SP_fiq ->|R0 |
152: * |R1 |
153: * |R2 |
154: * |R3 |
155: * |R12(ip) |
156: * |R14_fiq(lr) | <- return address from exception
157: * +---------------+
158: */
159:
160: ldr lr, =Csym(FIQ_Handler)
161: bx lr
162:
163: /* ---------------------------------------------------------------------------------
164: * Undefined instruction exception
165: */
166: .global Csym(undef_entry)
167: .extern Csym(UndefinedInst_Handler)
168: .extern Csym(VFPInvalid_Handler)
169:
170: Csym(undef_entry):
171: sub lr, lr, #4 // Return address adjustment
172: ldr sp, =__und_stack_start // Switch to exception stack
173: stmfd sp!, {r0-r3, ip, lr} // Save R0-R3,R12,LR to UDF stack
174:
175: /* Stack image
176: * +---------------+
177: * SP_udf ->|R0 |
178: * |R1 |
179: * |R2 |
180: * |R3 |
181: * |R12(ip) |
182: * |R14_und(lr) | <- return address from exception
183: * +---------------+
184: */
185:
186: #if USE_FPU
187:
188: #define TA_FPU 0x00001000 // TA_FPU = TA_COP0 = 0x00001000
189:
190: mrc p15, 0, ip, c1, c0, 2 // CPACR
191: tst ip, #5 << 20 // CP10,11 available ?
192: beq exe_undhdr // no -> jump
193: fmrx ip, fpexc
194: tst ip, #0x40000000 // fpexc.en ?
195: bne exe_undhdr // no -> jump
196:
197: /* After that, processing for FPU instructions */
198: ldr ip, =Csym(knl_ctxtsk)
199: ldr r0, [ip] // r0 = ctxtsk
200: cmp r0, #0 // if ctxtsk == NULL -> invalid use of VFP
201: beq exe_undhdr
202:
203: ldr ip, [r0, #TCB_tskatr]
204: tst ip, #TA_FPU // if no TA_FPU attribute -> invalid use of VFP
205: beq exe_undhdr
206:
207: ldr ip, =Csym(knl_taskindp)
208: ldr r2, [ip] // r2 = knl_taskindp
209: cmp r2, #0 // if knl_taskindp > 0 -> invalid use of VFP
210: bhi exe_undhdr
211:
212: /* enable VFP */
213: fmrx ip, fpexc
214: orr ip, ip, #0x40000000 // FPEXC.EN = 1
215: fmxr fpexc, ip
216:
217: ldr r2, =Csym(knl_fpu_ctx) // r2 = &knl_fpu_ctx
218: ldr r1, [r2] // r1 = knl_fpu_ctx
219: cmp r1, r0 // if knl_fpu_ctx == ctxtsk -> context switching is not required.
220: beq rtn_undef
221:
222: cmp r1, #0 // if knl_fpu_ctx == NULL -> context saving is not required.
223: beq load_fpuctx
224:
225: /* save VFP context */
226: fmrx lr, fpscr // Floating-Point Status and Control Register
227: ldr ip, [r1, #TCB_isstack] // r1 = TCB.isstack
228: sub ip, ip, #FPU_context // IP = FPU context
229:
230: stmia ip!, {r0, lr} // (r0 is padding)
231: fstmiad ip!, {d0-d15}
232: fstmiad ip!, {d16-d31}
233:
234: /* load VFP context */
235: load_fpuctx:
236: ldr ip, [r0, #TCB_isstack] // r0 = ctxtsk
237: sub ip, ip, #FPU_context // IP = FPU context
238:
239: ldmia ip!, {r1, lr} // (r1 is padding)
240: fldmiad ip!, {d0-d15}
241: fldmiad ip!, {d16-d31}
242: fmxr fpscr, lr // Floating-Point Status and Control Register
243:
244: str r0, [r2] // knl_fpu_ctx = ctxtsk
245:
246: rtn_undef:
247: ldmfd sp!, {r0-r3, ip, lr} // restore registers
248: movs pc,lr // return from exception
249:
250: exe_undhdr:
251: #endif /* USE_FPU */
252: ldr lr, =Csym(UndefinedInst_Handler)
253: bx lr
254:
255: /* ---------------------------------------------------------------------------------
256: * Prefetch abort exception
257: */
258: .global Csym(iabort_entry)
259: .extern Csym(PrefetchAbort_Handler)
260:
261: Csym(iabort_entry):
262: sub lr, lr, #4 // Return address adjustment
263: ldr sp, =__abt_stack_start // Switch to exception stack
264: stmfd sp!, {r0-r3, ip, lr} // Save R0-R3,R12,LR to ABT stack
265:
266: /* Stack image
267: * +---------------+
268: * SP_abt ->|R0 |
269: * |R1 |
270: * |R2 |
271: * |R3 |
272: * |R12(ip) |
273: * |R14_abt(lr) | <- return address from exception
274: * +---------------+
275: */
276:
277: ldr lr, =Csym(PrefetchAbort_Handler)
278: bx lr
279:
280: /* ---------------------------------------------------------------------------------
281: * Data abort exception
282: */
283: .global Csym(dabort_entry)
284: .extern Csym(DataAbort_Handler)
285:
286: Csym(dabort_entry):
287: sub lr, lr, #4 // Return address adjustment
288: ldr sp, =__abt_stack_start // Switch to exception stack
289: stmfd sp!, {r0-r3, ip, lr} // Save R0-R3,R12,LR to ABT stack
290:
291: /* Stack image
292: * +---------------+
293: * SP_abt ->|R0 |
294: * |R1 |
295: * |R2 |
296: * |R3 |
297: * |R12(ip) |
298: * |R14_abt(lr) | <- return address from exception
299: * +---------------+
300: */
301:
302: ldr lr, =Csym(DataAbort_Handler)
303: bx lr
304:
305: /* ---------------------------------------------------------------------------------
306: * Exception Stack Area
307: */
308: .section .fiq_stack_section, "aw", %nobits
309: .global __fiq_stack
310: __fiq_stack:
311: .space FIQ_STACK_SIZE
312:
313: .section .und_stack_section, "aw", %nobits
314: .global __und_stack
315: __und_stack:
316: .space UND_STACK_SIZE
317:
318: .section .abt_stack_section, "aw", %nobits
319: .global __abt_stack
320: __abt_stack:
321: .space ABT_STACK_SIZE
322:
323:
324: #endif /* CPU_CORE_ARMV7A */