2005-04-16 15:20:36 -07:00
|
|
|
//
|
|
|
|
// 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
|
2005-04-22 14:44:40 -07:00
|
|
|
.global ia64_do_tlb_purge
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
.text
|
|
|
|
.align 16
|
|
|
|
|
2005-04-22 14:44:40 -07:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2005-04-22 14:44:40 -07:00
|
|
|
ia64_do_tlb_purge:
|
2005-04-16 15:20:36 -07:00
|
|
|
#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
|
|
|
|
;;
|
2005-04-22 14:44:40 -07:00
|
|
|
// 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:
|
2005-04-16 15:20:36 -07:00
|
|
|
// 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)
|