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 // 02/01/04 J.Hall <jenna.s.hall@intel.com>
11 // Before entering virtual mode code:
12 // 1. Check for TLB CPU error
13 // 2. Restore current thread pointer to kr6
14 // 3. Move stack ptr 16 bytes to conform to C calling convention
16 #include <linux/config.h>
17 #include <linux/threads.h>
19 #include <asm/asmmacro.h>
20 #include <asm/pgtable.h>
21 #include <asm/processor.h>
22 #include <asm/mca_asm.h>
26 * When we get a machine check, the kernel stack pointer is no longer
27 * valid, so we need to set a new stack pointer.
29 #define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */
32 * Needed for return context to SAL
34 #define IA64_MCA_SAME_CONTEXT 0
35 #define IA64_MCA_COLD_BOOT -2
40 * SAL_TO_OS_MCA_HANDOFF_STATE (SAL 3.0 spec)
42 * 2. GR8 = PAL_PROC physical address
43 * 3. GR9 = SAL_PROC physical address
44 * 4. GR10 = SAL GP (physical)
45 * 5. GR11 = Rendez state
46 * 6. GR12 = Return address to location within SAL_CHECK
48 #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \
49 movl _tmp=ia64_sal_to_os_handoff_state;; \
50 DATA_VA_TO_PA(_tmp);; \
51 st8 [_tmp]=r1,0x08;; \
52 st8 [_tmp]=r8,0x08;; \
53 st8 [_tmp]=r9,0x08;; \
54 st8 [_tmp]=r10,0x08;; \
55 st8 [_tmp]=r11,0x08;; \
56 st8 [_tmp]=r12,0x08;; \
57 st8 [_tmp]=r17,0x08;; \
61 * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec)
62 * (p6) is executed if we never entered virtual mode (TLB error)
63 * (p7) is executed if we entered virtual mode as expected (normal case)
64 * 1. GR8 = OS_MCA return status
65 * 2. GR9 = SAL GP (physical)
66 * 3. GR10 = 0/1 returning same/new context
67 * 4. GR22 = New min state save area pointer
68 * returns ptr to SAL rtn save loc in _tmp
70 #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \
71 movl _tmp=ia64_os_to_sal_handoff_state;; \
72 DATA_VA_TO_PA(_tmp);; \
73 ld8 r8=[_tmp],0x08;; \
74 ld8 r9=[_tmp],0x08;; \
75 ld8 r10=[_tmp],0x08;; \
77 // now _tmp is pointing to SAL rtn save location
80 * COLD_BOOT_HANDOFF_STATE() sets ia64_mca_os_to_sal_state
81 * imots_os_status=IA64_MCA_COLD_BOOT
83 * imots_context=IA64_MCA_SAME_CONTEXT
84 * imots_new_min_state=Min state save area pointer
85 * imots_sal_check_ra=Return address to location within SAL_CHECK
88 #define COLD_BOOT_HANDOFF_STATE(sal_to_os_handoff,os_to_sal_handoff,tmp)\
89 movl tmp=IA64_MCA_COLD_BOOT; \
90 movl sal_to_os_handoff=__pa(ia64_sal_to_os_handoff_state); \
91 movl os_to_sal_handoff=__pa(ia64_os_to_sal_handoff_state);; \
92 st8 [os_to_sal_handoff]=tmp,8;; \
93 ld8 tmp=[sal_to_os_handoff],48;; \
94 st8 [os_to_sal_handoff]=tmp,8;; \
95 movl tmp=IA64_MCA_SAME_CONTEXT;; \
96 st8 [os_to_sal_handoff]=tmp,8;; \
97 ld8 tmp=[sal_to_os_handoff],-8;; \
98 st8 [os_to_sal_handoff]=tmp,8;; \
99 ld8 tmp=[sal_to_os_handoff];; \
100 st8 [os_to_sal_handoff]=tmp;;
102 .global ia64_os_mca_dispatch
103 .global ia64_os_mca_dispatch_end
104 .global ia64_sal_to_os_handoff_state
105 .global ia64_os_to_sal_handoff_state
106 .global ia64_mca_proc_state_dump
107 .global ia64_mca_stack
108 .global ia64_mca_stackframe
109 .global ia64_mca_bspstore
110 .global ia64_init_stack
115 ia64_os_mca_dispatch:
117 // Serialize all MCA processing
118 movl r2=ia64_mca_serialize
124 (p6) br ia64_os_mca_spin
126 // Save the SAL to OS MCA handoff state as defined
128 // NOTE : The order in which the state gets saved
129 // is dependent on the way the C-structure
130 // for ia64_mca_sal_to_os_state_t has been
131 // defined in include/asm/mca.h
132 SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
135 // LOG PROCESSOR STATE INFO FROM HERE ON..
137 br ia64_os_mca_proc_state_dump;;
139 ia64_os_mca_done_dump:
141 movl r16=__pa(ia64_sal_to_os_handoff_state)+56
143 ld8 r18=[r16] // Get processor state parameter on existing PALE_CHECK.
146 (p7) br.spnt done_tlb_purge_and_reload
148 // The following code purges TC and TR entries. Then reload all TC entries.
149 // Purge percpu data TC entries.
150 begin_tlb_purge_and_reload:
152 movl r17=__pa(ia64_mca_tlb_list) // Physical address of ia64_mca_tlb_list
156 1: cmp.eq p6,p7=r19,r20
158 ld8 r18=[r17],IA64_MCA_TLB_INFO_SIZE
164 adds r17=-IA64_MCA_TLB_INFO_SIZE,r17
166 mov r23=r17 // save current ia64_mca_percpu_info addr pointer.
169 ld8 r18=[r17],8 // r18=ptce_base
171 ld4 r19=[r17],4 // r19=ptce_count[0]
173 ld4 r20=[r17],4 // r20=ptce_count[1]
175 ld4 r21=[r17],4 // r21=ptce_stride[0]
178 ld4 r22=[r17],4 // r22=ptce_stride[1]
182 cmp.ltu p6,p7=r24,r19
183 (p7) br.cond.dpnt.few 4f
196 srlz.i // srlz.i implies srlz.d
199 // Now purge addresses formerly mapped by TR registers
200 // 1. Purge ITR&DTR for kernel.
201 movl r16=KERNEL_START
202 mov r18=KERNEL_TR_PAGE_SHIFT<<2
211 // 2. Purge DTR for PERCPU data.
213 mov r18=PAGE_SHIFT<<2
219 // 3. Purge ITR for PAL code.
223 mov r18=IA64_GRANULE_SHIFT<<2
229 // 4. Purge DTR for stack.
230 mov r16=IA64_KR(CURRENT_STACK)
232 shl r16=r16,IA64_GRANULE_SHIFT
236 mov r18=IA64_GRANULE_SHIFT<<2
242 // Finally reload the TR registers.
243 // 1. Reload DTR/ITR registers for kernel.
244 mov r18=KERNEL_TR_PAGE_SHIFT<<2
245 movl r17=KERNEL_START
249 mov r16=IA64_TR_KERNEL
250 movl r18=((1 << KERNEL_TR_PAGE_SHIFT) | PAGE_KERNEL)
259 // 2. Reload DTR register for PERCPU data.
261 movl r16=PERCPU_ADDR // vaddr
262 movl r18=PAGE_SHIFT<<2
268 mov r16=IA64_TR_PERCPU_DATA;
274 // 3. Reload ITR for PAL code.
277 ld8 r18=[r17],8 // pte
279 ld8 r16=[r17] // vaddr
280 mov r19=IA64_GRANULE_SHIFT<<2
284 mov r20=IA64_TR_PALCODE
290 // 4. Reload DTR for stack.
291 mov r16=IA64_KR(CURRENT_STACK)
293 shl r16=r16,IA64_GRANULE_SHIFT
300 mov r19=IA64_GRANULE_SHIFT<<2
304 mov r20=IA64_TR_CURRENT_STACK
310 br.sptk.many done_tlb_purge_and_reload
312 COLD_BOOT_HANDOFF_STATE(r20,r21,r22)
313 br.sptk.many ia64_os_mca_done_restore
315 done_tlb_purge_and_reload:
317 // Setup new stack frame for OS_MCA handling
318 movl r2=ia64_mca_bspstore;; // local bspstore area location in r2
320 movl r3=ia64_mca_stackframe;; // save stack frame to memory in r3
322 rse_switch_context(r6,r3,r2);; // RSC management in this new context
323 movl r12=ia64_mca_stack
324 mov r2=8*1024;; // stack size must be same as C array
325 add r12=r2,r12;; // stack base @ bottom of array
326 adds r12=-16,r12;; // allow 16 bytes of scratch
327 // (C calling convention)
330 // Enter virtual mode from physical mode
331 VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
332 ia64_os_mca_virtual_begin:
334 // Call virtual mode handler
335 movl r2=ia64_mca_ucmc_handler;;
337 br.call.sptk.many b0=b6;;
339 // Revert back to physical mode before going back to SAL
340 PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4)
341 ia64_os_mca_virtual_end:
343 // restore the original stack frame here
344 movl r2=ia64_mca_stackframe // restore stack frame from memory at r2
349 rse_return_context(r4,r3,r2) // switch from interrupt context for RSE
351 // let us restore all the registers from our PSI structure
354 begin_os_mca_restore:
355 br ia64_os_mca_proc_state_restore;;
357 ia64_os_mca_done_restore:
358 OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2);;
359 // branch back to SALE_CHECK
361 mov b0=r3;; // SAL_CHECK return address
364 movl r3=ia64_mca_serialize;;
370 ia64_os_mca_dispatch_end:
371 //EndMain//////////////////////////////////////////////////////////////////////
376 // ia64_os_mca_proc_state_dump()
380 // This stub dumps the processor state during MCHK to a data area
384 ia64_os_mca_proc_state_dump:
385 // Save bank 1 GRs 16-31 which will be used by c-language code when we switch
386 // to virtual addressing mode.
387 movl r2=ia64_mca_proc_state_dump;; // Os state dump area
388 DATA_VA_TO_PA(r2) // convert to to physical address
391 mov r5=ar.unat // ar.unat
393 // save banked GRs 16-31 along with NaT bits
395 st8.spill [r2]=r16,8;;
396 st8.spill [r2]=r17,8;;
397 st8.spill [r2]=r18,8;;
398 st8.spill [r2]=r19,8;;
399 st8.spill [r2]=r20,8;;
400 st8.spill [r2]=r21,8;;
401 st8.spill [r2]=r22,8;;
402 st8.spill [r2]=r23,8;;
403 st8.spill [r2]=r24,8;;
404 st8.spill [r2]=r25,8;;
405 st8.spill [r2]=r26,8;;
406 st8.spill [r2]=r27,8;;
407 st8.spill [r2]=r28,8;;
408 st8.spill [r2]=r29,8;;
409 st8.spill [r2]=r30,8;;
410 st8.spill [r2]=r31,8;;
413 st8 [r2]=r4,8 // save User NaT bits for r16-r31
414 mov ar.unat=r5 // restore original unat
418 add r4=8,r2 // duplicate r2 in r4
419 add r6=2*8,r2 // duplicate r2 in r4
442 add r4=8,r2 // duplicate r2 in r4
443 add r6=2*8,r2 // duplicate r2 in r4
451 st8 [r6]=r7,3*8;; // 48 byte rements
454 st8 [r2]=r3,8*8;; // 64 byte rements
456 // if PSR.ic=0, reading interruption registers causes an illegal operation fault
458 tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test
459 (p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc.
460 begin_skip_intr_regs:
461 (p6) br SkipIntrRegs;;
463 add r4=8,r2 // duplicate r2 in r4
464 add r6=2*8,r2 // duplicate r2 in r6
487 mov r3=cr25;; // cr.iha
488 st8 [r2]=r3,160;; // 160 byte rement
491 st8 [r2]=r0,152;; // another 152 byte .
493 add r4=8,r2 // duplicate r2 in r4
494 add r6=2*8,r2 // duplicate r2 in r6
497 // mov r5=cr.ivr // cr.ivr, don't read it
503 mov r3=r0 // cr.eoi => cr67
504 mov r5=r0 // cr.irr0 => cr68
505 mov r7=r0;; // cr.irr1 => cr69
510 mov r3=r0 // cr.irr2 => cr70
511 mov r5=r0 // cr.irr3 => cr71
522 mov r3=r0 // cr.lrr0 => cr80
523 mov r5=r0;; // cr.lrr1 => cr81
531 add r4=8,r2 // duplicate r2 in r4
532 add r6=2*8,r2 // duplicate r2 in r6
550 mov r7=r0;; // ar.kr8
553 st8 [r6]=r7,10*8;; // rement by 72 bytes
556 mov ar.rsc=r0 // put RSE in enforced lazy mode
565 st8 [r2]=r3,8*13 // increment by 13x8 bytes
577 st8 [r2]=r3,160 // 160
587 add r2=8*62,r2 //padding
598 br.cloop.sptk.few cStRR
601 br ia64_os_mca_done_dump;;
603 //EndStub//////////////////////////////////////////////////////////////////////
608 // ia64_os_mca_proc_state_restore()
612 // This is a stub to restore the saved processor state during MCHK
616 ia64_os_mca_proc_state_restore:
618 // Restore bank1 GR16-31
619 movl r2=ia64_mca_proc_state_dump // Convert virtual address
620 ;; // of OS state dump area
621 DATA_VA_TO_PA(r2) // to physical address
623 restore_GRs: // restore bank-1 GRs 16-31
625 add r3=16*8,r2;; // to get to NaT of GR 16-31
627 mov ar.unat=r3;; // first restore NaT
629 ld8.fill r16=[r2],8;;
630 ld8.fill r17=[r2],8;;
631 ld8.fill r18=[r2],8;;
632 ld8.fill r19=[r2],8;;
633 ld8.fill r20=[r2],8;;
634 ld8.fill r21=[r2],8;;
635 ld8.fill r22=[r2],8;;
636 ld8.fill r23=[r2],8;;
637 ld8.fill r24=[r2],8;;
638 ld8.fill r25=[r2],8;;
639 ld8.fill r26=[r2],8;;
640 ld8.fill r27=[r2],8;;
641 ld8.fill r28=[r2],8;;
642 ld8.fill r29=[r2],8;;
643 ld8.fill r30=[r2],8;;
644 ld8.fill r31=[r2],8;;
646 ld8 r3=[r2],8;; // increment to skip NaT
650 add r4=8,r2 // duplicate r2 in r4
651 add r6=2*8,r2;; // duplicate r2 in r4
673 add r4=8,r2 // duplicate r2 in r4
674 add r6=2*8,r2;; // duplicate r2 in r4
678 ld8 r7=[r6],3*8;; // 48 byte increments
683 ld8 r3=[r2],8*8;; // 64 byte increments
687 // if PSR.ic=1, reading interruption registers causes an illegal operation fault
689 tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test
690 (p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc.
692 begin_rskip_intr_regs:
693 (p6) br rSkipIntrRegs;;
695 add r4=8,r2 // duplicate r2 in r4
696 add r6=2*8,r2;; // duplicate r2 in r4
702 // mov cr.isr=r5 // cr.isr is read only
718 ld8 r3=[r2],160;; // 160 byte increment
722 ld8 r3=[r2],152;; // another 152 byte inc.
724 add r4=8,r2 // duplicate r2 in r4
725 add r6=2*8,r2;; // duplicate r2 in r6
731 // mov cr.ivr=r5 // cr.ivr is read only
738 // mov cr.irr0=r5 // cr.irr0 is read only
739 // mov cr.irr1=r7;; // cr.irr1 is read only
744 // mov cr.irr2=r3 // cr.irr2 is read only
745 // mov cr.irr3=r5 // cr.irr3 is read only
763 add r4=8,r2 // duplicate r2 in r4
764 add r6=2*8,r2;; // duplicate r2 in r4
791 // mov ar.bsp=r5 // ar.bsp is read only
792 mov ar.rsc=r0 // make sure that RSE is in enforced lazy mode
809 ld8 r3=[r2],160;; // 160
820 add r2=8*62,r2;; // padding
829 mov rr[r7]=r3 // what are its access previledges?
831 br.cloop.sptk.few cStRRr
836 br ia64_os_mca_done_restore;;
838 //EndStub//////////////////////////////////////////////////////////////////////
841 // ok, the issue here is that we need to save state information so
842 // it can be useable by the kernel debugger and show regs routines.
843 // In order to do this, our best bet is save the current state (plus
844 // the state information obtain from the MIN_STATE_AREA) into a pt_regs
845 // format. This way we can pass it on in a useable format.
849 // SAL to OS entry point for INIT on the monarch processor
850 // This has been defined for registration purposes with SAL
851 // as a part of ia64_mca_init.
853 // When we get here, the following registers have been
854 // set by the SAL for our use
856 // 1. GR1 = OS INIT GP
857 // 2. GR8 = PAL_PROC physical address
858 // 3. GR9 = SAL_PROC physical address
859 // 4. GR10 = SAL GP (physical)
860 // 5. GR11 = Init Reason
861 // 0 = Received INIT for event other than crash dump switch
862 // 1 = Received wakeup at the end of an OS_MCA corrected machine check
863 // 2 = Received INIT dude to CrashDump switch assertion
865 // 6. GR12 = Return address to location within SAL_INIT procedure
868 GLOBAL_ENTRY(ia64_monarch_init_handler)
870 // stash the information the SAL passed to os
871 SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
877 adds r3=8,r2 // set up second base pointer
881 // ok, enough should be saved at this point to be dangerous, and supply
882 // information for a dump
883 // We need to switch to Virtual mode before hitting the C functions.
885 movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN
886 mov r3=psr // get the current psr, minimum enabled at this point
890 movl r3=IVirtual_Switch
892 mov cr.iip=r3 // short return to set the appropriate bits
893 mov cr.ipsr=r2 // need to do an rfi to set appropriate bits
899 // We should now be running virtual
901 // Let's call the C handler to get the rest of the state info
903 alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!)
905 adds out0=16,sp // out0 = pointer to pt_regs
908 adds out1=16,sp // out0 = pointer to switch_stack
910 br.call.sptk.many rp=ia64_init_handler
914 br.sptk return_from_init
915 END(ia64_monarch_init_handler)
918 // SAL to OS entry point for INIT on the slave processor
919 // This has been defined for registration purposes with SAL
920 // as a part of ia64_mca_init.
923 GLOBAL_ENTRY(ia64_slave_init_handler)
925 END(ia64_slave_init_handler)