1 | # @(#)cpu_asm.S 1.5 - 95/04/24 |
---|
2 | # |
---|
3 | # |
---|
4 | # TODO: |
---|
5 | # Context_switch needs to only save callee save registers |
---|
6 | # I think this means can skip: r1, r2, r19-29, r31 |
---|
7 | # Ref: p 3-2 of Procedure Calling Conventions Manual |
---|
8 | # This should be #ifndef DEBUG so that debugger has |
---|
9 | # accurate visibility into all registers |
---|
10 | # |
---|
11 | # This file contains the assembly code for the HPPA implementation |
---|
12 | # of RTEMS. |
---|
13 | # |
---|
14 | # COPYRIGHT (c) 1994,95 by Division Incorporated |
---|
15 | # |
---|
16 | # To anyone who acknowledges that this file is provided "AS IS" |
---|
17 | # without any express or implied warranty: |
---|
18 | # permission to use, copy, modify, and distribute this file |
---|
19 | # for any purpose is hereby granted without fee, provided that |
---|
20 | # the above copyright notice and this notice appears in all |
---|
21 | # copies, and that the name of Division Incorporated not be |
---|
22 | # used in advertising or publicity pertaining to distribution |
---|
23 | # of the software without specific, written prior permission. |
---|
24 | # Division Incorporated makes no representations about the |
---|
25 | # suitability of this software for any purpose. |
---|
26 | # |
---|
27 | # $Id$ |
---|
28 | # |
---|
29 | |
---|
30 | #include <rtems/hppa.h> |
---|
31 | #include <rtems/cpu_asm.h> |
---|
32 | #include <rtems/cpu.h> |
---|
33 | |
---|
34 | #include <offsets.h> |
---|
35 | |
---|
36 | .SPACE $PRIVATE$ |
---|
37 | .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31 |
---|
38 | .SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82 |
---|
39 | .SPACE $TEXT$ |
---|
40 | .SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44 |
---|
41 | .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY |
---|
42 | .SPACE $TEXT$ |
---|
43 | .SUBSPA $CODE$ |
---|
44 | |
---|
45 | # |
---|
46 | # Special register usage for context switch and interrupts |
---|
47 | # Stay away from %cr28 which is used for TLB misses on 72000 |
---|
48 | # |
---|
49 | |
---|
50 | isr_arg0 .reg %cr24 |
---|
51 | isr_r9 .reg %cr25 |
---|
52 | |
---|
53 | # |
---|
54 | # Interrupt stack frame looks like this |
---|
55 | # |
---|
56 | # offset item |
---|
57 | # ----------------------------------------------------------------- |
---|
58 | # INTEGER_CONTEXT_OFFSET Context_Control |
---|
59 | # FP_CONTEXT_OFFSET Context_Control_fp |
---|
60 | # |
---|
61 | # It is padded out to a multiple of 64 |
---|
62 | # |
---|
63 | |
---|
64 | |
---|
65 | # PAGE^L |
---|
66 | # void __Generic_ISR_Handler() |
---|
67 | # |
---|
68 | # This routine provides the RTEMS interrupt management. |
---|
69 | # |
---|
70 | # NOTE: |
---|
71 | # Upon entry, the stack will contain a stack frame back to the |
---|
72 | # interrupted task. If dispatching is enabled, this is the |
---|
73 | # outer most interrupt, (and a context switch is necessary or |
---|
74 | # the current task has signals), then set up the stack to |
---|
75 | # transfer control to the interrupt dispatcher. |
---|
76 | # |
---|
77 | # |
---|
78 | # We jump here from the interrupt vector. |
---|
79 | # The hardware has done some stuff for us: |
---|
80 | # PSW saved in IPSW |
---|
81 | # PSW set to 0 |
---|
82 | # PSW[E] set to default (0) |
---|
83 | # PSW[M] set to 1 iff this is HPMC |
---|
84 | # |
---|
85 | # IIA queue is frozen (since PSW[Q] is now 0) |
---|
86 | # privilege level promoted to 0 |
---|
87 | # IIR, ISR, IOR potentially updated if PSW[Q] was 1 at trap |
---|
88 | # registers GR 1,8,9,16,17,24,25 copied to shadow regs |
---|
89 | # SHR 0 1 2 3 4 5 6 |
---|
90 | # |
---|
91 | # Our vector stub did the following |
---|
92 | # placed vector number is in r1 |
---|
93 | # |
---|
94 | # stub |
---|
95 | # r1 <- vector number |
---|
96 | # save ipsw under rock |
---|
97 | # ipsw = ipsw & ~1 -- disable ints |
---|
98 | # save qregs under rock |
---|
99 | # qra = _Generic_ISR_handler |
---|
100 | # rfi |
---|
101 | # |
---|
102 | ################################################ |
---|
103 | |
---|
104 | # Distinct Interrupt Entry Points |
---|
105 | # |
---|
106 | # The following macro and the 32 instantiations of the macro |
---|
107 | # are necessary to determine which interrupt vector occurred. |
---|
108 | # The following macro allows a unique entry point to be defined |
---|
109 | # for each vector. |
---|
110 | # |
---|
111 | # r9 was loaded with the vector before branching here |
---|
112 | # scratch registers available: gr1, gr8, gr9, gr16, gr17, gr24 |
---|
113 | # |
---|
114 | # NOTE: |
---|
115 | # .align 32 doesn not seem to work in the continuation below |
---|
116 | # so just have to count 8 instructions |
---|
117 | # |
---|
118 | # NOTE: |
---|
119 | # this whole scheme needs to be rethought for TLB traps which |
---|
120 | # have requirements about what tlb faults they can incur. |
---|
121 | # ref: TLB Operation Requirements in 1.1 arch book |
---|
122 | |
---|
123 | #define THANDLER(vector) \ |
---|
124 | mtctl %r9, isr_r9 ! \ |
---|
125 | b _Generic_ISR_Handler! \ |
---|
126 | ldi vector, %r9! \ |
---|
127 | nop ! \ |
---|
128 | nop ! \ |
---|
129 | nop ! \ |
---|
130 | nop ! \ |
---|
131 | nop |
---|
132 | |
---|
133 | .align 4096 |
---|
134 | .EXPORT IVA_Table,ENTRY,PRIV_LEV=0 |
---|
135 | IVA_Table: |
---|
136 | .PROC |
---|
137 | .CALLINFO FRAME=0,NO_CALLS |
---|
138 | .ENTRY |
---|
139 | |
---|
140 | THANDLER(0) /* unused */ |
---|
141 | |
---|
142 | THANDLER(HPPA_INTERRUPT_HIGH_PRIORITY_MACHINE_CHECK) |
---|
143 | |
---|
144 | THANDLER(HPPA_INTERRUPT_POWER_FAIL) |
---|
145 | |
---|
146 | THANDLER(HPPA_INTERRUPT_RECOVERY_COUNTER) |
---|
147 | |
---|
148 | THANDLER(HPPA_INTERRUPT_EXTERNAL_INTERRUPT) |
---|
149 | |
---|
150 | THANDLER(HPPA_INTERRUPT_LOW_PRIORITY_MACHINE_CHECK) |
---|
151 | |
---|
152 | THANDLER(HPPA_INTERRUPT_INSTRUCTION_TLB_MISS) |
---|
153 | |
---|
154 | THANDLER(HPPA_INTERRUPT_INSTRUCTION_MEMORY_PROTECTION) |
---|
155 | |
---|
156 | THANDLER(HPPA_INTERRUPT_ILLEGAL_INSTRUCTION) |
---|
157 | |
---|
158 | THANDLER(HPPA_INTERRUPT_BREAK_INSTRUCTION) |
---|
159 | |
---|
160 | THANDLER(HPPA_INTERRUPT_PRIVILEGED_OPERATION) |
---|
161 | |
---|
162 | THANDLER(HPPA_INTERRUPT_PRIVILEGED_REGISTER) |
---|
163 | |
---|
164 | THANDLER(HPPA_INTERRUPT_OVERFLOW) |
---|
165 | |
---|
166 | THANDLER(HPPA_INTERRUPT_CONDITIONAL) |
---|
167 | |
---|
168 | THANDLER(HPPA_INTERRUPT_ASSIST_EXCEPTION) |
---|
169 | |
---|
170 | THANDLER(HPPA_INTERRUPT_DATA_TLB_MISS) |
---|
171 | |
---|
172 | THANDLER(HPPA_INTERRUPT_NON_ACCESS_INSTRUCTION_TLB_MISS) |
---|
173 | |
---|
174 | THANDLER(HPPA_INTERRUPT_NON_ACCESS_DATA_TLB_MISS) |
---|
175 | |
---|
176 | THANDLER(HPPA_INTERRUPT_DATA_MEMORY_PROTECTION) |
---|
177 | |
---|
178 | THANDLER(HPPA_INTERRUPT_DATA_MEMORY_BREAK) |
---|
179 | |
---|
180 | THANDLER(HPPA_INTERRUPT_TLB_DIRTY_BIT) |
---|
181 | |
---|
182 | THANDLER(HPPA_INTERRUPT_PAGE_REFERENCE) |
---|
183 | |
---|
184 | THANDLER(HPPA_INTERRUPT_ASSIST_EMULATION) |
---|
185 | |
---|
186 | THANDLER(HPPA_INTERRUPT_HIGHER_PRIVILEGE_TRANSFER) |
---|
187 | |
---|
188 | THANDLER(HPPA_INTERRUPT_LOWER_PRIVILEGE_TRANSFER) |
---|
189 | |
---|
190 | THANDLER(HPPA_INTERRUPT_TAKEN_BRANCH) |
---|
191 | |
---|
192 | THANDLER(HPPA_INTERRUPT_DATA_MEMORY_ACCESS_RIGHTS) |
---|
193 | |
---|
194 | THANDLER(HPPA_INTERRUPT_DATA_MEMORY_PROTECTION_ID) |
---|
195 | |
---|
196 | THANDLER(HPPA_INTERRUPT_UNALIGNED_DATA_REFERENCE) |
---|
197 | |
---|
198 | THANDLER(HPPA_INTERRUPT_PERFORMANCE_MONITOR) |
---|
199 | |
---|
200 | THANDLER(HPPA_INTERRUPT_INSTRUCTION_DEBUG) |
---|
201 | |
---|
202 | THANDLER(HPPA_INTERRUPT_DATA_DEBUG) |
---|
203 | |
---|
204 | .EXIT |
---|
205 | .PROCEND |
---|
206 | |
---|
207 | .EXPORT _Generic_ISR_Handler,ENTRY,PRIV_LEV=0 |
---|
208 | _Generic_ISR_Handler: |
---|
209 | .PROC |
---|
210 | .CALLINFO FRAME=0,NO_CALLS |
---|
211 | .ENTRY |
---|
212 | |
---|
213 | # Turn on the D bit in psw so we can start saving stuff on stack |
---|
214 | # (interrupt context pieces that need to be saved before the RFI) |
---|
215 | |
---|
216 | ssm HPPA_PSW_D, %r0 |
---|
217 | mtctl arg0, isr_arg0 |
---|
218 | |
---|
219 | # save interrupt state |
---|
220 | mfctl ipsw, arg0 |
---|
221 | stw arg0, IPSW_OFFSET(sp) |
---|
222 | |
---|
223 | mfctl iir, arg0 |
---|
224 | stw arg0, IIR_OFFSET(sp) |
---|
225 | |
---|
226 | mfctl ior, arg0 |
---|
227 | stw arg0, IOR_OFFSET(sp) |
---|
228 | |
---|
229 | mfctl pcoq, arg0 |
---|
230 | stw arg0, PCOQFRONT_OFFSET(sp) |
---|
231 | |
---|
232 | mtctl %r0, pcoq |
---|
233 | mfctl pcoq, arg0 |
---|
234 | stw arg0, PCOQBACK_OFFSET(sp) |
---|
235 | |
---|
236 | mfctl %sar, arg0 |
---|
237 | stw arg0, SAR_OFFSET(sp) |
---|
238 | |
---|
239 | # Prepare to re-enter virtual mode |
---|
240 | # We need Q in case the interrupt handler enables interrupts |
---|
241 | # |
---|
242 | |
---|
243 | ldil L%CPU_PSW_DEFAULT, arg0 |
---|
244 | ldo R%CPU_PSW_DEFAULT(arg0), arg0 |
---|
245 | mtctl arg0, ipsw |
---|
246 | |
---|
247 | # Now jump to "rest_of_isr_handler" with the rfi |
---|
248 | # We are assuming the space queues are all correct already |
---|
249 | |
---|
250 | ldil L%rest_of_isr_handler, arg0 |
---|
251 | ldo R%rest_of_isr_handler(arg0), arg0 |
---|
252 | mtctl arg0, pcoq |
---|
253 | ldo 4(arg0), arg0 |
---|
254 | mtctl arg0, pcoq |
---|
255 | |
---|
256 | rfi |
---|
257 | nop |
---|
258 | |
---|
259 | # At this point we are back in virtual mode and all our |
---|
260 | # normal addressing is once again ok. |
---|
261 | |
---|
262 | rest_of_isr_handler: |
---|
263 | |
---|
264 | # |
---|
265 | # Build an interrupt frame to hold the contexts we will need. |
---|
266 | # We have already saved the interrupt items on the stack |
---|
267 | |
---|
268 | # At this point the following registers are damaged wrt the interrupt |
---|
269 | # reg current value saved value |
---|
270 | # ------------------------------------------------ |
---|
271 | # arg0 scratch isr_arg0 (ctl) |
---|
272 | # r9 vector number isr_r9 (ctl) |
---|
273 | # |
---|
274 | # Point to beginning of integer context and |
---|
275 | # save the integer context |
---|
276 | stw %r1,R1_OFFSET(sp) |
---|
277 | stw %r2,R2_OFFSET(sp) |
---|
278 | stw %r3,R3_OFFSET(sp) |
---|
279 | stw %r4,R4_OFFSET(sp) |
---|
280 | stw %r5,R5_OFFSET(sp) |
---|
281 | stw %r6,R6_OFFSET(sp) |
---|
282 | stw %r7,R7_OFFSET(sp) |
---|
283 | stw %r8,R8_OFFSET(sp) |
---|
284 | stw %r9,R9_OFFSET(sp) |
---|
285 | stw %r10,R10_OFFSET(sp) |
---|
286 | stw %r11,R11_OFFSET(sp) |
---|
287 | stw %r12,R12_OFFSET(sp) |
---|
288 | stw %r13,R13_OFFSET(sp) |
---|
289 | stw %r14,R14_OFFSET(sp) |
---|
290 | stw %r15,R15_OFFSET(sp) |
---|
291 | stw %r16,R16_OFFSET(sp) |
---|
292 | stw %r17,R17_OFFSET(sp) |
---|
293 | stw %r18,R18_OFFSET(sp) |
---|
294 | stw %r19,R19_OFFSET(sp) |
---|
295 | stw %r20,R20_OFFSET(sp) |
---|
296 | stw %r21,R21_OFFSET(sp) |
---|
297 | stw %r22,R22_OFFSET(sp) |
---|
298 | stw %r23,R23_OFFSET(sp) |
---|
299 | stw %r24,R24_OFFSET(sp) |
---|
300 | stw %r25,R25_OFFSET(sp) |
---|
301 | stw %r26,R26_OFFSET(sp) |
---|
302 | stw %r27,R27_OFFSET(sp) |
---|
303 | stw %r28,R28_OFFSET(sp) |
---|
304 | stw %r29,R29_OFFSET(sp) |
---|
305 | stw %r30,R30_OFFSET(sp) |
---|
306 | stw %r31,R31_OFFSET(sp) |
---|
307 | |
---|
308 | # Now most registers are available since they have been saved |
---|
309 | # |
---|
310 | # The following items are currently wrong in the integer context |
---|
311 | # reg current value saved value |
---|
312 | # ------------------------------------------------ |
---|
313 | # arg0 scratch isr_arg0 (ctl) |
---|
314 | # r9 vector number isr_r9 (ctl) |
---|
315 | # |
---|
316 | # Fix them |
---|
317 | |
---|
318 | mfctl isr_arg0,%r3 |
---|
319 | stw %r3,ARG0_OFFSET(sp) |
---|
320 | |
---|
321 | mfctl isr_r9,%r3 |
---|
322 | stw %r3,R9_OFFSET(sp) |
---|
323 | |
---|
324 | # |
---|
325 | # At this point we are done with isr_arg0, and isr_r9 control registers |
---|
326 | # |
---|
327 | |
---|
328 | |
---|
329 | # Point to beginning of float context and |
---|
330 | # save the floating point context -- doing whatever patches are necessary |
---|
331 | .call ARGW0=GR |
---|
332 | bl _CPU_Save_float_context,%r2 |
---|
333 | ldo FP_CONTEXT_OFFSET(sp),arg0 |
---|
334 | |
---|
335 | # save the ptr to interrupt frame as an argument for the interrupt handler |
---|
336 | copy sp, arg1 |
---|
337 | |
---|
338 | # Advance the frame to point beyond all interrupt contexts (integer & float) |
---|
339 | # this also includes the pad to align to 64byte stack boundary |
---|
340 | ldo CPU_INTERRUPT_FRAME_SIZE(sp), sp |
---|
341 | |
---|
342 | # r3 -- &_ISR_Nest_level |
---|
343 | # r5 -- value _ISR_Nest_level |
---|
344 | # r4 -- &_Thread_Dispatch_disable_level |
---|
345 | # r6 -- value _Thread_Dispatch_disable_level |
---|
346 | # r9 -- vector number |
---|
347 | |
---|
348 | .import _ISR_Nest_level,data |
---|
349 | ldil L%_ISR_Nest_level,%r3 |
---|
350 | ldo R%_ISR_Nest_level(%r3),%r3 |
---|
351 | ldw 0(%r3),%r5 |
---|
352 | |
---|
353 | .import _Thread_Dispatch_disable_level,data |
---|
354 | ldil L%_Thread_Dispatch_disable_level,%r4 |
---|
355 | ldo R%_Thread_Dispatch_disable_level(%r4),%r4 |
---|
356 | ldw 0(%r4),%r6 |
---|
357 | |
---|
358 | # increment interrupt nest level counter. If outermost interrupt |
---|
359 | # switch the stack and squirrel away the previous sp. |
---|
360 | addi 1,%r5,%r5 |
---|
361 | stw %r5, 0(%r3) |
---|
362 | |
---|
363 | # compute and save new stack (with frame) |
---|
364 | # just in case we are nested -- simpler this way |
---|
365 | comibf,= 1,%r5,stack_done |
---|
366 | ldo 128(sp),%r7 |
---|
367 | |
---|
368 | # |
---|
369 | # Switch to interrupt stack allocated by the interrupt manager (intr.c) |
---|
370 | # |
---|
371 | .import _CPU_Interrupt_stack_low,data |
---|
372 | ldil L%_CPU_Interrupt_stack_low,%r7 |
---|
373 | ldw R%_CPU_Interrupt_stack_low(%r7),%r7 |
---|
374 | ldo 128(%r7),%r7 |
---|
375 | |
---|
376 | stack_done: |
---|
377 | # save our current stack pointer where the "old sp" is supposed to be |
---|
378 | stw sp, -4(%r7) |
---|
379 | # and switch stacks (or advance old stack in nested case) |
---|
380 | copy %r7, sp |
---|
381 | |
---|
382 | # increment the dispatch disable level counter. |
---|
383 | addi 1,%r6,%r6 |
---|
384 | stw %r6, 0(%r4) |
---|
385 | |
---|
386 | # load address of user handler |
---|
387 | .import _ISR_Vector_table,data |
---|
388 | ldil L%_ISR_Vector_table,%r8 |
---|
389 | ldo R%_ISR_Vector_table(%r8),%r8 |
---|
390 | ldwx,s %r9(%r8),%r8 |
---|
391 | |
---|
392 | # invoke user interrupt handler |
---|
393 | # Interrupts are currently disabled, as per RTEMS convention |
---|
394 | # The handler has the option of re-enabling interrupts |
---|
395 | # NOTE: can not use 'bl' since it uses "pc-relative" addressing |
---|
396 | # and we are using a hard coded address from a table |
---|
397 | # So... we fudge r2 ourselves (ala dynacall) |
---|
398 | # |
---|
399 | copy %r9, %r26 |
---|
400 | .call ARGW0=GR, ARGW1=GR |
---|
401 | blr %r0, rp |
---|
402 | bv,n 0(%r8) |
---|
403 | |
---|
404 | post_user_interrupt_handler: |
---|
405 | |
---|
406 | # Back from user handler(s) |
---|
407 | # Disable external interrupts (since the interrupt handler could |
---|
408 | # have turned them on) and return to the interrupted task stack (assuming |
---|
409 | # (_ISR_Nest_level == 0) |
---|
410 | |
---|
411 | rsm HPPA_PSW_I, %r0 |
---|
412 | ldw -4(sp), sp |
---|
413 | |
---|
414 | # r3 -- &_ISR_Nest_level |
---|
415 | # r5 -- value _ISR_Nest_level |
---|
416 | # r4 -- &_Thread_Dispatch_disable_level |
---|
417 | # r6 -- value _Thread_Dispatch_disable_level |
---|
418 | |
---|
419 | .import _ISR_Nest_level,data |
---|
420 | ldil L%_ISR_Nest_level,%r3 |
---|
421 | ldo R%_ISR_Nest_level(%r3),%r3 |
---|
422 | ldw 0(%r3),%r5 |
---|
423 | |
---|
424 | .import _Thread_Dispatch_disable_level,data |
---|
425 | ldil L%_Thread_Dispatch_disable_level,%r4 |
---|
426 | ldo R%_Thread_Dispatch_disable_level(%r4),%r4 |
---|
427 | ldw 0(%r4), %r6 |
---|
428 | |
---|
429 | # decrement isr nest level |
---|
430 | addi -1, %r5, %r5 |
---|
431 | stw %r5, 0(%r3) |
---|
432 | |
---|
433 | # decrement dispatch disable level counter and, if not 0, go on |
---|
434 | addi -1,%r6,%r6 |
---|
435 | comibf,= 0,%r6,isr_restore |
---|
436 | stw %r6, 0(%r4) |
---|
437 | |
---|
438 | # check whether or not a context switch is necessary |
---|
439 | .import _Context_Switch_necessary,data |
---|
440 | ldil L%_Context_Switch_necessary,%r8 |
---|
441 | ldw R%_Context_Switch_necessary(%r8),%r8 |
---|
442 | comibf,=,n 0,%r8,ISR_dispatch |
---|
443 | |
---|
444 | # check whether or not a context switch is necessary because an ISR |
---|
445 | # sent signals to the interrupted task |
---|
446 | .import _ISR_Signals_to_thread_executing,data |
---|
447 | ldil L%_ISR_Signals_to_thread_executing,%r8 |
---|
448 | ldw R%_ISR_Signals_to_thread_executing(%r8),%r8 |
---|
449 | comibt,=,n 0,%r8,isr_restore |
---|
450 | |
---|
451 | # OK, something happened while in ISR and we need to switch to a task |
---|
452 | # other than the one which was interrupted or the |
---|
453 | # ISR_Signals_to_thread_executing case |
---|
454 | # We also turn on interrupts, since the interrupted task had them |
---|
455 | # on (obviously :-) and Thread_Dispatch is happy to leave ints on. |
---|
456 | # |
---|
457 | |
---|
458 | ISR_dispatch: |
---|
459 | ssm HPPA_PSW_I, %r0 |
---|
460 | |
---|
461 | .import _Thread_Dispatch,code |
---|
462 | .call |
---|
463 | bl _Thread_Dispatch,%r2 |
---|
464 | ldo 128(sp),sp |
---|
465 | |
---|
466 | ldo -128(sp),sp |
---|
467 | |
---|
468 | rsm HPPA_PSW_I, %r0 |
---|
469 | |
---|
470 | isr_restore: |
---|
471 | |
---|
472 | # Get a pointer to beginning of our stack frame |
---|
473 | ldo -CPU_INTERRUPT_FRAME_SIZE(sp), %arg1 |
---|
474 | |
---|
475 | # restore float |
---|
476 | .call ARGW0=GR |
---|
477 | bl _CPU_Restore_float_context,%r2 |
---|
478 | ldo FP_CONTEXT_OFFSET(%arg1), arg0 |
---|
479 | |
---|
480 | copy %arg1, %arg0 |
---|
481 | |
---|
482 | # ********** FALL THRU ********** |
---|
483 | |
---|
484 | # Jump here from bottom of Context_Switch |
---|
485 | # Also called directly by _CPU_Context_Restart_self via _Thread_Restart_self |
---|
486 | # restore interrupt state |
---|
487 | # |
---|
488 | |
---|
489 | .EXPORT _CPU_Context_restore |
---|
490 | _CPU_Context_restore: |
---|
491 | |
---|
492 | # Turn off Q & I so we can write pcoq |
---|
493 | rsm HPPA_PSW_Q + HPPA_PSW_I, %r0 |
---|
494 | |
---|
495 | ldw IPSW_OFFSET(arg0), %r8 |
---|
496 | mtctl %r8, ipsw |
---|
497 | |
---|
498 | ldw SAR_OFFSET(arg0), %r9 |
---|
499 | mtctl %r9, sar |
---|
500 | |
---|
501 | ldw PCOQFRONT_OFFSET(arg0), %r10 |
---|
502 | mtctl %r10, pcoq |
---|
503 | |
---|
504 | ldw PCOQBACK_OFFSET(arg0), %r11 |
---|
505 | mtctl %r11, pcoq |
---|
506 | |
---|
507 | # |
---|
508 | # restore integer state |
---|
509 | # |
---|
510 | ldw R1_OFFSET(arg0),%r1 |
---|
511 | ldw R2_OFFSET(arg0),%r2 |
---|
512 | ldw R3_OFFSET(arg0),%r3 |
---|
513 | ldw R4_OFFSET(arg0),%r4 |
---|
514 | ldw R5_OFFSET(arg0),%r5 |
---|
515 | ldw R6_OFFSET(arg0),%r6 |
---|
516 | ldw R7_OFFSET(arg0),%r7 |
---|
517 | ldw R8_OFFSET(arg0),%r8 |
---|
518 | ldw R9_OFFSET(arg0),%r9 |
---|
519 | ldw R10_OFFSET(arg0),%r10 |
---|
520 | ldw R11_OFFSET(arg0),%r11 |
---|
521 | ldw R12_OFFSET(arg0),%r12 |
---|
522 | ldw R13_OFFSET(arg0),%r13 |
---|
523 | ldw R14_OFFSET(arg0),%r14 |
---|
524 | ldw R15_OFFSET(arg0),%r15 |
---|
525 | ldw R16_OFFSET(arg0),%r16 |
---|
526 | ldw R17_OFFSET(arg0),%r17 |
---|
527 | ldw R18_OFFSET(arg0),%r18 |
---|
528 | ldw R19_OFFSET(arg0),%r19 |
---|
529 | ldw R20_OFFSET(arg0),%r20 |
---|
530 | ldw R21_OFFSET(arg0),%r21 |
---|
531 | ldw R22_OFFSET(arg0),%r22 |
---|
532 | ldw R23_OFFSET(arg0),%r23 |
---|
533 | ldw R24_OFFSET(arg0),%r24 |
---|
534 | ldw R25_OFFSET(arg0),%r25 |
---|
535 | # skipping r26 (aka arg0) until we are done with it |
---|
536 | ldw R27_OFFSET(arg0),%r27 |
---|
537 | ldw R28_OFFSET(arg0),%r28 |
---|
538 | ldw R29_OFFSET(arg0),%r29 |
---|
539 | ldw R30_OFFSET(arg0),%r30 |
---|
540 | ldw R31_OFFSET(arg0),%r31 |
---|
541 | |
---|
542 | # Must load r26 last since it is arg0 |
---|
543 | ldw R26_OFFSET(arg0),%r26 |
---|
544 | |
---|
545 | isr_exit: |
---|
546 | rfi |
---|
547 | .EXIT |
---|
548 | .PROCEND |
---|
549 | |
---|
550 | # |
---|
551 | # This section is used to context switch floating point registers. |
---|
552 | # Ref: 6-35 of Architecture 1.1 |
---|
553 | # |
---|
554 | # NOTE: since integer multiply uses the floating point unit, |
---|
555 | # we have to save/restore fp on every trap. We cannot |
---|
556 | # just try to keep track of fp usage. |
---|
557 | |
---|
558 | .align 32 |
---|
559 | .EXPORT _CPU_Save_float_context,ENTRY,PRIV_LEV=0 |
---|
560 | _CPU_Save_float_context: |
---|
561 | .PROC |
---|
562 | .CALLINFO FRAME=0,NO_CALLS |
---|
563 | .ENTRY |
---|
564 | fstds,ma %fr0,8(%arg0) |
---|
565 | fstds,ma %fr1,8(%arg0) |
---|
566 | fstds,ma %fr2,8(%arg0) |
---|
567 | fstds,ma %fr3,8(%arg0) |
---|
568 | fstds,ma %fr4,8(%arg0) |
---|
569 | fstds,ma %fr5,8(%arg0) |
---|
570 | fstds,ma %fr6,8(%arg0) |
---|
571 | fstds,ma %fr7,8(%arg0) |
---|
572 | fstds,ma %fr8,8(%arg0) |
---|
573 | fstds,ma %fr9,8(%arg0) |
---|
574 | fstds,ma %fr10,8(%arg0) |
---|
575 | fstds,ma %fr11,8(%arg0) |
---|
576 | fstds,ma %fr12,8(%arg0) |
---|
577 | fstds,ma %fr13,8(%arg0) |
---|
578 | fstds,ma %fr14,8(%arg0) |
---|
579 | fstds,ma %fr15,8(%arg0) |
---|
580 | fstds,ma %fr16,8(%arg0) |
---|
581 | fstds,ma %fr17,8(%arg0) |
---|
582 | fstds,ma %fr18,8(%arg0) |
---|
583 | fstds,ma %fr19,8(%arg0) |
---|
584 | fstds,ma %fr20,8(%arg0) |
---|
585 | fstds,ma %fr21,8(%arg0) |
---|
586 | fstds,ma %fr22,8(%arg0) |
---|
587 | fstds,ma %fr23,8(%arg0) |
---|
588 | fstds,ma %fr24,8(%arg0) |
---|
589 | fstds,ma %fr25,8(%arg0) |
---|
590 | fstds,ma %fr26,8(%arg0) |
---|
591 | fstds,ma %fr27,8(%arg0) |
---|
592 | fstds,ma %fr28,8(%arg0) |
---|
593 | fstds,ma %fr29,8(%arg0) |
---|
594 | fstds,ma %fr30,8(%arg0) |
---|
595 | fstds %fr31,0(%arg0) |
---|
596 | bv 0(%r2) |
---|
597 | addi -(31*8), %arg0, %arg0 ; restore arg0 just for fun |
---|
598 | .EXIT |
---|
599 | .PROCEND |
---|
600 | |
---|
601 | .align 32 |
---|
602 | .EXPORT _CPU_Restore_float_context,ENTRY,PRIV_LEV=0 |
---|
603 | _CPU_Restore_float_context: |
---|
604 | .PROC |
---|
605 | .CALLINFO FRAME=0,NO_CALLS |
---|
606 | .ENTRY |
---|
607 | addi (31*8), %arg0, %arg0 ; point at last double |
---|
608 | fldds 0(%arg0),%fr31 |
---|
609 | fldds,mb -8(%arg0),%fr30 |
---|
610 | fldds,mb -8(%arg0),%fr29 |
---|
611 | fldds,mb -8(%arg0),%fr28 |
---|
612 | fldds,mb -8(%arg0),%fr27 |
---|
613 | fldds,mb -8(%arg0),%fr26 |
---|
614 | fldds,mb -8(%arg0),%fr25 |
---|
615 | fldds,mb -8(%arg0),%fr24 |
---|
616 | fldds,mb -8(%arg0),%fr23 |
---|
617 | fldds,mb -8(%arg0),%fr22 |
---|
618 | fldds,mb -8(%arg0),%fr21 |
---|
619 | fldds,mb -8(%arg0),%fr20 |
---|
620 | fldds,mb -8(%arg0),%fr19 |
---|
621 | fldds,mb -8(%arg0),%fr18 |
---|
622 | fldds,mb -8(%arg0),%fr17 |
---|
623 | fldds,mb -8(%arg0),%fr16 |
---|
624 | fldds,mb -8(%arg0),%fr15 |
---|
625 | fldds,mb -8(%arg0),%fr14 |
---|
626 | fldds,mb -8(%arg0),%fr13 |
---|
627 | fldds,mb -8(%arg0),%fr12 |
---|
628 | fldds,mb -8(%arg0),%fr11 |
---|
629 | fldds,mb -8(%arg0),%fr10 |
---|
630 | fldds,mb -8(%arg0),%fr9 |
---|
631 | fldds,mb -8(%arg0),%fr8 |
---|
632 | fldds,mb -8(%arg0),%fr7 |
---|
633 | fldds,mb -8(%arg0),%fr6 |
---|
634 | fldds,mb -8(%arg0),%fr5 |
---|
635 | fldds,mb -8(%arg0),%fr4 |
---|
636 | fldds,mb -8(%arg0),%fr3 |
---|
637 | fldds,mb -8(%arg0),%fr2 |
---|
638 | fldds,mb -8(%arg0),%fr1 |
---|
639 | bv 0(%r2) |
---|
640 | fldds,mb -8(%arg0),%fr0 |
---|
641 | .EXIT |
---|
642 | .PROCEND |
---|
643 | |
---|
644 | # |
---|
645 | # These 2 small routines are unused right now. |
---|
646 | # Normally we just go thru _CPU_Save_float_context (and Restore) |
---|
647 | # |
---|
648 | # Here we just deref the ptr and jump up, letting _CPU_Save_float_context |
---|
649 | # do the return for us. |
---|
650 | # |
---|
651 | .EXPORT _CPU_Context_save_fp,ENTRY,PRIV_LEV=0 |
---|
652 | _CPU_Context_save_fp: |
---|
653 | .PROC |
---|
654 | .CALLINFO FRAME=0,NO_CALLS |
---|
655 | .ENTRY |
---|
656 | bl _CPU_Save_float_context, %r0 |
---|
657 | ldw 0(%arg0), %arg0 |
---|
658 | .EXIT |
---|
659 | .PROCEND |
---|
660 | |
---|
661 | .EXPORT _CPU_Context_restore_fp,ENTRY,PRIV_LEV=0 |
---|
662 | _CPU_Context_restore_fp: |
---|
663 | .PROC |
---|
664 | .CALLINFO FRAME=0,NO_CALLS |
---|
665 | .ENTRY |
---|
666 | bl _CPU_Restore_float_context, %r0 |
---|
667 | ldw 0(%arg0), %arg0 |
---|
668 | .EXIT |
---|
669 | .PROCEND |
---|
670 | |
---|
671 | |
---|
672 | # void _CPU_Context_switch( run_context, heir_context ) |
---|
673 | # |
---|
674 | # This routine performs a normal non-FP context switch. |
---|
675 | # |
---|
676 | |
---|
677 | .align 32 |
---|
678 | .EXPORT _CPU_Context_switch,ENTRY,PRIV_LEV=0,ARGW0=GR,ARGW1=GR |
---|
679 | _CPU_Context_switch: |
---|
680 | .PROC |
---|
681 | .CALLINFO FRAME=64 |
---|
682 | .ENTRY |
---|
683 | |
---|
684 | # Save the integer context |
---|
685 | stw %r1,R1_OFFSET(arg0) |
---|
686 | stw %r2,R2_OFFSET(arg0) |
---|
687 | stw %r3,R3_OFFSET(arg0) |
---|
688 | stw %r4,R4_OFFSET(arg0) |
---|
689 | stw %r5,R5_OFFSET(arg0) |
---|
690 | stw %r6,R6_OFFSET(arg0) |
---|
691 | stw %r7,R7_OFFSET(arg0) |
---|
692 | stw %r8,R8_OFFSET(arg0) |
---|
693 | stw %r9,R9_OFFSET(arg0) |
---|
694 | stw %r10,R10_OFFSET(arg0) |
---|
695 | stw %r11,R11_OFFSET(arg0) |
---|
696 | stw %r12,R12_OFFSET(arg0) |
---|
697 | stw %r13,R13_OFFSET(arg0) |
---|
698 | stw %r14,R14_OFFSET(arg0) |
---|
699 | stw %r15,R15_OFFSET(arg0) |
---|
700 | stw %r16,R16_OFFSET(arg0) |
---|
701 | stw %r17,R17_OFFSET(arg0) |
---|
702 | stw %r18,R18_OFFSET(arg0) |
---|
703 | stw %r19,R19_OFFSET(arg0) |
---|
704 | stw %r20,R20_OFFSET(arg0) |
---|
705 | stw %r21,R21_OFFSET(arg0) |
---|
706 | stw %r22,R22_OFFSET(arg0) |
---|
707 | stw %r23,R23_OFFSET(arg0) |
---|
708 | stw %r24,R24_OFFSET(arg0) |
---|
709 | stw %r25,R25_OFFSET(arg0) |
---|
710 | stw %r26,R26_OFFSET(arg0) |
---|
711 | stw %r27,R27_OFFSET(arg0) |
---|
712 | stw %r28,R28_OFFSET(arg0) |
---|
713 | stw %r29,R29_OFFSET(arg0) |
---|
714 | stw %r30,R30_OFFSET(arg0) |
---|
715 | stw %r31,R31_OFFSET(arg0) |
---|
716 | |
---|
717 | # fill in interrupt context section |
---|
718 | stw %r2, PCOQFRONT_OFFSET(%arg0) |
---|
719 | ldo 4(%r2), %r2 |
---|
720 | stw %r2, PCOQBACK_OFFSET(%arg0) |
---|
721 | |
---|
722 | # Generate a suitable IPSW by using the system default psw |
---|
723 | # with the current low bits added in. |
---|
724 | |
---|
725 | ldil L%CPU_PSW_DEFAULT, %r2 |
---|
726 | ldo R%CPU_PSW_DEFAULT(%r2), %r2 |
---|
727 | ssm 0, %arg2 |
---|
728 | dep %arg2, 31, 8, %r2 |
---|
729 | stw %r2, IPSW_OFFSET(%arg0) |
---|
730 | |
---|
731 | # at this point, the running task context is completely saved |
---|
732 | # Now jump to the bottom of the interrupt handler to load the |
---|
733 | # heirs context |
---|
734 | |
---|
735 | b _CPU_Context_restore |
---|
736 | copy %arg1, %arg0 |
---|
737 | |
---|
738 | .EXIT |
---|
739 | .PROCEND |
---|
740 | |
---|
741 | |
---|
742 | /* |
---|
743 | * Find first bit |
---|
744 | * NOTE: |
---|
745 | * This is used (and written) only for the ready chain code and |
---|
746 | * priority bit maps. |
---|
747 | * Any other use constitutes fraud. |
---|
748 | * Returns first bit from the least significant side. |
---|
749 | * Eg: if input is 0x8001 |
---|
750 | * output will indicate the '1' bit and return 0. |
---|
751 | * This is counter to HPPA bit numbering which calls this |
---|
752 | * bit 31. This way simplifies the macros _CPU_Priority_Mask |
---|
753 | * and _CPU_Priority_Bits_index. |
---|
754 | * |
---|
755 | * NOTE: |
---|
756 | * We just use 16 bit version |
---|
757 | * does not handle zero case |
---|
758 | * |
---|
759 | * Based on the UTAH Mach libc version of ffs. |
---|
760 | */ |
---|
761 | |
---|
762 | .align 32 |
---|
763 | .EXPORT hppa_rtems_ffs,ENTRY,PRIV_LEV=0,ARGW0=GR |
---|
764 | hppa_rtems_ffs: |
---|
765 | .PROC |
---|
766 | .CALLINFO FRAME=0,NO_CALLS |
---|
767 | .ENTRY |
---|
768 | |
---|
769 | #ifdef RETURN_ERROR_ON_ZERO |
---|
770 | comb,= %arg0,%r0,ffsdone ; If arg0 is 0 |
---|
771 | ldi -1,%ret0 ; return -1 |
---|
772 | #endif |
---|
773 | |
---|
774 | #if BITFIELD_SIZE == 32 |
---|
775 | ldi 31,%ret0 ; Set return to high bit |
---|
776 | extru,= %arg0,31,16,%r0 ; If low 16 bits are non-zero |
---|
777 | addi,tr -16,%ret0,%ret0 ; subtract 16 from bitpos |
---|
778 | shd %r0,%arg0,16,%arg0 ; else shift right 16 bits |
---|
779 | #else |
---|
780 | ldi 15,%ret0 ; Set return to high bit |
---|
781 | #endif |
---|
782 | extru,= %arg0,31,8,%r0 ; If low 8 bits are non-zero |
---|
783 | addi,tr -8,%ret0,%ret0 ; subtract 8 from bitpos |
---|
784 | shd %r0,%arg0,8,%arg0 ; else shift right 8 bits |
---|
785 | extru,= %arg0,31,4,%r0 ; If low 4 bits are non-zero |
---|
786 | addi,tr -4,%ret0,%ret0 ; subtract 4 from bitpos |
---|
787 | shd %r0,%arg0,4,%arg0 ; else shift right 4 bits |
---|
788 | extru,= %arg0,31,2,%r0 ; If low 2 bits are non-zero |
---|
789 | addi,tr -2,%ret0,%ret0 ; subtract 2 from bitpos |
---|
790 | shd %r0,%arg0,2,%arg0 ; else shift right 2 bits |
---|
791 | extru,= %arg0,31,1,%r0 ; If low bit is non-zero |
---|
792 | addi -1,%ret0,%ret0 ; subtract 1 from bitpos |
---|
793 | ffsdone: |
---|
794 | bv,n 0(%r2) |
---|
795 | nop |
---|
796 | .EXIT |
---|
797 | .PROCEND |
---|