2 // assembly portion of the IA64 MCA handling
4 // Mods by cfleck to integrate into kernel build
5 // 00/03/15 davidm Added various stop bits to get a clean compile
7 // 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp
8 // kstack, switch modes, jump to C INIT handler
10 #include <linux/config.h>
11 #include <asm/pgtable.h>
12 #include <asm/processor.h>
13 #include <asm/mca_asm.h>
17 * When we get an machine check, the kernel stack pointer is no longer
18 * valid, so we need to set a new stack pointer.
20 #define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */
29 * SAL_TO_OS_MCA_HANDOFF_STATE
31 * 2. GR8 = PAL_PROC physical address
32 * 3. GR9 = SAL_PROC physical address
33 * 4. GR10 = SAL GP (physical)
34 * 5. GR11 = Rendez state
35 * 6. GR12 = Return address to location within SAL_CHECK
37 #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \
38 movl _tmp=ia64_sal_to_os_handoff_state;; \
39 st8 [_tmp]=r1,0x08;; \
40 st8 [_tmp]=r8,0x08;; \
41 st8 [_tmp]=r9,0x08;; \
42 st8 [_tmp]=r10,0x08;; \
43 st8 [_tmp]=r11,0x08;; \
47 * OS_MCA_TO_SAL_HANDOFF_STATE
48 * 1. GR8 = OS_MCA status
49 * 2. GR9 = SAL GP (physical)
50 * 3. GR22 = New min state save area pointer
52 #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \
53 movl _tmp=ia64_os_to_sal_handoff_state;; \
54 DATA_VA_TO_PA(_tmp);; \
55 ld8 r8=[_tmp],0x08;; \
56 ld8 r9=[_tmp],0x08;; \
61 * Jump to the instruction referenced by
63 * Branch is taken only if the predicate
64 * register "p" is true.
65 * "ip" is the address of the instruction
66 * located at "from_label".
67 * "temp" is a scratch register like r2
68 * "adjust" needed for HP compiler.
69 * A screwup somewhere with constant arithmetic.
71 #define BRANCH(to_label, temp, p, adjust) \
72 100: (p) mov temp=ip; \
74 (p) adds temp=to_label-100b,temp;\
76 (p) adds temp=adjust,temp; \
81 .global ia64_os_mca_dispatch
82 .global ia64_os_mca_dispatch_end
83 .global ia64_sal_to_os_handoff_state
84 .global ia64_os_to_sal_handoff_state
85 .global ia64_os_mca_ucmc_handler
86 .global ia64_mca_proc_state_dump
87 .global ia64_mca_proc_state_restore
88 .global ia64_mca_stack
89 .global ia64_mca_stackframe
90 .global ia64_mca_bspstore
91 .global ia64_init_stack
99 // Pretend that we are in interrupt context
101 dep r2=0, r2, PSR_IC, 2;
103 #endif /* #if defined(MCA_TEST) */
105 // Save the SAL to OS MCA handoff state as defined
107 // NOTE : The order in which the state gets saved
108 // is dependent on the way the C-structure
109 // for ia64_mca_sal_to_os_state_t has been
110 // defined in include/asm/mca.h
111 SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
113 // LOG PROCESSOR STATE INFO FROM HERE ON..
116 BRANCH(ia64_os_mca_proc_state_dump, r2, p0, 0x0)
118 ia64_os_mca_done_dump:
120 // Setup new stack frame for OS_MCA handling
121 movl r2=ia64_mca_bspstore // local bspstore area location in r2
122 movl r3=ia64_mca_stackframe // save stack frame to memory in r3
123 rse_switch_context(r6,r3,r2);; // RSC management in this new context
124 movl r12=ia64_mca_stack;;
126 // Enter virtual mode from physical mode
127 VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
128 ia64_os_mca_virtual_begin:
131 movl r2=ia64_mca_ucmc_handler;;
133 br.call.sptk.few b0=b6
135 // Revert back to physical mode before going back to SAL
136 PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4)
137 ia64_os_mca_virtual_end:
139 #if defined(MCA_TEST)
140 // Pretend that we are in interrupt context
142 dep r2=0, r2, PSR_IC, 2;
144 #endif /* #if defined(MCA_TEST) */
146 // restore the original stack frame here
147 movl r2=ia64_mca_stackframe // restore stack frame from memory at r2
152 rse_return_context(r4,r3,r2) // switch from interrupt context for RSE
154 // let us restore all the registers from our PSI structure
157 begin_os_mca_restore:
158 BRANCH(ia64_os_mca_proc_state_restore, r2, p0, 0x0)
161 ia64_os_mca_done_restore:
164 VIRTUAL_MODE_ENTER(r2,r3, vmode_enter, r4)
168 // branch back to SALE_CHECK
169 OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2)
171 mov b0=r3 // SAL_CHECK return address
174 #endif /* #ifdef SOFTSDV */
175 ia64_os_mca_dispatch_end:
176 //EndMain//////////////////////////////////////////////////////////////////////
181 // ia64_os_mca_proc_state_dump()
185 // This stub dumps the processor state during MCHK to a data area
189 ia64_os_mca_proc_state_dump:
190 // Get and save GR0-31 from Proc. Min. State Save Area to SAL PSI
191 movl r2=ia64_mca_proc_state_dump;; // Os state dump area
194 mov r5=ar.unat // ar.unat
196 // save banked GRs 16-31 along with NaT bits
198 st8.spill [r2]=r16,8;;
199 st8.spill [r2]=r17,8;;
200 st8.spill [r2]=r18,8;;
201 st8.spill [r2]=r19,8;;
202 st8.spill [r2]=r20,8;;
203 st8.spill [r2]=r21,8;;
204 st8.spill [r2]=r22,8;;
205 st8.spill [r2]=r23,8;;
206 st8.spill [r2]=r24,8;;
207 st8.spill [r2]=r25,8;;
208 st8.spill [r2]=r26,8;;
209 st8.spill [r2]=r27,8;;
210 st8.spill [r2]=r28,8;;
211 st8.spill [r2]=r29,8;;
212 st8.spill [r2]=r30,8;;
213 st8.spill [r2]=r31,8;;
216 st8 [r2]=r4,8 // save User NaT bits for r16-r31
217 mov ar.unat=r5 // restore original unat
221 add r4=8,r2 // duplicate r2 in r4
222 add r6=2*8,r2 // duplicate r2 in r4
245 add r4=8,r2 // duplicate r2 in r4
246 add r6=2*8,r2 // duplicate r2 in r4
250 mov r7=cr2;; // cr.iva
254 st8 [r6]=r7,3*8;; // 48 byte rements
256 mov r3=cr8;; // cr.pta
257 st8 [r2]=r3,8*8;; // 64 byte rements
259 // if PSR.ic=0, reading interruption registers causes an illegal operation fault
261 tbit.nz.unc p2,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test
262 (p2) st8 [r2]=r0,9*8+160 // increment by 168 byte inc.
263 begin_skip_intr_regs:
264 BRANCH(SkipIntrRegs, r9, p2, 0x0)
266 add r4=8,r2 // duplicate r2 in r4
267 add r6=2*8,r2 // duplicate r2 in r6
269 mov r3=cr16 // cr.ipsr
270 mov r5=cr17 // cr.isr
271 mov r7=r0;; // cr.ida => cr18
276 mov r3=cr19 // cr.iip
277 mov r5=cr20 // cr.idtr
278 mov r7=cr21;; // cr.iitr
283 mov r3=cr22 // cr.iipa
284 mov r5=cr23 // cr.ifs
285 mov r7=cr24;; // cr.iim
290 mov r3=cr25;; // cr.iha
291 st8 [r2]=r3,160;; // 160 byte rement
294 st8 [r2]=r0,168 // another 168 byte .
296 mov r3=cr66;; // cr.lid
297 st8 [r2]=r3,40 // 40 byte rement
299 mov r3=cr71;; // cr.ivr
302 mov r3=cr72;; // cr.tpr
303 st8 [r2]=r3,24 // 24 byte increment
305 mov r3=r0;; // cr.eoi => cr75
306 st8 [r2]=r3,168 // 168 byte inc.
308 mov r3=r0;; // cr.irr0 => cr96
309 st8 [r2]=r3,16 // 16 byte inc.
311 mov r3=r0;; // cr.irr1 => cr98
312 st8 [r2]=r3,16 // 16 byte inc.
314 mov r3=r0;; // cr.irr2 => cr100
315 st8 [r2]=r3,16 // 16 byte inc
317 mov r3=r0;; // cr.irr3 => cr100
318 st8 [r2]=r3,16 // 16b inc.
320 mov r3=r0;; // cr.itv => cr114
321 st8 [r2]=r3,16 // 16 byte inc.
323 mov r3=r0;; // cr.pmv => cr116
326 mov r3=r0;; // cr.lrr0 => cr117
329 mov r3=r0;; // cr.lrr1 => cr118
332 mov r3=r0;; // cr.cmcv => cr119
337 add r4=8,r2 // duplicate r2 in r4
338 add r6=2*8,r2 // duplicate r2 in r6
342 mov r7=ar2;; // ar.kr2
349 mov r7=ar5;; // ar.kr5
356 mov r7=r0;; // ar.kr8
359 st8 [r6]=r7,10*8;; // rement by 72 bytes
361 mov r3=ar16 // ar.rsc
362 mov ar16=r0 // put RSE in enforced lazy mode
363 mov r5=ar17 // ar.bsp
365 mov r7=ar18;; // ar.bspstore
370 mov r3=ar19;; // ar.rnat
371 st8 [r2]=r3,8*13 // increment by 13x8 bytes
373 mov r3=ar32;; // ar.ccv
376 mov r3=ar36;; // ar.unat
379 mov r3=ar40;; // ar.fpsr
382 mov r3=ar44;; // ar.itc
383 st8 [r2]=r3,160 // 160
385 mov r3=ar64;; // ar.pfs
388 mov r3=ar65;; // ar.lc
391 mov r3=ar66;; // ar.ec
393 add r2=8*62,r2 //padding
403 br.cloop.sptk.few cStRR
406 BRANCH(ia64_os_mca_done_dump, r2, p0, -0x10)
409 //EndStub//////////////////////////////////////////////////////////////////////
414 // ia64_os_mca_proc_state_restore()
418 // This is a stub to restore the saved processor state during MCHK
422 ia64_os_mca_proc_state_restore:
424 // Restore bank1 GR16-31
425 movl r2=ia64_mca_proc_state_dump // Convert virtual address
426 ;; // of OS state dump area
427 DATA_VA_TO_PA(r2) // to physical address
429 restore_GRs: // restore bank-1 GRs 16-31
431 add r3=16*8,r2;; // to get to NaT of GR 16-31
433 mov ar.unat=r3;; // first restore NaT
435 ld8.fill r16=[r2],8;;
436 ld8.fill r17=[r2],8;;
437 ld8.fill r18=[r2],8;;
438 ld8.fill r19=[r2],8;;
439 ld8.fill r20=[r2],8;;
440 ld8.fill r21=[r2],8;;
441 ld8.fill r22=[r2],8;;
442 ld8.fill r23=[r2],8;;
443 ld8.fill r24=[r2],8;;
444 ld8.fill r25=[r2],8;;
445 ld8.fill r26=[r2],8;;
446 ld8.fill r27=[r2],8;;
447 ld8.fill r28=[r2],8;;
448 ld8.fill r29=[r2],8;;
449 ld8.fill r30=[r2],8;;
450 ld8.fill r31=[r2],8;;
452 ld8 r3=[r2],8;; // increment to skip NaT
456 add r4=8,r2 // duplicate r2 in r4
457 add r6=2*8,r2;; // duplicate r2 in r4
479 add r4=8,r2 // duplicate r2 in r4
480 add r6=2*8,r2;; // duplicate r2 in r4
484 ld8 r7=[r6],3*8;; // 48 byte increments
487 mov cr2=r7;; // cr.iva
489 ld8 r3=[r2],8*8;; // 64 byte increments
490 // mov cr8=r3 // cr.pta
493 // if PSR.ic=1, reading interruption registers causes an illegal operation fault
495 tbit.nz.unc p2,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test
496 (p2) st8 [r2]=r0,9*8+160 // increment by 160 byte inc.
498 begin_rskip_intr_regs:
499 BRANCH(rSkipIntrRegs, r9, p2, 0x0)
502 add r4=8,r2 // duplicate r2 in r4
503 add r6=2*8,r2;; // duplicate r2 in r4
508 mov cr16=r3 // cr.ipsr
509 mov cr17=r5 // cr.isr is read only
510 // mov cr18=r7;; // cr.ida
515 mov cr19=r3 // cr.iip
516 mov cr20=r5 // cr.idtr
517 mov cr21=r7;; // cr.iitr
522 mov cr22=r3 // cr.iipa
523 mov cr23=r5 // cr.ifs
524 mov cr24=r7 // cr.iim
526 ld8 r3=[r2],160;; // 160 byte increment
527 mov cr25=r3 // cr.iha
530 ld8 r3=[r2],168;; // another 168 byte inc.
532 ld8 r3=[r2],40;; // 40 byte increment
533 mov cr66=r3 // cr.lid
536 // mov cr71=r3 // cr.ivr is read only
537 ld8 r3=[r2],24;; // 24 byte increment
538 mov cr72=r3 // cr.tpr
540 ld8 r3=[r2],168;; // 168 byte inc.
541 // mov cr75=r3 // cr.eoi
543 ld8 r3=[r2],16;; // 16 byte inc.
544 // mov cr96=r3 // cr.irr0 is read only
546 ld8 r3=[r2],16;; // 16 byte inc.
547 // mov cr98=r3 // cr.irr1 is read only
549 ld8 r3=[r2],16;; // 16 byte inc
550 // mov cr100=r3 // cr.irr2 is read only
552 ld8 r3=[r2],16;; // 16b inc.
553 // mov cr102=r3 // cr.irr3 is read only
555 ld8 r3=[r2],16;; // 16 byte inc.
556 // mov cr114=r3 // cr.itv
559 // mov cr116=r3 // cr.pmv
561 // mov cr117=r3 // cr.lrr0
563 // mov cr118=r3 // cr.lrr1
565 // mov cr119=r3 // cr.cmcv
568 add r4=8,r2 // duplicate r2 in r4
569 add r6=2*8,r2;; // duplicate r2 in r4
576 mov ar2=r7;; // ar.kr2
583 mov ar5=r7;; // ar.kr5
590 // mov ar8=r6 // ar.kr8
596 // mov ar16=r3 // ar.rsc
597 // mov ar17=r5 // ar.bsp is read only
598 mov ar16=r0 // make sure that RSE is in enforced lazy mode
600 mov ar18=r7;; // ar.bspstore
603 mov ar19=r9 // ar.rnat
605 mov ar16=r3 // ar.rsc
607 mov ar32=r3 // ar.ccv
610 mov ar36=r3 // ar.unat
613 mov ar40=r3 // ar.fpsr
615 ld8 r3=[r2],160;; // 160
616 // mov ar44=r3 // ar.itc
619 mov ar64=r3 // ar.pfs
626 add r2=8*62,r2;; // padding
634 // mov rr[r4]=r3 // what are its access previledges?
636 br.cloop.sptk.few cStRRr
641 BRANCH(ia64_os_mca_done_restore, r2, p0, -0x20)
643 //EndStub//////////////////////////////////////////////////////////////////////
645 // ok, the issue here is that we need to save state information so
646 // it can be useable by the kernel debugger and show regs routines.
647 // In order to do this, our best bet is save the current state (plus
648 // the state information obtain from the MIN_STATE_AREA) into a pt_regs
649 // format. This way we can pass it on in a useable format.
653 // SAL to OS entry point for INIT on the monarch processor
654 // This has been defined for registration purposes with SAL
655 // as a part of ia64_mca_init.
657 // When we get here, the follow registers have been
658 // set by the SAL for our use
660 // 1. GR1 = OS INIT GP
661 // 2. GR8 = PAL_PROC physical address
662 // 3. GR9 = SAL_PROC physical address
663 // 4. GR10 = SAL GP (physical)
664 // 5. GR11 = Init Reason
665 // 0 = Received INIT for event other than crash dump switch
666 // 1 = Received wakeup at the end of an OS_MCA corrected machine check
667 // 2 = Received INIT dude to CrashDump switch assertion
669 // 6. GR12 = Return address to location within SAL_INIT procedure
674 .global ia64_monarch_init_handler
675 .proc ia64_monarch_init_handler
676 ia64_monarch_init_handler:
678 #if defined(CONFIG_SMP) && defined(SAL_MPINIT_WORKAROUND)
680 // work around SAL bug that sends all processors to monarch entry
683 movl r18=__cpu_physical_id
685 dep r18=0,r18,61,3 // convert to physical address
688 ld4 r18=[r18] // get the BSP ID
692 cmp4.ne p6,p0=r17,r18 // Am I the BSP ?
693 (p6) br.cond.spnt slave_init_spin_me
699 // ok, the first thing we do is stash the information
700 // the SAL passed to os
703 movl _tmp=ia64_sal_to_os_handoff_state
705 dep _tmp=0,_tmp, 61, 3 // get physical address
710 st8 [_tmp]=r10,0x08;;
711 st8 [_tmp]=r11,0x08;;
712 st8 [_tmp]=r12,0x08;;
714 // now we want to save information so we can dump registers
719 adds r3=8,r2 // set up second base pointer
723 // ok, enough should be saved at this point to be dangerous, and supply
724 // information for a dump
725 // We need to switch to Virtual mode before hitting the C functions.
729 movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN
730 mov r3=psr // get the current psr, minimum enabled at this point
734 movl r3=IVirtual_Switch
736 mov cr.iip=r3 // short return to set the appropriate bits
737 mov cr.ipsr=r2 // need to do an rfi to set appropriate bits
743 // We should now be running virtual
745 // Lets call the C handler to get the rest of the state info
747 alloc r14=ar.pfs,0,0,1,0 // now it's safe (must be first in insn group!)
749 adds out0=16,sp // out0 = pointer to pt_regs
752 br.call.sptk.few rp=ia64_init_handler
756 br.sptk return_from_init
761 // SAL to OS entry point for INIT on the slave processor
762 // This has been defined for registration purposes with SAL
763 // as a part of ia64_mca_init.
768 .global ia64_slave_init_handler
769 .proc ia64_slave_init_handler
770 ia64_slave_init_handler:
774 br.sptk slave_init_spin_me