mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
b8d8b883e6
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>
946 lines
21 KiB
ArmAsm
946 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)
|