2 # Copyright (C) 2005 Jakub Vana
3 # Copyright (C) 2005 Jakub Jermar
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
10 # - Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # - Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # - The name of the author may not be used to endorse or promote products
16 # derived from this software without specific prior written permission.
18 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <arch/stack.h>
31 #include <arch/register.h>
32 #include <arch/mm/page.h>
35 #define STACK_ITEMS 14
36 #define STACK_FRAME_SIZE ALIGN_UP((STACK_ITEMS*STACK_ITEM_SIZE) + STACK_SCRATCH_AREA_SIZE, STACK_ALIGNMENT)
38 #if (STACK_ITEMS % 2 == 0)
39 # define STACK_FRAME_BIAS 8
41 # define STACK_FRAME_BIAS 16
44 /** Partitioning of bank 0 registers. */
48 #define R_KSTACK_BSP r22 /* keep in sync with before_thread_runs_arch() */
49 #define R_KSTACK r23 /* keep in sync with before_thread_runs_arch() */
51 /** Heavyweight interrupt handler
53 * This macro roughly follows steps from 1 to 19 described in
54 * Intel Itanium Architecture Software Developer's Manual, Chapter 3.4.2.
56 * HEAVYWEIGHT_HANDLER macro must cram into 16 bundles (48 instructions).
57 * This goal is achieved by using procedure calls after RSE becomes operational.
59 * Some steps are skipped (enabling and disabling interrupts).
60 * Some steps are not fully supported yet (e.g. dealing with floating-point
63 * @param offs Offset from the beginning of IVT.
64 * @param handler Interrupt handler address.
66 .macro HEAVYWEIGHT_HANDLER offs, handler=universal_handler
69 movl R_HANDLER = \handler ;;
70 br heavyweight_handler
73 .global heavyweight_handler
75 /* 1. copy interrupt registers into bank 0 */
78 * Note that r24-r31 from bank 0 can be used only as long as PSR.ic = 0.
86 /* 2. preserve predicate register into bank 0 */
89 /* 3. switch to kernel memory stack */
91 shr.u r31 = r12, VRN_SHIFT ;;
93 shr.u r30 = r30, PSR_CPL_SHIFT ;;
94 and r30 = PSR_CPL_MASK_SHIFTED, r30 ;;
97 * Set p3 to true if the interrupted context executed in kernel mode.
98 * Set p4 to false if the interrupted context didn't execute in kernel mode.
100 cmp.eq p3, p4 = r30, r0 ;;
101 cmp.eq p1, p2 = r30, r0 ;; /* remember IPSR setting in p1 and p2 */
104 * Set p3 to true if the stack register references kernel address space.
105 * Set p4 to false if the stack register doesn't reference kernel address space.
107 (p3) cmp.eq p3, p4 = VRN_KERNEL, r31 ;;
110 * Now, p4 is true iff the stack needs to be switched to kernel stack.
113 (p4) mov r12 = R_KSTACK ;;
115 add r31 = -STACK_FRAME_BIAS, r12 ;;
116 add r12 = -STACK_FRAME_SIZE, r12
118 /* 4. save registers in bank 0 into memory stack */
119 st8 [r31] = r30, -8 ;; /* save old stack pointer */
121 st8 [r31] = r29, -8 ;; /* save predicate registers */
123 st8 [r31] = r24, -8 ;; /* save cr.iip */
124 st8 [r31] = r25, -8 ;; /* save cr.ipsr */
125 st8 [r31] = r26, -8 ;; /* save cr.iipa */
126 st8 [r31] = r27, -8 ;; /* save cr.isr */
127 st8 [r31] = r28, -8 ;; /* save cr.ifa */
129 /* 5. RSE switch from interrupted context */
135 st8 [r31] = r24, -8 ;; /* save ar.rsc */
136 st8 [r31] = r25, -8 ;; /* save ar.pfs */
137 st8 [r31] = r26, -8 /* save ar.ifs */
139 and r24 = ~(RSC_PL_MASK), r24 ;;
140 and r30 = ~(RSC_MODE_MASK), r24 ;;
141 mov ar.rsc = r30 ;; /* update RSE state */
144 mov r28 = ar.bspstore ;;
147 * Inspect BSPSTORE to figure out whether it is necessary to switch to kernel BSPSTORE.
149 (p1) shr.u r30 = r28, VRN_SHIFT ;;
150 (p1) cmp.eq p1, p2 = VRN_KERNEL, r30 ;;
153 * If BSPSTORE needs to be switched, p1 is false and p2 is true.
156 (p2) mov r30 = R_KSTACK_BSP ;;
157 (p2) mov ar.bspstore = r30 ;;
161 st8 [r31] = r27, -8 ;; /* save ar.rnat */
162 st8 [r31] = r30, -8 ;; /* save new value written to ar.bspstore */
163 st8 [r31] = r28, -8 ;; /* save ar.bspstore */
164 st8 [r31] = r29, -8 /* save ar.bsp */
166 mov ar.rsc = r24 /* restore RSE's setting + kernel privileges */
168 /* steps 6 - 15 are done by heavyweight_handler_inner() */
169 mov R_RET = b0 /* save b0 belonging to interrupted context */
170 br.call.sptk.many b0 = heavyweight_handler_inner
171 0: mov b0 = R_RET /* restore b0 belonging to the interrupted context */
173 /* 16. RSE switch to interrupted context */
174 cover /* allocate zerro size frame (step 1 (from Intel Docs)) */
176 add r31 = STACK_SCRATCH_AREA_SIZE, r12 ;;
178 ld8 r30 = [r31], +8 ;; /* load ar.bsp */
179 ld8 r29 = [r31], +8 ;; /* load ar.bspstore */
180 ld8 r28 = [r31], +8 ;; /* load ar.bspstore_new */
181 sub r27 = r30 , r28 ;; /* calculate loadrs (step 2) */
186 or r24 = r30 , r27 ;;
187 mov ar.rsc = r24 ;; /* place RSE in enforced lazy mode */
189 loadrs /* (step 3) */
191 ld8 r27 = [r31], +8 ;; /* load ar.rnat */
192 ld8 r26 = [r31], +8 ;; /* load cr.ifs */
193 ld8 r25 = [r31], +8 ;; /* load ar.pfs */
194 ld8 r24 = [r31], +8 ;; /* load ar.rsc */
196 mov ar.bspstore = r29 ;; /* (step 4) */
197 mov ar.rnat = r27 /* (step 5) */
199 mov ar.pfs = r25 /* (step 6) */
202 mov ar.rsc = r24 /* (step 7) */
204 /* 17. restore interruption state from memory stack */
205 ld8 r28 = [r31], +8 ;; /* load cr.ifa */
206 ld8 r27 = [r31], +8 ;; /* load cr.isr */
207 ld8 r26 = [r31], +8 ;; /* load cr.iipa */
208 ld8 r25 = [r31], +8 ;; /* load cr.ipsr */
209 ld8 r24 = [r31], +8 ;; /* load cr.iip */
217 /* 18. restore predicate registers from memory stack */
218 ld8 r29 = [r31], +8 ;; /* load predicate registers */
221 /* 19. return from interruption */
222 ld8 r12 = [r31] /* load stack pointer */
225 .global heavyweight_handler_inner
226 heavyweight_handler_inner:
228 * From this point, the rest of the interrupted context
229 * will be preserved in stacked registers and backing store.
231 alloc loc0 = ar.pfs, 0, 47, 2, 0 ;;
233 /* bank 0 is going to be shadowed, copy essential data from there */
234 mov loc1 = R_RET /* b0 belonging to interrupted context */
238 add out1 = STACK_SCRATCH_AREA_SIZE, r12
240 /* 6. switch to bank 1 and reenable PSR.ic */
245 /* 7. preserve branch and application registers */
262 /* 8. preserve general and floating-point registers */
263 /* TODO: save floating-point context */
275 /* skip r12 (stack pointer) */
296 /* 9. skipped (will not enable interrupts) */
303 /* 10. call handler */
304 movl r1 = _hardcoded_load_address
307 br.call.sptk.many b0 = b1
309 /* 11. return from handler */
312 /* 12. skipped (will not disable interrupts) */
319 /* 13. restore general and floating-point registers */
320 /* TODO: restore floating-point context */
332 /* skip r12 (stack pointer) */
353 /* 14. restore branch and application registers */
370 /* 15. disable PSR.ic and switch to bank 0 */
382 HEAVYWEIGHT_HANDLER 0x0000
383 HEAVYWEIGHT_HANDLER 0x0400
384 HEAVYWEIGHT_HANDLER 0x0800
385 HEAVYWEIGHT_HANDLER 0x0c00 alternate_instruction_tlb_fault
386 HEAVYWEIGHT_HANDLER 0x1000 alternate_data_tlb_fault
387 HEAVYWEIGHT_HANDLER 0x1400 data_nested_tlb_fault
388 HEAVYWEIGHT_HANDLER 0x1800
389 HEAVYWEIGHT_HANDLER 0x1c00
390 HEAVYWEIGHT_HANDLER 0x2000 data_dirty_bit_fault
391 HEAVYWEIGHT_HANDLER 0x2400 instruction_access_bit_fault
392 HEAVYWEIGHT_HANDLER 0x2800 data_access_bit_fault
393 HEAVYWEIGHT_HANDLER 0x2c00 break_instruction
394 HEAVYWEIGHT_HANDLER 0x3000 external_interrupt /* For external interrupt, heavyweight handler is used. */
395 HEAVYWEIGHT_HANDLER 0x3400
396 HEAVYWEIGHT_HANDLER 0x3800
397 HEAVYWEIGHT_HANDLER 0x3c00
398 HEAVYWEIGHT_HANDLER 0x4000
399 HEAVYWEIGHT_HANDLER 0x4400
400 HEAVYWEIGHT_HANDLER 0x4800
401 HEAVYWEIGHT_HANDLER 0x4c00
403 HEAVYWEIGHT_HANDLER 0x5000 page_not_present
404 HEAVYWEIGHT_HANDLER 0x5100
405 HEAVYWEIGHT_HANDLER 0x5200
406 HEAVYWEIGHT_HANDLER 0x5300
407 HEAVYWEIGHT_HANDLER 0x5400 general_exception
408 HEAVYWEIGHT_HANDLER 0x5500
409 HEAVYWEIGHT_HANDLER 0x5600
410 HEAVYWEIGHT_HANDLER 0x5700
411 HEAVYWEIGHT_HANDLER 0x5800
412 HEAVYWEIGHT_HANDLER 0x5900
413 HEAVYWEIGHT_HANDLER 0x5a00
414 HEAVYWEIGHT_HANDLER 0x5b00
415 HEAVYWEIGHT_HANDLER 0x5c00
416 HEAVYWEIGHT_HANDLER 0x5d00
417 HEAVYWEIGHT_HANDLER 0x5e00
418 HEAVYWEIGHT_HANDLER 0x5f00
420 HEAVYWEIGHT_HANDLER 0x6000
421 HEAVYWEIGHT_HANDLER 0x6100
422 HEAVYWEIGHT_HANDLER 0x6200
423 HEAVYWEIGHT_HANDLER 0x6300
424 HEAVYWEIGHT_HANDLER 0x6400
425 HEAVYWEIGHT_HANDLER 0x6500
426 HEAVYWEIGHT_HANDLER 0x6600
427 HEAVYWEIGHT_HANDLER 0x6700
428 HEAVYWEIGHT_HANDLER 0x6800
429 HEAVYWEIGHT_HANDLER 0x6900
430 HEAVYWEIGHT_HANDLER 0x6a00
431 HEAVYWEIGHT_HANDLER 0x6b00
432 HEAVYWEIGHT_HANDLER 0x6c00
433 HEAVYWEIGHT_HANDLER 0x6d00
434 HEAVYWEIGHT_HANDLER 0x6e00
435 HEAVYWEIGHT_HANDLER 0x6f00
437 HEAVYWEIGHT_HANDLER 0x7000
438 HEAVYWEIGHT_HANDLER 0x7100
439 HEAVYWEIGHT_HANDLER 0x7200
440 HEAVYWEIGHT_HANDLER 0x7300
441 HEAVYWEIGHT_HANDLER 0x7400
442 HEAVYWEIGHT_HANDLER 0x7500
443 HEAVYWEIGHT_HANDLER 0x7600
444 HEAVYWEIGHT_HANDLER 0x7700
445 HEAVYWEIGHT_HANDLER 0x7800
446 HEAVYWEIGHT_HANDLER 0x7900
447 HEAVYWEIGHT_HANDLER 0x7a00
448 HEAVYWEIGHT_HANDLER 0x7b00
449 HEAVYWEIGHT_HANDLER 0x7c00
450 HEAVYWEIGHT_HANDLER 0x7d00
451 HEAVYWEIGHT_HANDLER 0x7e00
452 HEAVYWEIGHT_HANDLER 0x7f00