linux/arch/ia64/kernel/mca_asm.S
Ashok Raj b8d8b883e6 [IA64] cpu hotplug: return offlined cpus to SAL
This patch is required to support cpu removal for IPF systems. Existing code
just fakes the real offline by keeping it run the idle thread, and polling
for the bit to re-appear in the cpu_state to get out of the idle loop.

For the cpu-offline to work correctly, we need to pass control of this CPU 
back to SAL so it can continue in the boot-rendez mode. This gives the
SAL control to not pick this cpu as the monarch processor for global MCA
events, and addition does not wait for this cpu to checkin with SAL
for global MCA events as well. The handoff is implemented as documented in 
SAL specification section 3.2.5.1 "OS_BOOT_RENDEZ to SAL return State"

Signed-off-by: Ashok Raj <ashok.raj@intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
2005-04-22 14:44:40 -07:00

947 lines
21 KiB
ArmAsm

//
// assembly portion of the IA64 MCA handling
//
// Mods by cfleck to integrate into kernel build
// 00/03/15 davidm Added various stop bits to get a clean compile
//
// 00/03/29 cfleck Added code to save INIT handoff state in pt_regs format, switch to temp
// kstack, switch modes, jump to C INIT handler
//
// 02/01/04 J.Hall <jenna.s.hall@intel.com>
// Before entering virtual mode code:
// 1. Check for TLB CPU error
// 2. Restore current thread pointer to kr6
// 3. Move stack ptr 16 bytes to conform to C calling convention
//
// 04/11/12 Russ Anderson <rja@sgi.com>
// Added per cpu MCA/INIT stack save areas.
//
#include <linux/config.h>
#include <linux/threads.h>
#include <asm/asmmacro.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/mca_asm.h>
#include <asm/mca.h>
/*
* When we get a machine check, the kernel stack pointer is no longer
* valid, so we need to set a new stack pointer.
*/
#define MINSTATE_PHYS /* Make sure stack access is physical for MINSTATE */
/*
* Needed for return context to SAL
*/
#define IA64_MCA_SAME_CONTEXT 0
#define IA64_MCA_COLD_BOOT -2
#include "minstate.h"
/*
* SAL_TO_OS_MCA_HANDOFF_STATE (SAL 3.0 spec)
* 1. GR1 = OS GP
* 2. GR8 = PAL_PROC physical address
* 3. GR9 = SAL_PROC physical address
* 4. GR10 = SAL GP (physical)
* 5. GR11 = Rendez state
* 6. GR12 = Return address to location within SAL_CHECK
*/
#define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \
LOAD_PHYSICAL(p0, _tmp, ia64_sal_to_os_handoff_state);; \
st8 [_tmp]=r1,0x08;; \
st8 [_tmp]=r8,0x08;; \
st8 [_tmp]=r9,0x08;; \
st8 [_tmp]=r10,0x08;; \
st8 [_tmp]=r11,0x08;; \
st8 [_tmp]=r12,0x08;; \
st8 [_tmp]=r17,0x08;; \
st8 [_tmp]=r18,0x08
/*
* OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec)
* (p6) is executed if we never entered virtual mode (TLB error)
* (p7) is executed if we entered virtual mode as expected (normal case)
* 1. GR8 = OS_MCA return status
* 2. GR9 = SAL GP (physical)
* 3. GR10 = 0/1 returning same/new context
* 4. GR22 = New min state save area pointer
* returns ptr to SAL rtn save loc in _tmp
*/
#define OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(_tmp) \
movl _tmp=ia64_os_to_sal_handoff_state;; \
DATA_VA_TO_PA(_tmp);; \
ld8 r8=[_tmp],0x08;; \
ld8 r9=[_tmp],0x08;; \
ld8 r10=[_tmp],0x08;; \
ld8 r22=[_tmp],0x08;;
// now _tmp is pointing to SAL rtn save location
/*
* COLD_BOOT_HANDOFF_STATE() sets ia64_mca_os_to_sal_state
* imots_os_status=IA64_MCA_COLD_BOOT
* imots_sal_gp=SAL GP
* imots_context=IA64_MCA_SAME_CONTEXT
* imots_new_min_state=Min state save area pointer
* imots_sal_check_ra=Return address to location within SAL_CHECK
*
*/
#define COLD_BOOT_HANDOFF_STATE(sal_to_os_handoff,os_to_sal_handoff,tmp)\
movl tmp=IA64_MCA_COLD_BOOT; \
movl sal_to_os_handoff=__pa(ia64_sal_to_os_handoff_state); \
movl os_to_sal_handoff=__pa(ia64_os_to_sal_handoff_state);; \
st8 [os_to_sal_handoff]=tmp,8;; \
ld8 tmp=[sal_to_os_handoff],48;; \
st8 [os_to_sal_handoff]=tmp,8;; \
movl tmp=IA64_MCA_SAME_CONTEXT;; \
st8 [os_to_sal_handoff]=tmp,8;; \
ld8 tmp=[sal_to_os_handoff],-8;; \
st8 [os_to_sal_handoff]=tmp,8;; \
ld8 tmp=[sal_to_os_handoff];; \
st8 [os_to_sal_handoff]=tmp;;
#define GET_IA64_MCA_DATA(reg) \
GET_THIS_PADDR(reg, ia64_mca_data) \
;; \
ld8 reg=[reg]
.global ia64_os_mca_dispatch
.global ia64_os_mca_dispatch_end
.global ia64_sal_to_os_handoff_state
.global ia64_os_to_sal_handoff_state
.global ia64_do_tlb_purge
.text
.align 16
/*
* Just the TLB purge part is moved to a separate function
* so we can re-use the code for cpu hotplug code as well
* Caller should now setup b1, so we can branch once the
* tlb flush is complete.
*/
ia64_do_tlb_purge:
#define O(member) IA64_CPUINFO_##member##_OFFSET
GET_THIS_PADDR(r2, cpu_info) // load phys addr of cpu_info into r2
;;
addl r17=O(PTCE_STRIDE),r2
addl r2=O(PTCE_BASE),r2
;;
ld8 r18=[r2],(O(PTCE_COUNT)-O(PTCE_BASE));; // r18=ptce_base
ld4 r19=[r2],4 // r19=ptce_count[0]
ld4 r21=[r17],4 // r21=ptce_stride[0]
;;
ld4 r20=[r2] // r20=ptce_count[1]
ld4 r22=[r17] // r22=ptce_stride[1]
mov r24=0
;;
adds r20=-1,r20
;;
#undef O
2:
cmp.ltu p6,p7=r24,r19
(p7) br.cond.dpnt.few 4f
mov ar.lc=r20
3:
ptc.e r18
;;
add r18=r22,r18
br.cloop.sptk.few 3b
;;
add r18=r21,r18
add r24=1,r24
;;
br.sptk.few 2b
4:
srlz.i // srlz.i implies srlz.d
;;
// Now purge addresses formerly mapped by TR registers
// 1. Purge ITR&DTR for kernel.
movl r16=KERNEL_START
mov r18=KERNEL_TR_PAGE_SHIFT<<2
;;
ptr.i r16, r18
ptr.d r16, r18
;;
srlz.i
;;
srlz.d
;;
// 2. Purge DTR for PERCPU data.
movl r16=PERCPU_ADDR
mov r18=PERCPU_PAGE_SHIFT<<2
;;
ptr.d r16,r18
;;
srlz.d
;;
// 3. Purge ITR for PAL code.
GET_THIS_PADDR(r2, ia64_mca_pal_base)
;;
ld8 r16=[r2]
mov r18=IA64_GRANULE_SHIFT<<2
;;
ptr.i r16,r18
;;
srlz.i
;;
// 4. Purge DTR for stack.
mov r16=IA64_KR(CURRENT_STACK)
;;
shl r16=r16,IA64_GRANULE_SHIFT
movl r19=PAGE_OFFSET
;;
add r16=r19,r16
mov r18=IA64_GRANULE_SHIFT<<2
;;
ptr.d r16,r18
;;
srlz.i
;;
// Now branch away to caller.
br.sptk.many b1
;;
ia64_os_mca_dispatch:
// Serialize all MCA processing
mov r3=1;;
LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);;
ia64_os_mca_spin:
xchg8 r4=[r2],r3;;
cmp.ne p6,p0=r4,r0
(p6) br ia64_os_mca_spin
// Save the SAL to OS MCA handoff state as defined
// by SAL SPEC 3.0
// NOTE : The order in which the state gets saved
// is dependent on the way the C-structure
// for ia64_mca_sal_to_os_state_t has been
// defined in include/asm/mca.h
SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
;;
// LOG PROCESSOR STATE INFO FROM HERE ON..
begin_os_mca_dump:
br ia64_os_mca_proc_state_dump;;
ia64_os_mca_done_dump:
LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56)
;;
ld8 r18=[r16] // Get processor state parameter on existing PALE_CHECK.
;;
tbit.nz p6,p7=r18,60
(p7) br.spnt done_tlb_purge_and_reload
// The following code purges TC and TR entries. Then reload all TC entries.
// Purge percpu data TC entries.
begin_tlb_purge_and_reload:
movl r18=ia64_reload_tr;;
LOAD_PHYSICAL(p0,r18,ia64_reload_tr);;
mov b1=r18;;
br.sptk.many ia64_do_tlb_purge;;
ia64_reload_tr:
// Finally reload the TR registers.
// 1. Reload DTR/ITR registers for kernel.
mov r18=KERNEL_TR_PAGE_SHIFT<<2
movl r17=KERNEL_START
;;
mov cr.itir=r18
mov cr.ifa=r17
mov r16=IA64_TR_KERNEL
mov r19=ip
movl r18=PAGE_KERNEL
;;
dep r17=0,r19,0, KERNEL_TR_PAGE_SHIFT
;;
or r18=r17,r18
;;
itr.i itr[r16]=r18
;;
itr.d dtr[r16]=r18
;;
srlz.i
srlz.d
;;
// 2. Reload DTR register for PERCPU data.
GET_THIS_PADDR(r2, ia64_mca_per_cpu_pte)
;;
movl r16=PERCPU_ADDR // vaddr
movl r18=PERCPU_PAGE_SHIFT<<2
;;
mov cr.itir=r18
mov cr.ifa=r16
;;
ld8 r18=[r2] // load per-CPU PTE
mov r16=IA64_TR_PERCPU_DATA;
;;
itr.d dtr[r16]=r18
;;
srlz.d
;;
// 3. Reload ITR for PAL code.
GET_THIS_PADDR(r2, ia64_mca_pal_pte)
;;
ld8 r18=[r2] // load PAL PTE
;;
GET_THIS_PADDR(r2, ia64_mca_pal_base)
;;
ld8 r16=[r2] // load PAL vaddr
mov r19=IA64_GRANULE_SHIFT<<2
;;
mov cr.itir=r19
mov cr.ifa=r16
mov r20=IA64_TR_PALCODE
;;
itr.i itr[r20]=r18
;;
srlz.i
;;
// 4. Reload DTR for stack.
mov r16=IA64_KR(CURRENT_STACK)
;;
shl r16=r16,IA64_GRANULE_SHIFT
movl r19=PAGE_OFFSET
;;
add r18=r19,r16
movl r20=PAGE_KERNEL
;;
add r16=r20,r16
mov r19=IA64_GRANULE_SHIFT<<2
;;
mov cr.itir=r19
mov cr.ifa=r18
mov r20=IA64_TR_CURRENT_STACK
;;
itr.d dtr[r20]=r16
;;
srlz.d
;;
br.sptk.many done_tlb_purge_and_reload
err:
COLD_BOOT_HANDOFF_STATE(r20,r21,r22)
br.sptk.many ia64_os_mca_done_restore
done_tlb_purge_and_reload:
// Setup new stack frame for OS_MCA handling
GET_IA64_MCA_DATA(r2)
;;
add r3 = IA64_MCA_CPU_STACKFRAME_OFFSET, r2
add r2 = IA64_MCA_CPU_RBSTORE_OFFSET, r2
;;
rse_switch_context(r6,r3,r2);; // RSC management in this new context
GET_IA64_MCA_DATA(r2)
;;
add r2 = IA64_MCA_CPU_STACK_OFFSET+IA64_MCA_STACK_SIZE-16, r2
;;
mov r12=r2 // establish new stack-pointer
// Enter virtual mode from physical mode
VIRTUAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_begin, r4)
ia64_os_mca_virtual_begin:
// Call virtual mode handler
movl r2=ia64_mca_ucmc_handler;;
mov b6=r2;;
br.call.sptk.many b0=b6;;
.ret0:
// Revert back to physical mode before going back to SAL
PHYSICAL_MODE_ENTER(r2, r3, ia64_os_mca_virtual_end, r4)
ia64_os_mca_virtual_end:
// restore the original stack frame here
GET_IA64_MCA_DATA(r2)
;;
add r2 = IA64_MCA_CPU_STACKFRAME_OFFSET, r2
;;
movl r4=IA64_PSR_MC
;;
rse_return_context(r4,r3,r2) // switch from interrupt context for RSE
// let us restore all the registers from our PSI structure
mov r8=gp
;;
begin_os_mca_restore:
br ia64_os_mca_proc_state_restore;;
ia64_os_mca_done_restore:
OS_MCA_TO_SAL_HANDOFF_STATE_RESTORE(r2);;
// branch back to SALE_CHECK
ld8 r3=[r2];;
mov b0=r3;; // SAL_CHECK return address
// release lock
movl r3=ia64_mca_serialize;;
DATA_VA_TO_PA(r3);;
st8.rel [r3]=r0
br b0
;;
ia64_os_mca_dispatch_end:
//EndMain//////////////////////////////////////////////////////////////////////
//++
// Name:
// ia64_os_mca_proc_state_dump()
//
// Stub Description:
//
// This stub dumps the processor state during MCHK to a data area
//
//--
ia64_os_mca_proc_state_dump:
// Save bank 1 GRs 16-31 which will be used by c-language code when we switch
// to virtual addressing mode.
GET_IA64_MCA_DATA(r2)
;;
add r2 = IA64_MCA_CPU_PROC_STATE_DUMP_OFFSET, r2
;;
// save ar.NaT
mov r5=ar.unat // ar.unat
// save banked GRs 16-31 along with NaT bits
bsw.1;;
st8.spill [r2]=r16,8;;
st8.spill [r2]=r17,8;;
st8.spill [r2]=r18,8;;
st8.spill [r2]=r19,8;;
st8.spill [r2]=r20,8;;
st8.spill [r2]=r21,8;;
st8.spill [r2]=r22,8;;
st8.spill [r2]=r23,8;;
st8.spill [r2]=r24,8;;
st8.spill [r2]=r25,8;;
st8.spill [r2]=r26,8;;
st8.spill [r2]=r27,8;;
st8.spill [r2]=r28,8;;
st8.spill [r2]=r29,8;;
st8.spill [r2]=r30,8;;
st8.spill [r2]=r31,8;;
mov r4=ar.unat;;
st8 [r2]=r4,8 // save User NaT bits for r16-r31
mov ar.unat=r5 // restore original unat
bsw.0;;
//save BRs
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2 // duplicate r2 in r4
mov r3=b0
mov r5=b1
mov r7=b2;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=b3
mov r5=b4
mov r7=b5;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=b6
mov r5=b7;;
st8 [r2]=r3,2*8
st8 [r4]=r5,2*8;;
cSaveCRs:
// save CRs
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2 // duplicate r2 in r4
mov r3=cr.dcr
mov r5=cr.itm
mov r7=cr.iva;;
st8 [r2]=r3,8*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;; // 48 byte rements
mov r3=cr.pta;;
st8 [r2]=r3,8*8;; // 64 byte rements
// if PSR.ic=0, reading interruption registers causes an illegal operation fault
mov r3=psr;;
tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test
(p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc.
begin_skip_intr_regs:
(p6) br SkipIntrRegs;;
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2 // duplicate r2 in r6
mov r3=cr.ipsr
mov r5=cr.isr
mov r7=r0;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=cr.iip
mov r5=cr.ifa
mov r7=cr.itir;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=cr.iipa
mov r5=cr.ifs
mov r7=cr.iim;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=cr25;; // cr.iha
st8 [r2]=r3,160;; // 160 byte rement
SkipIntrRegs:
st8 [r2]=r0,152;; // another 152 byte .
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2 // duplicate r2 in r6
mov r3=cr.lid
// mov r5=cr.ivr // cr.ivr, don't read it
mov r7=cr.tpr;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=r0 // cr.eoi => cr67
mov r5=r0 // cr.irr0 => cr68
mov r7=r0;; // cr.irr1 => cr69
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=r0 // cr.irr2 => cr70
mov r5=r0 // cr.irr3 => cr71
mov r7=cr.itv;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=cr.pmv
mov r5=cr.cmcv;;
st8 [r2]=r3,7*8
st8 [r4]=r5,7*8;;
mov r3=r0 // cr.lrr0 => cr80
mov r5=r0;; // cr.lrr1 => cr81
st8 [r2]=r3,23*8
st8 [r4]=r5,23*8;;
adds r2=25*8,r2;;
cSaveARs:
// save ARs
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2 // duplicate r2 in r6
mov r3=ar.k0
mov r5=ar.k1
mov r7=ar.k2;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=ar.k3
mov r5=ar.k4
mov r7=ar.k5;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=ar.k6
mov r5=ar.k7
mov r7=r0;; // ar.kr8
st8 [r2]=r3,10*8
st8 [r4]=r5,10*8
st8 [r6]=r7,10*8;; // rement by 72 bytes
mov r3=ar.rsc
mov ar.rsc=r0 // put RSE in enforced lazy mode
mov r5=ar.bsp
;;
mov r7=ar.bspstore;;
st8 [r2]=r3,3*8
st8 [r4]=r5,3*8
st8 [r6]=r7,3*8;;
mov r3=ar.rnat;;
st8 [r2]=r3,8*13 // increment by 13x8 bytes
mov r3=ar.ccv;;
st8 [r2]=r3,8*4
mov r3=ar.unat;;
st8 [r2]=r3,8*4
mov r3=ar.fpsr;;
st8 [r2]=r3,8*4
mov r3=ar.itc;;
st8 [r2]=r3,160 // 160
mov r3=ar.pfs;;
st8 [r2]=r3,8
mov r3=ar.lc;;
st8 [r2]=r3,8
mov r3=ar.ec;;
st8 [r2]=r3
add r2=8*62,r2 //padding
// save RRs
mov ar.lc=0x08-1
movl r4=0x00;;
cStRR:
dep.z r5=r4,61,3;;
mov r3=rr[r5];;
st8 [r2]=r3,8
add r4=1,r4
br.cloop.sptk.few cStRR
;;
end_os_mca_dump:
br ia64_os_mca_done_dump;;
//EndStub//////////////////////////////////////////////////////////////////////
//++
// Name:
// ia64_os_mca_proc_state_restore()
//
// Stub Description:
//
// This is a stub to restore the saved processor state during MCHK
//
//--
ia64_os_mca_proc_state_restore:
// Restore bank1 GR16-31
GET_IA64_MCA_DATA(r2)
;;
add r2 = IA64_MCA_CPU_PROC_STATE_DUMP_OFFSET, r2
restore_GRs: // restore bank-1 GRs 16-31
bsw.1;;
add r3=16*8,r2;; // to get to NaT of GR 16-31
ld8 r3=[r3];;
mov ar.unat=r3;; // first restore NaT
ld8.fill r16=[r2],8;;
ld8.fill r17=[r2],8;;
ld8.fill r18=[r2],8;;
ld8.fill r19=[r2],8;;
ld8.fill r20=[r2],8;;
ld8.fill r21=[r2],8;;
ld8.fill r22=[r2],8;;
ld8.fill r23=[r2],8;;
ld8.fill r24=[r2],8;;
ld8.fill r25=[r2],8;;
ld8.fill r26=[r2],8;;
ld8.fill r27=[r2],8;;
ld8.fill r28=[r2],8;;
ld8.fill r29=[r2],8;;
ld8.fill r30=[r2],8;;
ld8.fill r31=[r2],8;;
ld8 r3=[r2],8;; // increment to skip NaT
bsw.0;;
restore_BRs:
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2;; // duplicate r2 in r4
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
mov b0=r3
mov b1=r5
mov b2=r7;;
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
mov b3=r3
mov b4=r5
mov b5=r7;;
ld8 r3=[r2],2*8
ld8 r5=[r4],2*8;;
mov b6=r3
mov b7=r5;;
restore_CRs:
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2;; // duplicate r2 in r4
ld8 r3=[r2],8*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;; // 48 byte increments
mov cr.dcr=r3
mov cr.itm=r5
mov cr.iva=r7;;
ld8 r3=[r2],8*8;; // 64 byte increments
// mov cr.pta=r3
// if PSR.ic=1, reading interruption registers causes an illegal operation fault
mov r3=psr;;
tbit.nz.unc p6,p0=r3,PSR_IC;; // PSI Valid Log bit pos. test
(p6) st8 [r2]=r0,9*8+160 // increment by 232 byte inc.
begin_rskip_intr_regs:
(p6) br rSkipIntrRegs;;
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2;; // duplicate r2 in r4
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
mov cr.ipsr=r3
// mov cr.isr=r5 // cr.isr is read only
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
mov cr.iip=r3
mov cr.ifa=r5
mov cr.itir=r7;;
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
mov cr.iipa=r3
mov cr.ifs=r5
mov cr.iim=r7
ld8 r3=[r2],160;; // 160 byte increment
mov cr.iha=r3
rSkipIntrRegs:
ld8 r3=[r2],152;; // another 152 byte inc.
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2;; // duplicate r2 in r6
ld8 r3=[r2],8*3
ld8 r5=[r4],8*3
ld8 r7=[r6],8*3;;
mov cr.lid=r3
// mov cr.ivr=r5 // cr.ivr is read only
mov cr.tpr=r7;;
ld8 r3=[r2],8*3
ld8 r5=[r4],8*3
ld8 r7=[r6],8*3;;
// mov cr.eoi=r3
// mov cr.irr0=r5 // cr.irr0 is read only
// mov cr.irr1=r7;; // cr.irr1 is read only
ld8 r3=[r2],8*3
ld8 r5=[r4],8*3
ld8 r7=[r6],8*3;;
// mov cr.irr2=r3 // cr.irr2 is read only
// mov cr.irr3=r5 // cr.irr3 is read only
mov cr.itv=r7;;
ld8 r3=[r2],8*7
ld8 r5=[r4],8*7;;
mov cr.pmv=r3
mov cr.cmcv=r5;;
ld8 r3=[r2],8*23
ld8 r5=[r4],8*23;;
adds r2=8*23,r2
adds r4=8*23,r4;;
// mov cr.lrr0=r3
// mov cr.lrr1=r5
adds r2=8*2,r2;;
restore_ARs:
add r4=8,r2 // duplicate r2 in r4
add r6=2*8,r2;; // duplicate r2 in r4
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
mov ar.k0=r3
mov ar.k1=r5
mov ar.k2=r7;;
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
mov ar.k3=r3
mov ar.k4=r5
mov ar.k5=r7;;
ld8 r3=[r2],10*8
ld8 r5=[r4],10*8
ld8 r7=[r6],10*8;;
mov ar.k6=r3
mov ar.k7=r5
;;
ld8 r3=[r2],3*8
ld8 r5=[r4],3*8
ld8 r7=[r6],3*8;;
// mov ar.rsc=r3
// mov ar.bsp=r5 // ar.bsp is read only
mov ar.rsc=r0 // make sure that RSE is in enforced lazy mode
;;
mov ar.bspstore=r7;;
ld8 r9=[r2],8*13;;
mov ar.rnat=r9
mov ar.rsc=r3
ld8 r3=[r2],8*4;;
mov ar.ccv=r3
ld8 r3=[r2],8*4;;
mov ar.unat=r3
ld8 r3=[r2],8*4;;
mov ar.fpsr=r3
ld8 r3=[r2],160;; // 160
// mov ar.itc=r3
ld8 r3=[r2],8;;
mov ar.pfs=r3
ld8 r3=[r2],8;;
mov ar.lc=r3
ld8 r3=[r2];;
mov ar.ec=r3
add r2=8*62,r2;; // padding
restore_RRs:
mov r5=ar.lc
mov ar.lc=0x08-1
movl r4=0x00;;
cStRRr:
dep.z r7=r4,61,3
ld8 r3=[r2],8;;
mov rr[r7]=r3 // what are its access previledges?
add r4=1,r4
br.cloop.sptk.few cStRRr
;;
mov ar.lc=r5
;;
end_os_mca_restore:
br ia64_os_mca_done_restore;;
//EndStub//////////////////////////////////////////////////////////////////////
// ok, the issue here is that we need to save state information so
// it can be useable by the kernel debugger and show regs routines.
// In order to do this, our best bet is save the current state (plus
// the state information obtain from the MIN_STATE_AREA) into a pt_regs
// format. This way we can pass it on in a useable format.
//
//
// SAL to OS entry point for INIT on the monarch processor
// This has been defined for registration purposes with SAL
// as a part of ia64_mca_init.
//
// When we get here, the following registers have been
// set by the SAL for our use
//
// 1. GR1 = OS INIT GP
// 2. GR8 = PAL_PROC physical address
// 3. GR9 = SAL_PROC physical address
// 4. GR10 = SAL GP (physical)
// 5. GR11 = Init Reason
// 0 = Received INIT for event other than crash dump switch
// 1 = Received wakeup at the end of an OS_MCA corrected machine check
// 2 = Received INIT dude to CrashDump switch assertion
//
// 6. GR12 = Return address to location within SAL_INIT procedure
GLOBAL_ENTRY(ia64_monarch_init_handler)
.prologue
// stash the information the SAL passed to os
SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
;;
SAVE_MIN_WITH_COVER
;;
mov r8=cr.ifa
mov r9=cr.isr
adds r3=8,r2 // set up second base pointer
;;
SAVE_REST
// ok, enough should be saved at this point to be dangerous, and supply
// information for a dump
// We need to switch to Virtual mode before hitting the C functions.
movl r2=IA64_PSR_IT|IA64_PSR_IC|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFH|IA64_PSR_BN
mov r3=psr // get the current psr, minimum enabled at this point
;;
or r2=r2,r3
;;
movl r3=IVirtual_Switch
;;
mov cr.iip=r3 // short return to set the appropriate bits
mov cr.ipsr=r2 // need to do an rfi to set appropriate bits
;;
rfi
;;
IVirtual_Switch:
//
// We should now be running virtual
//
// Let's call the C handler to get the rest of the state info
//
alloc r14=ar.pfs,0,0,2,0 // now it's safe (must be first in insn group!)
;;
adds out0=16,sp // out0 = pointer to pt_regs
;;
DO_SAVE_SWITCH_STACK
.body
adds out1=16,sp // out0 = pointer to switch_stack
br.call.sptk.many rp=ia64_init_handler
.ret1:
return_from_init:
br.sptk return_from_init
END(ia64_monarch_init_handler)
//
// SAL to OS entry point for INIT on the slave processor
// This has been defined for registration purposes with SAL
// as a part of ia64_mca_init.
//
GLOBAL_ENTRY(ia64_slave_init_handler)
1: br.sptk 1b
END(ia64_slave_init_handler)