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