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 LOAD_PHYSICAL(p0, _tmp, ia64_sal_to_os_handoff_state);; \
50 st8 [_tmp]=r1,0x08;; \
51 st8 [_tmp]=r8,0x08;; \
52 st8 [_tmp]=r9,0x08;; \
53 st8 [_tmp]=r10,0x08;; \
54 st8 [_tmp]=r11,0x08;; \
55 st8 [_tmp]=r12,0x08;; \
56 st8 [_tmp]=r17,0x08;; \
60 * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec)
61 * (p6) is executed if we never entered virtual mode (TLB error)
62 * (p7) is executed if we entered virtual mode as expected (normal case)
63 * 1. GR8 = OS_MCA return status
64 * 2. GR9 = SAL GP (physical)
65 * 3. GR10 = 0/1 returning same/new context
66 * 4. GR22 = New min state save area pointer
67 * returns ptr to SAL rtn save loc in _tmp
69 #define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \
70 movl _tmp=ia64_os_to_sal_handoff_state;; \
71 DATA_VA_TO_PA(_tmp);; \
72 ld8 r8=[_tmp],0x08;; \
73 ld8 r9=[_tmp],0x08;; \
74 ld8 r10=[_tmp],0x08;; \
76 // now _tmp is pointing to SAL rtn save location
79 * COLD_BOOT_HANDOFF_STATE() sets ia64_mca_os_to_sal_state
80 * imots_os_status=IA64_MCA_COLD_BOOT
82 * imots_context=IA64_MCA_SAME_CONTEXT
83 * imots_new_min_state=Min state save area pointer
84 * imots_sal_check_ra=Return address to location within SAL_CHECK
87 #define COLD_BOOT_HANDOFF_STATE(sal_to_os_handoff,os_to_sal_handoff,tmp)\
88 movl tmp=IA64_MCA_COLD_BOOT; \
89 movl sal_to_os_handoff=__pa(ia64_sal_to_os_handoff_state); \
90 movl os_to_sal_handoff=__pa(ia64_os_to_sal_handoff_state);; \
91 st8 [os_to_sal_handoff]=tmp,8;; \
92 ld8 tmp=[sal_to_os_handoff],48;; \
93 st8 [os_to_sal_handoff]=tmp,8;; \
94 movl tmp=IA64_MCA_SAME_CONTEXT;; \
95 st8 [os_to_sal_handoff]=tmp,8;; \
96 ld8 tmp=[sal_to_os_handoff],-8;; \
97 st8 [os_to_sal_handoff]=tmp,8;; \
98 ld8 tmp=[sal_to_os_handoff];; \
99 st8 [os_to_sal_handoff]=tmp;;
101 .global ia64_os_mca_dispatch
102 .global ia64_os_mca_dispatch_end
103 .global ia64_sal_to_os_handoff_state
104 .global ia64_os_to_sal_handoff_state
105 .global ia64_mca_proc_state_dump
106 .global ia64_mca_stack
107 .global ia64_mca_stackframe
108 .global ia64_mca_bspstore
109 .global ia64_init_stack
114 ia64_os_mca_dispatch:
116 // Serialize all MCA processing
118 LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);;
122 (p6) br ia64_os_mca_spin
124 // Save the SAL to OS MCA handoff state as defined
126 // NOTE : The order in which the state gets saved
127 // is dependent on the way the C-structure
128 // for ia64_mca_sal_to_os_state_t has been
129 // defined in include/asm/mca.h
130 SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
133 // LOG PROCESSOR STATE INFO FROM HERE ON..
135 br ia64_os_mca_proc_state_dump;;
137 ia64_os_mca_done_dump:
139 LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56)
141 ld8 r18=[r16] // Get processor state parameter on existing PALE_CHECK.
144 (p7) br.spnt done_tlb_purge_and_reload
146 // The following code purges TC and TR entries. Then reload all TC entries.
147 // Purge percpu data TC entries.
148 begin_tlb_purge_and_reload:
150 LOAD_PHYSICAL(p0,r17,ia64_mca_tlb_list) // Physical address of ia64_mca_tlb_list
154 1: cmp.eq p6,p7=r19,r20
156 ld8 r18=[r17],IA64_MCA_TLB_INFO_SIZE
162 adds r17=-IA64_MCA_TLB_INFO_SIZE,r17
164 mov r23=r17 // save current ia64_mca_percpu_info addr pointer.
167 ld8 r18=[r17],8 // r18=ptce_base
169 ld4 r19=[r17],4 // r19=ptce_count[0]
171 ld4 r20=[r17],4 // r20=ptce_count[1]
173 ld4 r21=[r17],4 // r21=ptce_stride[0]
176 ld4 r22=[r17],4 // r22=ptce_stride[1]
180 cmp.ltu p6,p7=r24,r19
181 (p7) br.cond.dpnt.few 4f
194 srlz.i // srlz.i implies srlz.d
197 // Now purge addresses formerly mapped by TR registers
198 // 1. Purge ITR&DTR for kernel.
199 movl r16=KERNEL_START
200 mov r18=KERNEL_TR_PAGE_SHIFT<<2
209 // 2. Purge DTR for PERCPU data.
211 mov r18=PERCPU_PAGE_SHIFT<<2
217 // 3. Purge ITR for PAL code.
221 mov r18=IA64_GRANULE_SHIFT<<2
227 // 4. Purge DTR for stack.
228 mov r16=IA64_KR(CURRENT_STACK)
230 shl r16=r16,IA64_GRANULE_SHIFT
234 mov r18=IA64_GRANULE_SHIFT<<2
240 // Finally reload the TR registers.
241 // 1. Reload DTR/ITR registers for kernel.
242 mov r18=KERNEL_TR_PAGE_SHIFT<<2
243 movl r17=KERNEL_START
247 mov r16=IA64_TR_KERNEL
251 dep r17=0,r19,0, KERNEL_TR_PAGE_SHIFT
262 // 2. Reload DTR register for PERCPU data.
264 movl r16=PERCPU_ADDR // vaddr
265 movl r18=PERCPU_PAGE_SHIFT<<2
271 mov r16=IA64_TR_PERCPU_DATA;
277 // 3. Reload ITR for PAL code.
280 ld8 r18=[r17],8 // pte
282 ld8 r16=[r17] // vaddr
283 mov r19=IA64_GRANULE_SHIFT<<2
287 mov r20=IA64_TR_PALCODE
293 // 4. Reload DTR for stack.
294 mov r16=IA64_KR(CURRENT_STACK)
296 shl r16=r16,IA64_GRANULE_SHIFT
303 mov r19=IA64_GRANULE_SHIFT<<2
307 mov r20=IA64_TR_CURRENT_STACK
313 br.sptk.many done_tlb_purge_and_reload
315 COLD_BOOT_HANDOFF_STATE(r20,r21,r22)
316 br.sptk.many ia64_os_mca_done_restore
318 done_tlb_purge_and_reload:
320 // Setup new stack frame for OS_MCA handling
321 movl r2=ia64_mca_bspstore;; // local bspstore area location in r2
323 movl r3=ia64_mca_stackframe;; // save stack frame to memory in r3
325 rse_switch_context(r6,r3,r2);; // RSC management in this new context
326 movl r12=ia64_mca_stack
327 mov r2=8*1024;; // stack size must be same as C array
328 add r12=r2,r12;; // stack base @ bottom of array
329 adds r12=-16,r12;; // allow 16 bytes of scratch
330 // (C calling convention)
333 // Enter virtual mode from physical mode
334 VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
335 ia64_os_mca_virtual_begin:
337 // Call virtual mode handler
338 movl r2=ia64_mca_ucmc_handler;;
340 br.call.sptk.many b0=b6;;
342 // Revert back to physical mode before going back to SAL
343 PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4)
344 ia64_os_mca_virtual_end:
346 // restore the original stack frame here
347 movl r2=ia64_mca_stackframe // restore stack frame from memory at r2
352 rse_return_context(r4,r3,r2) // switch from interrupt context for RSE
354 // let us restore all the registers from our PSI structure
357 begin_os_mca_restore:
358 br ia64_os_mca_proc_state_restore;;
360 ia64_os_mca_done_restore:
361 OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2);;
362 // branch back to SALE_CHECK
364 mov b0=r3;; // SAL_CHECK return address
367 movl r3=ia64_mca_serialize;;
373 ia64_os_mca_dispatch_end:
374 //EndMain//////////////////////////////////////////////////////////////////////
379 // ia64_os_mca_proc_state_dump()
383 // This stub dumps the processor state during MCHK to a data area
387 ia64_os_mca_proc_state_dump:
388 // Save bank 1 GRs 16-31 which will be used by c-language code when we switch
389 // to virtual addressing mode.
390 LOAD_PHYSICAL(p0,r2,ia64_mca_proc_state_dump)// convert OS state dump area to physical address
393 mov r5=ar.unat // ar.unat
395 // save banked GRs 16-31 along with NaT bits
397 st8.spill [r2]=r16,8;;
398 st8.spill [r2]=r17,8;;
399 st8.spill [r2]=r18,8;;
400 st8.spill [r2]=r19,8;;
401 st8.spill [r2]=r20,8;;
402 st8.spill [r2]=r21,8;;
403 st8.spill [r2]=r22,8;;
404 st8.spill [r2]=r23,8;;
405 st8.spill [r2]=r24,8;;
406 st8.spill [r2]=r25,8;;
407 st8.spill [r2]=r26,8;;
408 st8.spill [r2]=r27,8;;
409 st8.spill [r2]=r28,8;;
410 st8.spill [r2]=r29,8;;
411 st8.spill [r2]=r30,8;;
412 st8.spill [r2]=r31,8;;
415 st8 [r2]=r4,8 // save User NaT bits for r16-r31
416 mov ar.unat=r5 // restore original unat
420 add r4=8,r2 // duplicate r2 in r4
421 add r6=2*8,r2 // duplicate r2 in r4
444 add r4=8,r2 // duplicate r2 in r4
445 add r6=2*8,r2 // duplicate r2 in r4
453 st8 [r6]=r7,3*8;; // 48 byte rements
456 st8 [r2]=r3,8*8;; // 64 byte rements
458 // if PSR.ic=0, reading interruption registers causes an illegal operation fault
460 tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test
461 (p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc.
462 begin_skip_intr_regs:
463 (p6) br SkipIntrRegs;;
465 add r4=8,r2 // duplicate r2 in r4
466 add r6=2*8,r2 // duplicate r2 in r6
489 mov r3=cr25;; // cr.iha
490 st8 [r2]=r3,160;; // 160 byte rement
493 st8 [r2]=r0,152;; // another 152 byte .
495 add r4=8,r2 // duplicate r2 in r4
496 add r6=2*8,r2 // duplicate r2 in r6
499 // mov r5=cr.ivr // cr.ivr, don't read it
505 mov r3=r0 // cr.eoi => cr67
506 mov r5=r0 // cr.irr0 => cr68
507 mov r7=r0;; // cr.irr1 => cr69
512 mov r3=r0 // cr.irr2 => cr70
513 mov r5=r0 // cr.irr3 => cr71
524 mov r3=r0 // cr.lrr0 => cr80
525 mov r5=r0;; // cr.lrr1 => cr81
533 add r4=8,r2 // duplicate r2 in r4
534 add r6=2*8,r2 // duplicate r2 in r6
552 mov r7=r0;; // ar.kr8
555 st8 [r6]=r7,10*8;; // rement by 72 bytes
558 mov ar.rsc=r0 // put RSE in enforced lazy mode
567 st8 [r2]=r3,8*13 // increment by 13x8 bytes
579 st8 [r2]=r3,160 // 160
589 add r2=8*62,r2 //padding
600 br.cloop.sptk.few cStRR
603 br ia64_os_mca_done_dump;;
605 //EndStub//////////////////////////////////////////////////////////////////////
610 // ia64_os_mca_proc_state_restore()
614 // This is a stub to restore the saved processor state during MCHK
618 ia64_os_mca_proc_state_restore:
620 // Restore bank1 GR16-31
621 movl r2=ia64_mca_proc_state_dump // Convert virtual address
622 ;; // of OS state dump area
623 DATA_VA_TO_PA(r2) // to physical address
625 restore_GRs: // restore bank-1 GRs 16-31
627 add r3=16*8,r2;; // to get to NaT of GR 16-31
629 mov ar.unat=r3;; // first restore NaT
631 ld8.fill r16=[r2],8;;
632 ld8.fill r17=[r2],8;;
633 ld8.fill r18=[r2],8;;
634 ld8.fill r19=[r2],8;;
635 ld8.fill r20=[r2],8;;
636 ld8.fill r21=[r2],8;;
637 ld8.fill r22=[r2],8;;
638 ld8.fill r23=[r2],8;;
639 ld8.fill r24=[r2],8;;
640 ld8.fill r25=[r2],8;;
641 ld8.fill r26=[r2],8;;
642 ld8.fill r27=[r2],8;;
643 ld8.fill r28=[r2],8;;
644 ld8.fill r29=[r2],8;;
645 ld8.fill r30=[r2],8;;
646 ld8.fill r31=[r2],8;;
648 ld8 r3=[r2],8;; // increment to skip NaT
652 add r4=8,r2 // duplicate r2 in r4
653 add r6=2*8,r2;; // duplicate r2 in r4
675 add r4=8,r2 // duplicate r2 in r4
676 add r6=2*8,r2;; // duplicate r2 in r4
680 ld8 r7=[r6],3*8;; // 48 byte increments
685 ld8 r3=[r2],8*8;; // 64 byte increments
689 // if PSR.ic=1, reading interruption registers causes an illegal operation fault
691 tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test
692 (p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc.
694 begin_rskip_intr_regs:
695 (p6) br rSkipIntrRegs;;
697 add r4=8,r2 // duplicate r2 in r4
698 add r6=2*8,r2;; // duplicate r2 in r4
704 // mov cr.isr=r5 // cr.isr is read only
720 ld8 r3=[r2],160;; // 160 byte increment
724 ld8 r3=[r2],152;; // another 152 byte inc.
726 add r4=8,r2 // duplicate r2 in r4
727 add r6=2*8,r2;; // duplicate r2 in r6
733 // mov cr.ivr=r5 // cr.ivr is read only
740 // mov cr.irr0=r5 // cr.irr0 is read only
741 // mov cr.irr1=r7;; // cr.irr1 is read only
746 // mov cr.irr2=r3 // cr.irr2 is read only
747 // mov cr.irr3=r5 // cr.irr3 is read only
765 add r4=8,r2 // duplicate r2 in r4
766 add r6=2*8,r2;; // duplicate r2 in r4
793 // mov ar.bsp=r5 // ar.bsp is read only
794 mov ar.rsc=r0 // make sure that RSE is in enforced lazy mode
811 ld8 r3=[r2],160;; // 160
822 add r2=8*62,r2;; // padding
831 mov rr[r7]=r3 // what are its access previledges?
833 br.cloop.sptk.few cStRRr
838 br ia64_os_mca_done_restore;;
840 //EndStub//////////////////////////////////////////////////////////////////////
843 // ok, the issue here is that we need to save state information so
844 // it can be useable by the kernel debugger and show regs routines.
845 // In order to do this, our best bet is save the current state (plus
846 // the state information obtain from the MIN_STATE_AREA) into a pt_regs
847 // format. This way we can pass it on in a useable format.
851 // SAL to OS entry point for INIT on the monarch processor
852 // This has been defined for registration purposes with SAL
853 // as a part of ia64_mca_init.
855 // When we get here, the following registers have been
856 // set by the SAL for our use
858 // 1. GR1 = OS INIT GP
859 // 2. GR8 = PAL_PROC physical address
860 // 3. GR9 = SAL_PROC physical address
861 // 4. GR10 = SAL GP (physical)
862 // 5. GR11 = Init Reason
863 // 0 = Received INIT for event other than crash dump switch
864 // 1 = Received wakeup at the end of an OS_MCA corrected machine check
865 // 2 = Received INIT dude to CrashDump switch assertion
867 // 6. GR12 = Return address to location within SAL_INIT procedure
870 GLOBAL_ENTRY(ia64_monarch_init_handler)
872 // stash the information the SAL passed to os
873 SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
879 adds r3=8,r2 // set up second base pointer
883 // ok, enough should be saved at this point to be dangerous, and supply
884 // information for a dump
885 // We need to switch to Virtual mode before hitting the C functions.
887 movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN
888 mov r3=psr // get the current psr, minimum enabled at this point
892 movl r3=IVirtual_Switch
894 mov cr.iip=r3 // short return to set the appropriate bits
895 mov cr.ipsr=r2 // need to do an rfi to set appropriate bits
901 // We should now be running virtual
903 // Let's call the C handler to get the rest of the state info
905 alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!)
907 adds out0=16,sp // out0 = pointer to pt_regs
910 adds out1=16,sp // out0 = pointer to switch_stack
912 br.call.sptk.many rp=ia64_init_handler
916 br.sptk return_from_init
917 END(ia64_monarch_init_handler)
920 // SAL to OS entry point for INIT on the slave processor
921 // This has been defined for registration purposes with SAL
922 // as a part of ia64_mca_init.
925 GLOBAL_ENTRY(ia64_slave_init_handler)
927 END(ia64_slave_init_handler)