TEMP
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..7c2ac35
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,6 @@
+CC = /home/rth/work/gcc/run-axp/bin/alphaev6-linux-gcc
+
+all: pal.o
+
+pal.o: pal.S
+ $(CC) -c -Wa,-m21264 -g -o $@ $<
diff --git a/impure.h b/impure.h
new file mode 100644
index 0000000..230ad14
--- /dev/null
+++ b/impure.h
@@ -0,0 +1,339 @@
+/*
+** Commmon area Offset Definitions:
+*/
+
+#define CNS_Q_RCS_ID 0x0
+#define CNS_Q_SCRATCH 0xA0
+
+/*
+** Processor Saved State Area Offset Definitions:
+**
+** These offsets are relative to the base of the impure area.
+*/
+
+#define CNS_Q_BASE 0x000 /* Define base for debug monitor compatibility */
+#define CNS_Q_FLAG 0x100
+#define CNS_Q_HALT 0x108
+#define CNS_Q_GPR 0x110 /* Offset to base of saved GPR area */
+#define CNS_Q_FPR 0x210 /* Offset to base of saved FPR area */
+#define CNS_Q_MCHK 0x310
+#define CNS_Q_PT 0x318 /* Offset to base of saved PALtemp area */
+#define CNS_Q_SHADOW 0x3D8 /* Offset to base of saved PALshadow area */
+#define CNS_Q_IPR 0x418 /* Offset to base of saved IPR area */
+
+/*
+** Offsets to saved internal processor registers
+*/
+
+#define CNS_Q_EXC_ADDR 0x418
+#define CNS_Q_PAL_BASE 0x420
+#define CNS_Q_MM_STAT 0x428
+#define CNS_Q_VA 0x430
+#define CNS_Q_ICSR 0x438
+#define CNS_Q_IPL 0x440
+#define CNS_Q_IPS 0x448
+#define CNS_Q_ITB_ASN 0x450
+#define CNS_Q_ASTER 0x458
+#define CNS_Q_ASTRR 0x460
+#define CNS_Q_ISR 0x468
+#define CNS_Q_IVPTBR 0x470
+#define CNS_Q_MCSR 0x478
+#define CNS_Q_DC_MODE 0x480
+#define CNS_Q_MAF_MODE 0x488
+#define CNS_Q_SIRR 0x490
+#define CNS_Q_FPCSR 0x498
+#define CNS_Q_ICPERR_STAT 0x4A0
+#define CNS_Q_PM_CTR 0x4A8
+#define CNS_Q_EXC_SUM 0x4B0
+#define CNS_Q_EXC_MASK 0x4B8
+#define CNS_Q_INT_ID 0x4C0
+#define CNS_Q_DCPERR_STAT 0x4C8
+#define CNS_Q_SC_STAT 0x4D0
+#define CNS_Q_SC_ADDR 0x4D8
+#define CNS_Q_SC_CTL 0x4E0
+#define CNS_Q_BC_TAG_ADDR 0x4E8
+
+#define CNS_Q_BC_STAT 0x4F0
+#define CNS_Q_BC_ADDR 0x4F8
+#define CNS_Q_FILL_SYN 0x500
+#define CNS_Q_LD_LOCK 0x508
+
+#define CNS_Q_BC_CFG 0x510
+#define CNS_Q_BC_CFG2 0x518
+#define CNS_Q_PM_CTL 0x520 /* Performance monitor counter */
+
+#define CNS_Q_SROM_REV 0x528
+#define CNS_Q_PROC_ID 0x530
+#define CNS_Q_MEM_SIZE 0x538
+#define CNS_Q_CYCLE_CNT 0x540
+#define CNS_Q_SIGNATURE 0x548
+#define CNS_Q_PROC_MASK 0x550
+#define CNS_Q_SYSCTX 0x558
+
+#define CNS_Q_BC_CFG_OFF 0x560
+
+#define CNS_K_SIZE 0x568
+
+#if 0
+/*
+** Macros for saving/restoring data to/from the PAL impure scratch
+** area.
+**
+** The console save state area is larger than the addressibility
+** of the HW_LD/ST instructions (10-bit signed byte displacement),
+** so some adjustments to the base offsets, as well as the offsets
+** within each base region, are necessary.
+**
+** The console save state area is divided into two segments; the
+** CPU-specific segment and the platform-specific segment. The
+** state that is saved in the CPU-specific segment includes GPRs,
+** FPRs, IPRs, halt code, MCHK flag, etc. All other state is saved
+** in the platform-specific segment.
+**
+** The impure pointer will need to be adjusted by a different offset
+** value for each region within a given segment. The SAVE and RESTORE
+** macros will auto-magically adjust the offsets accordingly.
+**
+*/
+
+#define SAVE_GPR(reg,offset,base) \
+ stq_p reg, ((offset-0x200))(base)
+
+#define RESTORE_GPR(reg,offset,base) \
+ ldq_p reg, ((offset-0x200))(base)
+
+#define SAVE_FPR(reg,offset,base) \
+ stt reg, ((offset-0x200))(base)
+
+#define RESTORE_FPR(reg,offset,base) \
+ ldt reg, ((offset-0x200))(base)
+
+#define SAVE_IPR(reg,offset,base) \
+ mfpr v0, reg; \
+ stq_p v0, ((offset-CNS_Q_IPR))(base)
+
+#define RESTORE_IPR(reg,offset,base) \
+ ldq_p v0, ((offset-CNS_Q_IPR))(base); \
+ mtpr v0, reg
+
+#define SAVE_SHADOW(reg,offset,base) \
+ stq_p reg, ((offset-CNS_Q_IPR))(base)
+
+#define RESTORE_SHADOW(reg,offset,base)\
+ ldq_p reg, ((offset-CNS_Q_IPR))(base)
+
+/*
+ * STORE_IPR doesn't compensate for weird
+ * offset/base combinations.
+ */
+#define STORE_IPR(reg,offset,base) \
+ mfpr v0, reg; \
+ stq_p v0, ((offset))(base)
+
+/*
+** Macro to save the internal state of the general purpose
+** register file. Note that it switches out of shadow mode
+** to save the registers real registers hidden behind the
+** shadow registers.
+**
+** Register Usage Conventions:
+**
+** pt0 - Saved v0 (r0)
+** pt4 - Saved t0 (r1)
+** t0 - Base address of the save state area.
+** v0 - scratch. Will be trashed.
+*/
+#define SAVE_GPRS \
+ lda t0, 0x200(t0); \
+ mfpr v0, pt0; \
+ SAVE_GPR(v0,CNS_Q_GPR+0x00,t0); \
+ mfpr v0, pt4; \
+ SAVE_GPR(v0,CNS_Q_GPR+0x08,t0); \
+ SAVE_GPR(r2,CNS_Q_GPR+0x10,t0); \
+ SAVE_GPR(r3,CNS_Q_GPR+0x18,t0); \
+ SAVE_GPR(r4,CNS_Q_GPR+0x20,t0); \
+ SAVE_GPR(r5,CNS_Q_GPR+0x28,t0); \
+ mfpr r5, icsr; \
+ ldah r4, (1<<(ICSR_V_SDE-16))(zero); \
+ bic r5, r4, r4; \
+ mtpr r4, icsr; \
+ STALL; \
+ STALL; \
+ STALL; \
+ NOP; \
+ SAVE_GPR(r6,CNS_Q_GPR+0x30,t0); \
+ SAVE_GPR(r7,CNS_Q_GPR+0x38,t0); \
+ SAVE_GPR(r8,CNS_Q_GPR+0x40,t0); \
+ SAVE_GPR(r9,CNS_Q_GPR+0x48,t0); \
+ SAVE_GPR(r10,CNS_Q_GPR+0x50,t0); \
+ SAVE_GPR(r11,CNS_Q_GPR+0x58,t0); \
+ SAVE_GPR(r12,CNS_Q_GPR+0x60,t0); \
+ SAVE_GPR(r13,CNS_Q_GPR+0x68,t0); \
+ SAVE_GPR(r14,CNS_Q_GPR+0x70,t0); \
+ SAVE_GPR(r15,CNS_Q_GPR+0x78,t0); \
+ SAVE_GPR(r16,CNS_Q_GPR+0x80,t0); \
+ SAVE_GPR(r17,CNS_Q_GPR+0x88,t0); \
+ SAVE_GPR(r18,CNS_Q_GPR+0x90,t0); \
+ SAVE_GPR(r19,CNS_Q_GPR+0x98,t0); \
+ SAVE_GPR(r20,CNS_Q_GPR+0xA0,t0); \
+ SAVE_GPR(r21,CNS_Q_GPR+0xA8,t0); \
+ SAVE_GPR(r22,CNS_Q_GPR+0xB0,t0); \
+ SAVE_GPR(r23,CNS_Q_GPR+0xB8,t0); \
+ SAVE_GPR(r24,CNS_Q_GPR+0xC0,t0); \
+ SAVE_GPR(r25,CNS_Q_GPR+0xC8,t0); \
+ SAVE_GPR(r26,CNS_Q_GPR+0xD0,t0); \
+ SAVE_GPR(r27,CNS_Q_GPR+0xD8,t0); \
+ SAVE_GPR(r28,CNS_Q_GPR+0xE0,t0); \
+ SAVE_GPR(r29,CNS_Q_GPR+0xE8,t0); \
+ SAVE_GPR(r30,CNS_Q_GPR+0xF0,t0); \
+ SAVE_GPR(r31,CNS_Q_GPR+0xF8,t0); \
+ STALL; \
+ STALL; \
+ mtpr r5, icsr; \
+ STALL; \
+ STALL; \
+ STALL; \
+ NOP; \
+ lda t0, -0x200(t0)
+
+/*
+** Macro to restore the internal state of the general purpose
+** register file. Note that it switches out of shadow mode
+** to save the registers real registers hidden behind the
+** shadow registers.
+**
+** Register Usage Conventions:
+**
+** t0 - Base address of the save state area.
+** v0 (r0) and t1 (r2) will be used as scratch.
+** Warning: Make sure that the base register t0
+** is not restored before we are done using it.
+*/
+#define RESTORE_GPRS \
+ lda t0, 0x200(t0); \
+ mfpr v0, icsr; \
+ ldah t1, (1<<(ICSR_V_SDE-16))(zero); \
+ bic v0, t1, t1; \
+ mtpr t1, icsr; \
+ STALL; \
+ STALL; \
+ STALL; \
+ NOP; \
+ RESTORE_GPR(r2,CNS_Q_GPR+0x10,t0); \
+ RESTORE_GPR(r3,CNS_Q_GPR+0x18,t0); \
+ RESTORE_GPR(r4,CNS_Q_GPR+0x20,t0); \
+ RESTORE_GPR(r5,CNS_Q_GPR+0x28,t0); \
+ RESTORE_GPR(r6,CNS_Q_GPR+0x30,t0); \
+ RESTORE_GPR(r7,CNS_Q_GPR+0x38,t0); \
+ RESTORE_GPR(r8,CNS_Q_GPR+0x40,t0); \
+ RESTORE_GPR(r9,CNS_Q_GPR+0x48,t0); \
+ RESTORE_GPR(r10,CNS_Q_GPR+0x50,t0); \
+ RESTORE_GPR(r11,CNS_Q_GPR+0x58,t0); \
+ RESTORE_GPR(r12,CNS_Q_GPR+0x60,t0); \
+ RESTORE_GPR(r13,CNS_Q_GPR+0x68,t0); \
+ RESTORE_GPR(r14,CNS_Q_GPR+0x70,t0); \
+ RESTORE_GPR(r15,CNS_Q_GPR+0x78,t0); \
+ RESTORE_GPR(r16,CNS_Q_GPR+0x80,t0); \
+ RESTORE_GPR(r17,CNS_Q_GPR+0x88,t0); \
+ RESTORE_GPR(r18,CNS_Q_GPR+0x90,t0); \
+ RESTORE_GPR(r19,CNS_Q_GPR+0x98,t0); \
+ RESTORE_GPR(r20,CNS_Q_GPR+0xA0,t0); \
+ RESTORE_GPR(r21,CNS_Q_GPR+0xA8,t0); \
+ RESTORE_GPR(r22,CNS_Q_GPR+0xB0,t0); \
+ RESTORE_GPR(r23,CNS_Q_GPR+0xB8,t0); \
+ RESTORE_GPR(r24,CNS_Q_GPR+0xC0,t0); \
+ RESTORE_GPR(r25,CNS_Q_GPR+0xC8,t0); \
+ RESTORE_GPR(r26,CNS_Q_GPR+0xD0,t0); \
+ RESTORE_GPR(r27,CNS_Q_GPR+0xD8,t0); \
+ RESTORE_GPR(r28,CNS_Q_GPR+0xE0,t0); \
+ RESTORE_GPR(r29,CNS_Q_GPR+0xE8,t0); \
+ RESTORE_GPR(r30,CNS_Q_GPR+0xF0,t0); \
+ RESTORE_GPR(r31,CNS_Q_GPR+0xF8,t0); \
+ STALL; \
+ STALL; \
+ mtpr v0, icsr; \
+ STALL; \
+ STALL; \
+ STALL; \
+ NOP; \
+ RESTORE_GPR(r0,CNS_Q_GPR+0x00,t0); \
+ RESTORE_GPR(r1,CNS_Q_GPR+0x08,t0);
+
+#endif /* 0 */
+
+
+
+/*
+** Short Corrected Error Logout Frame
+*/
+
+#define LAS_Q_BASE CNS_K_SIZE
+
+#define LAS_L_SIZE 0x0000
+#define LAS_L_FLAG 0x0004
+
+#define LAS_Q_OFFSET_BASE 0x0008
+
+#define LAS_L_CPU 0x0008
+#define LAS_L_SYS 0x000C
+
+#define LAS_Q_MCHK_CODE 0x0010
+
+#define LAS_Q_CPU_BASE 0x0018
+
+#define LAS_Q_BC_ADDR 0x0018
+#define LAS_Q_FILL_SYNDROME 0x0020
+
+#define LAS_Q_BC_STAT 0x0028
+#define LAS_Q_ISR 0x0030
+
+#define LAS_Q_SYS_BASE 0x0038
+
+#define LAS_K_SIZE 0x0038
+
+/*
+** Long Machine Check Error Logout Frame
+*/
+
+#define LAF_Q_BASE (LAS_Q_BASE+LAS_K_SIZE)
+
+#define LAF_L_SIZE 0x0000
+#define LAF_L_FLAG 0x0004
+
+#define LAF_Q_OFFSET_BASE 0x0008
+
+#define LAF_L_CPU 0x0008
+#define LAF_L_SYS 0x000C
+
+#define LAF_Q_MCHK_CODE 0x0010
+#define LAF_Q_PT 0x0018
+
+#define LAF_Q_CPU_BASE 0x00D8
+
+#define LAF_Q_EXC_ADDR 0x00D8
+#define LAF_Q_EXC_SUM 0x00E0
+#define LAF_Q_EXC_MASK 0x00E8
+#define LAF_Q_PAL_BASE 0x00F0
+#define LAF_Q_ISR 0x00F8
+#define LAF_Q_ICSR 0x0100
+#define LAF_Q_ICPERR 0x0108
+#define LAF_Q_DCPERR 0x0110
+#define LAF_Q_VA 0x0118
+#define LAF_Q_MM_STAT 0x0120
+#define LAF_Q_BC_ADDR 0x0140
+#define LAF_Q_BC_STAT 0x0150
+#define LAF_Q_SYS_BASE 0x0160
+
+#define LAF_Q_CPU_ERR0 0x160
+#define LAF_Q_CPU_ERR1 0x168
+#define LAF_Q_CIA_ERR 0x170
+#define LAF_Q_CIA_STAT 0x178
+#define LAF_Q_ERR_MASK 0x180
+#define LAF_Q_CIA_SYN 0x188
+#define LAF_Q_MEM_ERR0 0x190
+#define LAF_Q_MEM_ERR1 0x198
+#define LAF_Q_PCI_ERR0 0x1A0
+#define LAF_Q_PCI_ERR1 0x1A8
+#define LAF_Q_PCI_ERR2 0x1B0
+
+#define LAF_K_SIZE 0x01B8
diff --git a/osf.h b/osf.h
new file mode 100644
index 0000000..ab87955
--- /dev/null
+++ b/osf.h
@@ -0,0 +1,208 @@
+/*
+ * Virtual Address Options: 8K byte page size
+ */
+#define VA_S_SIZE 43
+#define VA_S_OFF 13
+#define VA_S_SEG 10
+#define VA_S_PAGE_SIZE 8192
+
+/*
+** System Entry Instruction Fault (entIF) Constants:
+*/
+
+#define IF_K_BPT 0x0
+#define IF_K_BUGCHK 0x1
+#define IF_K_GENTRAP 0x2
+#define IF_K_FEN 0x3
+#define IF_K_OPCDEC 0x4
+
+/*
+** System Entry Hardware Interrupt (entInt) Constants:
+*/
+
+#define INT_K_IP 0x0
+#define INT_K_CLK 0x1
+#define INT_K_MCHK 0x2
+#define INT_K_DEV 0x3
+#define INT_K_PERF 0x4
+
+/*
+** System Entry MM Fault (entMM) Constants:
+*/
+
+#define MM_K_TNV 0x0
+#define MM_K_ACV 0x1
+#define MM_K_FOR 0x2
+#define MM_K_FOE 0x3
+#define MM_K_FOW 0x4
+
+/*
+** Processor Status Register (PS) Bit Summary
+**
+** Extent Size Name Function
+** ------ ---- ---- ---------------------------------
+** <3> 1 CM Current Mode
+** <2:0> 3 IPL Interrupt Priority Level
+*/
+
+#define PS_V_CM 3
+#define PS_M_CM (1<<PS_V_CM)
+#define PS_V_IPL 0
+#define PS_M_IPL (7<<PS_V_IPL)
+
+#define PS_K_KERN (0<<PS_V_CM)
+#define PS_K_USER (1<<PS_V_CM)
+
+#define IPL_K_ZERO 0x0
+#define IPL_K_SW0 0x1
+#define IPL_K_SW1 0x2
+#define IPL_K_DEV0 0x3
+#define IPL_K_DEV1 0x4
+#define IPL_K_CLK 0x5
+#define IPL_K_RT 0x6
+#define IPL_K_PERF 0x6
+#define IPL_K_PFAIL 0x6
+#define IPL_K_MCHK 0x7
+
+#define IPL_K_LOW 0x0
+#define IPL_K_HIGH 0x7
+
+
+/*
+** Process Control Block (PCB) Offsets:
+*/
+
+#define PCB_Q_KSP 0x0000
+#define PCB_Q_USP 0x0008
+#define PCB_Q_PTBR 0x0010
+#define PCB_L_PCC 0x0018
+#define PCB_L_ASN 0x001C
+#define PCB_Q_UNIQUE 0x0020
+#define PCB_Q_FEN 0x0028
+#define PCB_Q_RSV0 0x0030
+#define PCB_Q_RSV1 0x0038
+
+/*
+** Stack Frame (FRM) Offsets:
+**
+** There are two types of system entries for OSF/1 - those for the
+** callsys CALL_PAL function and those for exceptions and interrupts.
+** Both entry types use the same stack frame layout. The stack frame
+** contains space for the PC, the PS, the saved GP, and the saved
+** argument registers a0, a1, and a2. On entry, SP points to the
+** saved PS.
+*/
+
+#define FRM_Q_PS 0
+#define FRM_Q_PC 8
+#define FRM_Q_GP 16
+#define FRM_Q_A0 24
+#define FRM_Q_A1 32
+#define FRM_Q_A2 40
+
+#define FRM_K_SIZE 48
+
+/*
+** Halt Codes:
+*/
+
+#define HLT_K_RESET 0x0000
+#define HLT_K_HW_HALT 0x0001
+#define HLT_K_KSP_INVAL 0x0002
+#define HLT_K_SCBB_INVAL 0x0003
+#define HLT_K_PTBR_INVAL 0x0004
+#define HLT_K_SW_HALT 0x0005
+#define HLT_K_DBL_MCHK 0x0006
+#define HLT_K_MCHK_FROM_PAL 0x0007
+
+/*
+** Machine Check Codes:
+*/
+
+#define MCHK_K_TPERR 0x0080
+#define MCHK_K_TCPERR 0x0082
+#define MCHK_K_HERR 0x0084
+#define MCHK_K_ECC_C 0x0086
+#define MCHK_K_ECC_NC 0x0088
+#define MCHK_K_UNKNOWN 0x008A
+#define MCHK_K_CACKSOFT 0x008C
+#define MCHK_K_BUGCHECK 0x008E
+#define MCHK_K_OS_BUGCHECK 0x0090
+#define MCHK_K_DCPERR 0x0092
+#define MCHK_K_ICPERR 0x0094
+#define MCHK_K_RETRY_IRD 0x0096
+#define MCHK_K_PROC_HERR 0x0098
+
+/*
+** System Machine Check Codes:
+*/
+
+#define MCHK_K_READ_NXM 0x0200
+#define MCHK_K_SYS_HERR 0x0202
+
+/*
+** Machine Check Error Status Summary (MCES) Register Format
+**
+** Extent Size Name Function
+** ------ ---- ---- ---------------------------------
+** <0> 1 MIP Machine check in progress
+** <1> 1 SCE System correctable error in progress
+** <2> 1 PCE Processor correctable error in progress
+** <3> 1 DPC Disable PCE error reporting
+** <4> 1 DSC Disable SCE error reporting
+*/
+
+#define MCES_V_MIP 0
+#define MCES_M_MIP (1<<MCES_V_MIP)
+#define MCES_V_SCE 1
+#define MCES_M_SCE (1<<MCES_V_SCE)
+#define MCES_V_PCE 2
+#define MCES_M_PCE (1<<MCES_V_PCE)
+#define MCES_V_DPC 3
+#define MCES_M_DPC (1<<MCES_V_DPC)
+#define MCES_V_DSC 4
+#define MCES_M_DSC (1<<MCES_V_DSC)
+
+#define MCES_M_ALL (MCES_M_MIP | MCES_M_SCE | MCES_M_PCE | MCES_M_DPC \
+ | MCES_M_DSC)
+
+/*
+**
+** Miscellaneous PAL State Flags (ptMisc) Bit Summary
+**
+** Extent Size Name Function
+** ------ ---- ---- ---------------------------------
+** <55:48> 8 SWAP Swap PALcode flag -- character 'S'
+** <47:32> 16 MCHK Machine Check Error code
+** <31:16> 16 SCB System Control Block vector
+** <15:08> 8 WHAMI Who-Am-I identifier
+** <04:00> 5 MCES Machine Check Error Summary bits
+**
+*/
+
+#define PT16_V_MCES 0
+#define PT16_V_WHAMI 8
+#define PT16_V_SCB 16
+#define PT16_V_MCHK 32
+#define PT16_V_SWAP 48
+
+/*
+** Who-Am-I (WHAMI) Register Format
+**
+** Extent Size Name Function
+** ------ ---- ---- ---------------------------------
+** <7:0> 8 ID Who-Am-I identifier
+** <15:8> 1 SWAP Swap PALcode flag - character 'S'
+*/
+
+#define WHAMI_V_SWAP 8
+#define WHAMI_M_SWAP (1<<WHAMI_V_SWAP)
+#define WHAMI_V_ID 0
+#define WHAMI_M_ID 0xFF
+
+#define WHAMI_K_SWAP 0x53 /* Character 'S' */
+
+/* System Control Block stuff. */
+#define SCB_Q_SYSMCHK 0x0660
+#define SCB_Q_PROCMCHK 0x0670
+
diff --git a/pal.S b/pal.S
new file mode 100644
index 0000000..0cc8f7c
--- /dev/null
+++ b/pal.S
@@ -0,0 +1,1774 @@
+ .set noat
+ .set nomacro
+ .text
+
+#include "osf.h"
+#include "impure.h"
+
+/* General Purpose Registers. */
+#define v0 $0
+#define t0 $1
+#define t1 $2
+#define t2 $3
+#define t3 $4
+#define t4 $5
+#define t5 $6
+#define a0 $16
+#define a1 $17
+#define a2 $18
+#define a3 $19
+#define a4 $20
+#define a5 $21
+#define t8 $22
+#define t9 $23
+#define t10 $24
+
+/* PALcode Shadow Registers. These registers are swapped out when
+ QEMU is in PALmode. Unlike real hardware, there is no enable bit.
+ However, also unlike real hardware, the originals can be accessed
+ via MTPR/MFPR. */
+#define p0 $8
+#define p1 $9
+#define p2 $10
+#define p3 $11
+#define p4 $12
+#define p5 $13
+#define p6 $14 // Used to save exc_addr for machine check
+#define p7 $25
+
+/* QEMU Processor Registers. */
+#define qemu_ps 0
+#define qemu_fen 1
+#define qemu_pcc_ofs 2
+#define qemu_trap_arg0 3
+#define qemu_trap_arg1 4
+#define qemu_trap_arg2 5
+#define qemu_exc_addr 6
+#define qemu_palbr 7
+#define qemu_ptbr 8
+#define qemu_vptptr 9
+#define qemu_unique 10
+#define qemu_shadow0 32
+#define qemu_shadow1 33
+#define qemu_shadow2 34
+#define qemu_shadow3 35
+#define qemu_shadow4 36
+#define qemu_shadow5 37
+#define qemu_shadow6 38
+#define qemu_shadow7 39
+
+/* PALcode Processor Register Private Storage. */
+#define pt0 40
+#define pt1 41
+#define pt2 42
+#define pt3 43
+#define pt4 44
+#define pt5 45
+#define pt6 46
+#define pt7 47
+#define pt8 48
+#define pt9 49
+#define pt10 50
+#define pt11 51
+#define pt12 52
+#define pt13 53
+#define pt14 54
+#define pt15 55
+#define pt16 56
+#define pt17 57
+#define pt18 58
+#define pt19 59
+#define pt20 60
+#define pt21 61
+#define pt22 62
+#define pt23 63
+
+/* QEMU function calls, via mtpr. */
+#define qemu_tbia 128
+#define qemu_tbis 129
+
+/* PALcode uses of the private storage slots. */
+#define ptSuper pt0
+#define ptEntUna pt1
+#define ptEntIF pt2
+#define ptEntSys pt3
+#define ptEntInt pt4
+#define ptEntArith pt5
+#define ptEntMM pt6
+#define ptMces pt7
+#define ptSysVal pt8
+#define ptUsp pt9
+#define ptKsp pt10
+#define ptKgp pt11
+#define ptPcbb pt12
+#define ptImpure pt13
+#define ptMchk0 pt14
+#define ptMchk1 pt15
+#define ptMisc pt16
+#define ptMchk2 pt17
+#define ptMchk3 pt18
+#define ptMchk4 pt19
+#define ptMchk5 pt20
+
+/*
+ * Shortcuts for various PALmode instructions.
+ */
+#define mtpr hw_mtpr
+#define mfpr hw_mfpr
+#define stq_p hw_stq/p
+#define stl_p hw_stl/p
+#define ldl_p hw_ldl/p
+#define ldq_p hw_ldq/p
+
+/* QEMU recognizes the EV4/EV5 HW_REI instruction as a special case of
+ the EV6 HW_RET instruction. This pulls the destination address from
+ the EXC_ADDR processor register. */
+#define hw_rei hw_ret ($31)
+
+/*
+ * Create a standard kernel entry stack frame.
+ */
+
+#define FRM_Q_PS 0
+#define FRM_Q_PC 8
+#define FRM_Q_GP 16
+#define FRM_Q_A0 24
+#define FRM_Q_A1 32
+#define FRM_Q_A2 40
+#define FRM_K_SIZE 48
+
+.macro STACK_FRAME save_ps, save_pc, temp
+ // Test if we're currently in user mode
+ and \save_ps, PS_M_CM, \temp
+ bne \temp, 0f
+ // Switch to kernel mode
+ mtpr $31, qemu_ps
+ mtpr $sp, ptUsp
+ mfpr $sp, ptKsp
+ // Allocate the stack frame
+0: lda $sp, -FRM_K_SIZE($sp)
+ stq \save_ps, FRM_Q_PS($sp)
+ stq \save_pc, FRM_Q_PC($sp)
+ stq $gp, FRM_Q_GP($sp)
+ stq a0, FRM_Q_A0($sp)
+ stq a1, FRM_Q_A1($sp)
+ stq a2, FRM_Q_A2($sp)
+.endm
+
+/*
+ * QEMU emulator "hardware" entry points.
+ */
+
+/*
+ * Reset
+ *
+ * INPUT PARAMETERS:
+ *
+ * trap_arg0 = Memory size
+ * trap_arg1 = Kernel entry (if loaded)
+ *
+ * Given that we've no CPU state to save, set things up so that we can
+ * jump to C to do the real initialization.
+ */
+ .org 0x0000
+__start:
+ br $gp, .+4
+ ldah $gp, 0($gp) !gpdisp!1
+ lda $gp, 0($gp) !gpdisp!1
+ lda $sp, stack_top($gp) !gprel
+ mfpr a0, qemu_trap_arg0
+ mfpr a1, qemu_trap_arg1
+ br do_start !samegp
+
+/*
+ * Machine Check
+ *
+ * INPUT PARAMETERS:
+ *
+ * trap_arg0 =
+ * trap_arg1 =
+ * trap_arg2 =
+ */
+ .org 0x0080
+Pal_Mchk:
+ mfpr p5, ptMces // Get the error summary
+ or p5, MCES_M_MIP, p4 // Set machine-check-in-progress
+ zap p4, 0x3c, p4 // Clear space for MCHK and SCB
+ mtpr p4, ptMces
+
+ ldah p0, SCB_Q_PROCMCHK
+ or p4, p0, p4 // Merge in the SCB vector
+ lda p0, MCHK_K_PROC_HERR
+ sll p0, PT16_V_MCHK, p0
+ or p4, p0, p4 // Merge in the MCHK code
+ mtpr p4, ptMisc
+
+ br MchkCommon_SaveRegs
+
+/*
+ * Interrupt
+ *
+ * INPUT PARAMETERS:
+ *
+ * trap_arg0 = interrupt type
+ * trap_arg1 = UNDEFINED
+ * trap_arg2 = UNDEFINED
+ */
+ .org 0x0100
+Pal_Interrupt:
+ mfpr p0, qemu_ps
+ mfpr p6, qemu_exc_addr
+
+ STACK_FRAME p0, p6, p2
+
+ mfpr p0, ptEntInt
+ mfpr $gp, ptKgp
+ mfpr a0, qemu_trap_arg0
+ hw_ret (p0)
+
+/*
+ * Memory Fault
+ *
+ * INPUT PARAMETERS:
+ *
+ * trap_arg0 = faulting address
+ * trap_arg1 = fault type (TNV, ACV, FOR, FOW, FOE)
+ * trap_arg2 = access type (exec=-1, read=0, write=1)
+ */
+ .org 0x0180
+Pal_MMFault:
+ mfpr p0, qemu_ps
+ mfpr p6, qemu_exc_addr
+
+ STACK_FRAME p0, p6, p2
+
+ mfpr p0, ptEntMM
+ mfpr $gp, ptKgp
+ mfpr a0, qemu_trap_arg0
+ mfpr a1, qemu_trap_arg1
+ mfpr a2, qemu_trap_arg2
+ hw_ret (p0)
+
+/*
+ * Unaligned Data
+ *
+ * INPUT PARAMETERS:
+ *
+ * trap_arg0 = faulting address
+ * trap_arg1 = opcode of faulting insn
+ * trap_arg2 = src/dst register number
+ */
+ .org 0x0200
+Pal_Unalign:
+ mfpr p0, qemu_ps
+ mfpr p6, qemu_exc_addr
+ addq p6, 4, p1 // increment past the faulting insn
+ blbs p6, MchkBugCheck
+
+ STACK_FRAME p0, p1, p2
+
+ mfpr p0, ptEntUna
+ mfpr $gp, ptKgp
+ mfpr a0, qemu_trap_arg0
+ mfpr a1, qemu_trap_arg1
+ mfpr a2, qemu_trap_arg2
+ hw_ret (p0)
+
+/*
+ * Illegal Opcode
+ *
+ * INPUT PARAMETERS:
+ *
+ * trap_arg0 = UNDEFINED
+ * trap_arg1 = UNDEFINED
+ * trap_arg2 = UNDEFINED
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r16 (a0) = Instruction fault code
+ * r17 (a1) = UNPREDICTABLE
+ * r18 (a2) = UNPREDICTABLE
+ */
+ .org 0x0280
+Pal_OpcDec:
+ mfpr p0, qemu_ps
+ mfpr p6, qemu_exc_addr
+ addq p6, 4, p1 // increment past the faulting insn
+ blbs p6, MchkBugCheck
+
+ STACK_FRAME p0, p1, p2
+
+ mfpr p0, ptEntIF
+ mfpr $gp, ptKgp
+ mov IF_K_OPCDEC, a0
+ hw_ret (p0)
+
+/*
+ * Arithmetic Trap
+ *
+ * INPUT PARAMETERS:
+ *
+ * trap_arg0 = exception type
+ * trap_arg1 = register modification mask
+ * trap_arg2 = UNDEFINED
+ */
+ .org 0x0300
+Pal_Arith:
+ mfpr p0, qemu_ps
+ mfpr p6, qemu_exc_addr
+ blbs p6, MchkBugCheck
+
+ STACK_FRAME p0, p6, p2
+
+ mfpr p0, ptEntArith
+ mfpr $gp, ptKgp
+ mfpr a0, qemu_trap_arg0
+ mfpr a1, qemu_trap_arg1
+ hw_ret (p0)
+
+/*
+ * Floating Point Disabled
+ *
+ * INPUT PARAMETERS:
+ *
+ * trap_arg0 = UNDEFINED
+ * trap_arg1 = UNDEFINED
+ * trap_arg2 = UNDEFINED
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r16 (a0) = Instruction fault code
+ * r17 (a1) = UNPREDICTABLE
+ * r18 (a2) = UNPREDICTABLE
+ */
+ .org 0x0380
+Pal_Fen:
+ mfpr p0, qemu_ps
+ mfpr p6, qemu_exc_addr
+ blbs p6, MchkBugCheck
+
+ STACK_FRAME p0, p6, p2
+
+ mfpr p0, ptEntIF
+ mfpr $gp, ptKgp
+ mov IF_K_FEN, a0
+ hw_ret (p0)
+
+/*
+ * OSF/1 Privileged CALL_PAL Entry Points
+ */
+
+#define ORG_CALL_PAL_PRIV(X) .org 0x1000+64*X
+
+/*
+ * Halt
+ *
+ * SIDE EFFECTS:
+ *
+ * We either power down the system or re-enter the console.
+ * But given that we're not returning to the kernel, there's
+ * no reason to continue processing in assembler. Go to C.
+ */
+ ORG_CALL_PAL_PRIV(0x00)
+CallPal_Halt:
+ bsr p7, UpdatePCB // Save kernel data
+ lda v0, HLT_K_SW_HALT
+ br Sys_EnterConsole
+
+/*
+ * Cache Flush
+ *
+ * For QEMU, this is of course a no-op.
+ */
+ ORG_CALL_PAL_PRIV(0x01)
+CallPal_Cflush:
+ hw_rei
+
+/*
+ * Drain Aborts
+ *
+ * For QEMU, this is of course a no-op.
+ */
+ ORG_CALL_PAL_PRIV(0x02)
+CallPal_Draina:
+ hw_rei
+
+ ORG_CALL_PAL_PRIV(0x03)
+CallPal_OpcDec03:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x04)
+CallPal_OpcDec04:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x05)
+CallPal_OpcDec05:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x06)
+CallPal_OpcDec06:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x07)
+CallPal_OpcDec07:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x08)
+CallPal_OpcDec08:
+ br CallPal_OpcDec
+
+/*
+ * Console Service
+ *
+ * INPUT PARAMETERS:
+ *
+ * r0 (v0) = Option selector
+ * r16..r21 (a0..a5) = Implementation specific entry parameters
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers a0..a5, and v0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x09)
+CallPal_Cserve:
+ br Sys_Cserve
+
+/*
+ * Swap PALcode
+ *
+ * FUNCTIONAL DESCRIPTION:
+ *
+ * The swap PALcode (swppal) function replaces the current
+ * (active) PALcode by the specified new PALcode image.
+ * This function is intended for use by operating systems
+ * only during bootstraps and restarts, or during transitions
+ * to console I/O mode.
+ *
+ * The PALcode descriptor passed in a0 is interpreted as
+ * either a PALcode variant or the base physical address
+ * of the new PALcode image. If a variant, the PALcode
+ * image must have been previously loaded. No PALcode
+ * loading occurs as a result of this function.
+ *
+ * NOTE:
+ * This implementation of SWPPAL does not support PALcode
+ * variants. If a variant is specified in a0, a check is
+ * performed to determine whether the variant is OSF/1 or
+ * not and the returned status is either unknown variant
+ * (if not OSF/1) or variant not loaded.
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New PALcode variant or base physical address
+ * r17 (a1) = New PC
+ * r18 (a2) = New PCB
+ * r19 (a3) = New VptPtr
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = Returned status indicating:
+ * 0 - Success (PALcode was switched)
+ * 1 - Unknown PALcode variant
+ * 2 - Known PALcode variant, but PALcode not loaded
+ */
+ ORG_CALL_PAL_PRIV(0x0A)
+CallPal_SwpPal:
+ // Save a copy of the return address in case of machine check.
+ mfpr p6, qemu_exc_addr
+
+ // Accept swapping to OSF PALcode. The side effect here is to
+ // load the other parameters for the kernel.
+ cmpeq a0, 2, v0
+ bne v0, CallPal_SwpPal_Cont
+
+ // Return as an unknown PALcode variant
+ mov 1, v0
+ hw_rei
+
+ .text 1
+CallPal_SwpPal_Cont:
+ // YOUAREHERE
+ .previous
+
+ ORG_CALL_PAL_PRIV(0x0B)
+CallPal_OpcDec0B:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x0C)
+CallPal_OpcDec0C:
+ br CallPal_OpcDec
+
+/*
+ * Write Interprocessor Interrupt Request
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = target processor number
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * SIDE EFFECTS:
+ *
+ */
+ ORG_CALL_PAL_PRIV(0x0D)
+CallPal_WrIpir:
+ // We do not currently support more cpus
+ hw_rei
+
+ ORG_CALL_PAL_PRIV(0x0E)
+CallPal_OpcDec0E:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x0F)
+CallPal_OpcDec0F:
+ br CallPal_OpcDec
+
+/*
+ * Read Machine Check Error Summary
+ *
+ * INPUT PARAMETERS:
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = returned MCES value
+ *
+ * SIDE EFFECTS:
+ *
+ */
+ ORG_CALL_PAL_PRIV(0x10)
+CallPal_RdMces:
+ mfpr v0, ptMces // Get current MCES value
+ and v0, MCES_M_ALL, v0 // Clear all other bits
+ hw_rei
+
+/*
+ * Write Machine Check Error Summary
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = MCES<DPC> <- a0<3>, MCES<DSC> <- a0<4>
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x11)
+CallPal_WrMces:
+ // Clear MIP, SCE, PCE
+ and a0, (MCES_M_MIP | MCES_M_SCE | MCES_M_PCE), p0
+ mfpr p1, ptMces
+ bic p1, p0, p1
+
+ // Copy DPC and DSC
+ and a0, (MCES_M_DPC | MCES_M_DSC), p0
+ bic p1, (MCES_M_DPC | MCES_M_DSC), p1
+ or p1, p0, p1
+
+ mtpr p1, ptMces
+ hw_rei
+
+ ORG_CALL_PAL_PRIV(0x12)
+CallPal_OpcDec12:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x13)
+CallPal_OpcDec13:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x14)
+CallPal_OpcDec14:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x15)
+CallPal_OpcDec15:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x16)
+CallPal_OpcDec16:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x17)
+CallPal_OpcDec17:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x18)
+CallPal_OpcDec18:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x19)
+CallPal_OpcDec19:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x1A)
+CallPal_OpcDec1A:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x1B)
+CallPal_OpcDec1B:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x1C)
+CallPal_OpcDec1C:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x1D)
+CallPal_OpcDec1D:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x1E)
+CallPal_OpcDec1E:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x1F)
+CallPal_OpcDec1F:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x20)
+CallPal_OpcDec20:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x21)
+CallPal_OpcDec21:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x22)
+CallPal_OpcDec22:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x23)
+CallPal_OpcDec23:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x24)
+CallPal_OpcDec24:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x25)
+CallPal_OpcDec25:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x26)
+CallPal_OpcDec26:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x27)
+CallPal_OpcDec27:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x28)
+CallPal_OpcDec28:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x29)
+CallPal_OpcDec29:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x2A)
+CallPal_OpcDec2A:
+ br CallPal_OpcDec
+
+/*
+ * Write Floating Point Enable
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = ICSR<FPE> <- a0<0>
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x2B)
+CallPal_WrFen:
+ mfpr p0, ptPcbb // Get PCBB
+ and a0, 1, a0 // Clean new FEN value to single bit
+ mtpr a0, qemu_fen
+ stl_p a0, PCB_Q_FEN(p0) // Write new PCB<FEN>
+ hw_rei
+
+ ORG_CALL_PAL_PRIV(0x2C)
+CallPal_OpcDec2C:
+ br CallPal_OpcDec
+
+/*
+ * Write Virtual Page Table Pointer
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New virtual page table pointer
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x2D)
+CallPal_WrVptPtr:
+ mtpr a0, qemu_vptptr
+ hw_rei
+
+ ORG_CALL_PAL_PRIV(0x2E)
+CallPal_OpcDec2E:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_PRIV(0x2F)
+CallPal_OpcDec2F:
+ br CallPal_OpcDec
+
+/*
+ * Swap Process Context
+ *
+ * FUNCTIONAL DESCRIPTION:
+ *
+ * The swap process context (swpctx) function saves
+ * the current process data in the current PCB, then
+ * switches to the PCB passed in a0 and loads the
+ * new process context. The old PCB is returned in v0.
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New PCBB
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = Old PCBB
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x30)
+CallPal_SwpCtx:
+ rpcc p5 // Get cycle counter
+ mfpr p6, qemu_exc_addr // Save exc_addr for machine check
+
+ mfpr v0, ptPcbb // Get current PCBB
+ mtpr a0, ptPcbb // Save new PCBB
+ srl p5, 32, p7 // Move CC<OFFSET> to low longword
+
+ addl p5, p7, p7 // Accumulate time for old pcb
+ stl_p p7, PCB_L_PCC(v0)
+
+ ldl_p t9, PCB_L_PCC(a0) // Get new PCC
+ subl t9, p5, p5 // Generate and ...
+ mtpr p5, qemu_pcc_ofs // .. set new CC<OFFSET> bits
+
+ stq_p $sp, PCB_Q_KSP(v0) // Store old kernel stack pointer
+ mfpr t10, ptUsp // Save old user stack pointer
+ stq_p t10, PCB_Q_USP(v0)
+
+ br CallPal_SwpCtxCont
+
+ .text 1
+CallPal_SwpCtxCont:
+ ldq_p $sp, PCB_Q_KSP(v0) // Install new stack pointers
+ ldq_p t10, PCB_Q_USP(v0)
+ mtpr t10, ptUsp
+
+ ldq_p t8, PCB_Q_FEN(a0) // Install new FEN
+ and t8, 1, t8
+ mtpr t8, qemu_fen
+
+ // QEMU does not implement an ASN; skip that.
+
+ ldq_p t10, PCB_Q_PTBR(a0) // Install new page tables
+ mtpr t10, qemu_ptbr
+ mtpr $31, qemu_tbia // Flush TLB
+
+ hw_rei
+ .previous
+
+/*
+ * Write System Value
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New system value
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x31)
+CallPal_WrVal:
+ mtpr a0, ptSysVal
+ hw_rei
+
+/*
+ * Read System Value
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = Returned system value
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0 and t8..t11 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x32)
+CallPal_RdVal:
+ mfpr v0, ptSysVal
+ hw_rei
+
+/*
+ * Translation Buffer Invalidate
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = tbi selector type:
+ *
+ * -2 - Flush all TB entries (tbia)
+ * -1 - Invalidate all TB entries with ASM=0 (tbiap)
+ * 1 - Invalidate ITB entry for va=a1 (tbisi)
+ * 2 - Invalidate DTB entry for va=a1 (tbisd)
+ * 3 - Invalidate both ITB and DTB entry for va=a1 (tbis)
+ *
+ * r17 (a1) = VA for TBISx types
+ *
+ * Qemu does not implement ASNs or split I/D tlbs. Therefore these
+ * collapse to tbia and tbis.
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x33)
+CallPal_Tbi:
+ bge a0, 1f
+
+ mtpr $31, qemu_tbia
+ hw_rei
+
+1: mtpr a1, qemu_tbis
+ hw_rei
+
+/*
+ * Write System Entry Address
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = VA of system entry point
+ * r17 (a1) = System entry point selector
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0..a1 are UNPREDICTABLE
+ * upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x34)
+CallPal_WrEnt:
+ andnot a0, 3, a0 // Clean PC<1:0>
+
+ cmpult a1, 6, t8 // Bound the input
+ cmoveq t8, 7, a1
+
+ br t0, 1f
+1: lda t0, WrEnt_Table-1b(t0)
+ s8addq t0, a1, t0
+ jmp $31, (t0), WrEnt_Table
+
+ .text 1
+WrEnt_Table:
+0: mtpr a0, ptEntInt
+ hw_rei
+1: mtpr a0, ptEntArith
+ hw_rei
+2: mtpr a0, ptEntMM
+ hw_rei
+3: mtpr a0, ptEntIF
+ hw_rei
+4: mtpr a0, ptEntUna
+ hw_rei
+5: mtpr a0, ptEntSys
+ hw_rei
+6: nop
+ hw_rei
+ .previous
+
+/*
+ * Swap Interrupt Priority Level
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New IPL
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = Old IPL
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x35)
+CallPal_SwpIpl:
+ mfpr v0, qemu_ps
+ and a0, PS_M_IPL, a0
+ and v0, PS_M_IPL, v0
+ mtpr a0, qemu_ps
+ hw_rei
+
+/*
+ * Read Processor Status
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = Current PS
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x36)
+CallPal_RdPs:
+ mfpr v0, qemu_ps
+ hw_rei
+
+/*
+ * Write Kernel Global Pointer
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New KGP value
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x37)
+CallPal_WrKgp:
+ mtpr a0, ptKgp
+ hw_rei
+
+/*
+ * Write User Stack Pointer
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New user stack pointer value
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x38)
+CallPal_WrUsp:
+ mtpr a0, ptUsp
+ hw_rei
+
+/*
+ * Write Performance Monitor
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New user stack pointer value
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, t8..t11, and a0 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x39)
+CallPal_WrPerfMon:
+ // Not implemented
+ hw_rei
+/*
+ * Read User Stack Pointer
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = User stack pointer value
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0, and t8..t11 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x3A)
+CallPal_RdUsp:
+ mfpr v0, ptUsp
+ hw_rei
+
+ ORG_CALL_PAL_PRIV(0x3B)
+CallPal_OpcDec3B:
+ br CallPal_OpcDec
+
+/*
+ * Who Am I
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = Current processor number
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0 and t8..t11 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x3C)
+CallPal_Whami:
+ // We do not currently support more cpus
+ mov 0, v0
+ hw_rei
+
+/*
+ * Return From System Call
+ *
+ * INPUT PARAMETERS:
+ *
+ * r30 (sp) = Pointer to the top of the kernel stack
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r29 (gp) = Restored user mode global pointer
+ * r30 (sp) = User stack pointer
+ *
+ * SIDE EFFECTS:
+ *
+ * Registers t0 and t8..t11 are UNPREDICTABLE upon return.
+ */
+ ORG_CALL_PAL_PRIV(0x3D)
+CallPal_RetSys:
+ ldq t9, FRM_Q_PC($sp) // Pop the return address
+ ldq $gp, FRM_Q_GP($sp) // Get the user mode global pointer
+ lda t8, FRM_K_SIZE($sp)
+ mtpr t8, ptKsp
+
+ mov PS_K_USER, t8 // Set new mode to user
+ mtpr t8, qemu_ps
+
+ mfpr $sp, ptUsp // Get the user stack pointer
+
+ andnot t9, 3, t9 // Clean return PC<1:0>
+ hw_ret (t9)
+
+/*
+ * Wait For Interrupt
+ *
+ * FUNCTIONAL DESCRIPTION:
+ *
+ * If possible, wait for the first of either of the following
+ * conditions before returning: any interrupt other than a clock
+ * tick; or the first clock tick after a specified number of clock
+ * ticks have bbeen skipped.
+ *
+ * INPUT PARAMETERS:
+ *
+ * ???
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * ???
+ *
+ * SIDE EFFECTS:
+ *
+ * ???
+ */
+ ORG_CALL_PAL_PRIV(0x3E)
+CallPal_WtInt:
+ hw_rei
+
+/*
+ * Return From Trap, Fault, or Interrupt
+ *
+ * INPUT PARAMETERS:
+ *
+ * r30 (sp) = Pointer to the top of the kernel stack
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * ps <- (sp+00)
+ * pc <- (sp+08)
+ * r29 (gp) <- (sp+16)
+ * r16 (a0) <- (sp+24)
+ * r17 (a1) <- (sp+32)
+ * r18 (a2) <- (sp+40)
+ */
+ ORG_CALL_PAL_PRIV(0x3F)
+CallPal_Rti:
+ mfpr p6, qemu_exc_addr // Save exc_addr for machine check
+
+ ldq p4, FRM_Q_PS($sp) // Get the PS
+ ldq p5, FRM_Q_PC($sp) // Get the return PC
+ ldq $gp, FRM_Q_GP($sp) // Get gp
+ ldq a0, FRM_Q_A0($sp) // Get a0
+
+ ldq a1, FRM_Q_A1(p7) // Get a1
+ ldq a2, FRM_Q_A2(p7) // Get a2
+ lda $sp, FRM_K_SIZE($sp) // Pop the stack
+ bic p5, 3, p5 // Clean return PC<1:0>
+
+ and p4, PS_M_CM, p3
+ bne p3, CallPal_Rti_ToUser
+
+ and p4, PS_M_IPL, p4
+ mtpr p4, qemu_ps
+ hw_ret (p5)
+
+ .text 1
+CallPal_Rti_ToUser:
+ mtpr p4, qemu_ps
+ mtpr $sp, ptKsp
+ mfpr $sp, ptUsp
+ hw_ret (p5)
+ .previous
+
+
+/*
+ * OSF/1 Unprivileged CALL_PAL Entry Points
+ */
+
+#define ORG_CALL_PAL_UNPRIV(X) .org 0x2000+64*(X-0x80)
+
+/*
+ * A helper routine for the unprivaledged kernel entry points, since the
+ * actual stack frame setup code is just a tad too large to fit inline.
+ *
+ * INPUT PARAMETERS:
+ *
+ * p5 = ps
+ * p6 = exc_addr
+ * p7 = return address
+ *
+ * SIDE EFFECTS:
+ *
+ * p0 is clobbered
+ *
+ */
+ .text 1
+CallPal_Stack_Frame:
+ // Test if we're currently in user mode
+ and p5, PS_M_CM, p0
+ bne p0, 0f
+CallPal_Stack_Frame_FromUser:
+ // Switch to kernel mode
+ mtpr $31, qemu_ps
+ mtpr $sp, ptUsp
+ mfpr $sp, ptKsp
+0:
+ // Allocate the stack frame
+ lda $sp, -FRM_K_SIZE($sp)
+ stq p5, FRM_Q_PS($sp)
+ stq p6, FRM_Q_PC($sp)
+ stq $gp, FRM_Q_GP($sp)
+ stq a0, FRM_Q_A0($sp)
+ stq a1, FRM_Q_A1($sp)
+ stq a2, FRM_Q_A2($sp)
+ ret $31, (p7), 0
+ .previous
+
+/*
+ * Breakpoint Trap
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r16 (a0) = Code for bpt (0)
+ * r17 (a1) = UNPREDICTABLE
+ * r18 (a2) = UNPREDICTABLE
+ */
+ ORG_CALL_PAL_UNPRIV(0x80)
+CallPal_Bpt:
+ mfpr p5, qemu_ps
+ mfpr p6, qemu_exc_addr
+ bsr p7, CallPal_Stack_Frame
+
+ mfpr p0, ptEntIF
+ mfpr $gp, ptKgp
+ mov IF_K_BPT, a0
+ hw_ret (p0)
+
+/*
+ * Bugcheck Trap
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r16 (a0) = Code for bugchk (1)
+ * r17 (a1) = UNPREDICTABLE
+ * r18 (a2) = UNPREDICTABLE
+ */
+ ORG_CALL_PAL_UNPRIV(0x81)
+CallPal_BugChk:
+ mfpr p5, qemu_ps
+ mfpr p6, qemu_exc_addr
+ bsr p7, CallPal_Stack_Frame
+
+ mfpr p0, ptEntIF
+ mfpr $gp, ptKgp
+ mov IF_K_BUGCHK, a0
+ hw_ret (p0)
+
+
+ ORG_CALL_PAL_UNPRIV(0x82)
+CallPal_OpcDec82:
+ br CallPal_OpcDec
+
+/*
+ * System Call
+ */
+ ORG_CALL_PAL_UNPRIV(0x83)
+CallPal_CallSys:
+ mfpr p5, qemu_ps
+ mfpr p6, qemu_exc_addr
+
+ and p5, PS_M_CM, p0
+ beq p0, 0f
+
+ bsr p7, CallPal_Stack_Frame_FromUser
+
+ mfpr p0, ptEntSys
+ mfpr $gp, ptKgp
+ hw_ret (p0)
+
+0: subq p6, 4, p6 // Get PC of CALL_PAL insn
+ br MchkOSBugCheck
+
+ ORG_CALL_PAL_UNPRIV(0x84)
+CallPal_OpcDec84:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x85)
+CallPal_OpcDec85:
+ br CallPal_OpcDec
+
+
+/*
+ * I-Stream Memory Barrier
+ *
+ * For QEMU, this is of course a no-op.
+ */
+ ORG_CALL_PAL_UNPRIV(0x86)
+CallPal_Imb:
+ hw_rei
+
+
+ ORG_CALL_PAL_UNPRIV(0x87)
+CallPal_OpcDec87:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x88)
+CallPal_OpcDec88:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x89)
+CallPal_OpcDec89:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x8A)
+CallPal_OpcDec8A:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x8B)
+CallPal_OpcDec8B:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x8C)
+CallPal_OpcDec8C:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x8D)
+CallPal_OpcDec8D:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x8E)
+CallPal_OpcDec8E:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x8F)
+CallPal_OpcDec8F:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x90)
+CallPal_OpcDec90:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x91)
+CallPal_OpcDec91:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x92)
+CallPal_OpcDec92:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x93)
+CallPal_OpcDec93:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x94)
+CallPal_OpcDec94:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x95)
+CallPal_OpcDec95:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x96)
+CallPal_OpcDec96:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x97)
+CallPal_OpcDec97:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x98)
+CallPal_OpcDec98:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x99)
+CallPal_OpcDec99:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x9A)
+CallPal_OpcDec9A:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x9B)
+CallPal_OpcDec9B:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x9C)
+CallPal_OpcDec9C:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0x9D)
+CallPal_OpcDec9D:
+ br CallPal_OpcDec
+
+/*
+ * Read Unique Value
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r0 (v0) = Returned process unique value
+*/
+ ORG_CALL_PAL_UNPRIV(0x9E)
+CallPal_RdUnique:
+ mfpr v0, qemu_unique
+ hw_rei
+
+/*
+ * Write Unique Value
+ *
+ * INPUT PARAMETERS:
+ *
+ * r16 (a0) = New process unique value
+ */
+ ORG_CALL_PAL_UNPRIV(0x9F)
+CallPal_WrUnique:
+ mtpr a0, qemu_unique
+ hw_rei
+
+
+ ORG_CALL_PAL_UNPRIV(0xA0)
+CallPal_OpcDecA0:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA1)
+CallPal_OpcDecA1:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA2)
+CallPal_OpcDecA2:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA3)
+CallPal_OpcDecA3:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA4)
+CallPal_OpcDecA4:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA5)
+CallPal_OpcDecA5:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA6)
+CallPal_OpcDecA6:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA7)
+CallPal_OpcDecA7:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA8)
+CallPal_OpcDecA8:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xA9)
+CallPal_OpcDecA9:
+ br CallPal_OpcDec
+/*
+ * Generate Trap
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * r16 (a0) = Code for gentrap (2)
+ * r17 (a1) = UNPREDICTABLE
+ * r18 (a2) = UNPREDICTABLE
+ */
+ ORG_CALL_PAL_UNPRIV(0xAA)
+CallPal_GenTrap:
+ mfpr p5, qemu_ps
+ mfpr p6, qemu_exc_addr
+ bsr p7, CallPal_Stack_Frame
+
+ mfpr p0, ptEntIF
+ mfpr $gp, ptKgp
+ mov IF_K_GENTRAP, a0
+ hw_ret (p0)
+
+
+ ORG_CALL_PAL_UNPRIV(0xAB)
+CallPal_OpcDecAB:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xAC)
+CallPal_OpcDecAC:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xAD)
+CallPal_OpcDecAD:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xAE)
+CallPal_OpcDecAE:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xAF)
+CallPal_OpcDecAF:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB0)
+CallPal_OpcDecB0:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB1)
+CallPal_OpcDecB1:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB2)
+CallPal_OpcDecB2:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB3)
+CallPal_OpcDecB3:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB4)
+CallPal_OpcDecB4:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB5)
+CallPal_OpcDecB5:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB6)
+CallPal_OpcDecB6:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB7)
+CallPal_OpcDecB7:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB8)
+CallPal_OpcDecB8:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xB9)
+CallPal_OpcDecB9:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xBA)
+CallPal_OpcDecBA:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xBB)
+CallPal_OpcDecBB:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xBC)
+CallPal_OpcDecBC:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xBD)
+CallPal_OpcDecBD:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xBE)
+CallPal_OpcDecBE:
+ br CallPal_OpcDec
+
+ ORG_CALL_PAL_UNPRIV(0xBF)
+CallPal_OpcDec:
+ mfpr p5, qemu_ps
+ mfpr p6, qemu_exc_addr
+ bsr p7, CallPal_Stack_Frame
+
+ mfpr p0, ptEntIF
+ mfpr $gp, ptKgp
+ mov IF_K_OPCDEC, a0
+ hw_ret (p0)
+
+ .org 0x3000
+ .text 1
+/*
+ * PALcode detected processor machine check handler.
+ *
+ * The PALcode-detected machine check handler loads a code
+ * indicating the type of machine check error, loads
+ * the System Control Block (SCB) vector for the
+ * processor machine check service routine, sets the
+ * Machine-Check-In-Progress (MIP) flag in the Machine
+ * Check Error Summary register (MCES), and merges
+ * with the common machine check flow.
+ *
+ * If a second processor machine check error condition
+ * is detected while the MIP flag is set, the processor
+ * is forced into console I/O mode indicating "double
+ * error abort encountered" as the reason for the halt.
+ *
+ * CALLING SEQUENCE:
+ *
+ * Called when an internal processor error is detected
+ * that cannot be successfully corrected by hardware or
+ * PALcode.
+ *
+ * INPUT PARAMETERS:
+ *
+ * r14 (p6) = Exception address
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * ptMchk0 = saved v0
+ * ptMchk1 = saved t0
+ * ptMchk2 = saved t3
+ * ptMchk3 = saved t4
+ * ptMchk4 = saved t5
+ * ptMchk5 = saved exc_addr
+ * ptMisc<47:32> = MCHK code
+ * ptMisc<31:16> = SCB vector
+ * ptMces<MIP> = Set
+ *
+ * SIDE EFFECTS:
+ *
+ * r0 (v0), r1 (t0), and r4..r6 (t3..t5) are saved in
+ * PAL temporaries and are available for use as scratch
+ * registers by the system specific machine check
+ * handler.
+ */
+
+MchkBugCheck:
+ lda p7, MCHK_K_BUGCHECK
+ br 1f
+MchkOSBugCheck:
+ lda p7, MCHK_K_OS_BUGCHECK
+1: sll p7, PT16_V_MCHK, p7 // Move error code into upper longword
+
+ mfpr p4, ptMces // Get and isolate MCES bits
+ zap p4, 0x3c, p4
+ or p4, p7, p4 // Combine MCES and error code
+
+ ldah p7, SCB_Q_PROCMCHK // Combine SCB and MCHK bits
+ or p4, p7, p7
+ or p7, MCES_M_MIP, p7 // Set machine-check-in-progress
+ mtpr p7, ptMces
+
+MchkCommon_SaveRegs:
+ mtpr v0, ptMchk0 // Save temporaries
+ mtpr t0, ptMchk1
+ mtpr t3, ptMchk2
+ mtpr t4, ptMchk3
+ mtpr t5, ptMchk4
+ mtpr p6, ptMchk5 // Save the exception address
+
+ blbs p4, MchkDouble
+ blbs p6, MchkFromPal
+
+/*
+ * Common Machine Check Handler
+ *
+ * INPUT STATE:
+ *
+ * ptMchk0 Saved v0
+ * ptMchk1 Saved t0
+ * ptMchk2 Saved t3
+ * ptMchk3 Saved t4
+ * ptMchk4 Saved t5
+ * ptMchk5 Saved exc_addr
+ * ptMisc<47:32> MCHK code
+ * ptMisc<31:16> SCB vector
+ * ptMces<MIP> Set
+ *
+ * Registers v0, t0, and t3 .. t5 are available for use, in
+ * addition to the shadow registers.
+ */
+
+MchkCommon:
+ mov 0, t4 // Assume non-retryable.
+
+ mfpr t5, ptMisc // Load MCHK code
+ extwl t5, 4, t5
+ andnot t5, 1, t5
+
+/*
+ * Build Machine Check Logout Frame
+ *
+ * This portion of the machine check handler builds a logout frame
+ * in the PAL impure scratch area, builds a stack frame on the kernel
+ * stack (already built if there was an interrupt machine check),
+ * loads the GP with the KGP, loads the machine check entry
+ * code in a0, loads a platform-specific interrupt vector
+ * (typically the same value as the SCB offset) in a1, loads
+ * the kseg address of the logout area in a2, and dispatches
+ * to the kernel interrupt handler pointed to by the entInt
+ * operating system entry point.
+ *
+ * OUTPUT PARAMETERS:
+ *
+ * a0 (r16) = Machine check entry type
+ * a1 (r17) = Platform-specific interrupt vector
+ * a2 (r18) = Pointer to logout area
+ */
+
+.macro STORE_IPR which, offset, base
+ mfpr v0, \which
+ stq_p v0, \offset(\base)
+.endm
+
+MchkLogOut:
+ mfpr p6, ptImpure // Get address of logout frame
+ lda p6, LAF_Q_BASE(p6)
+
+ lda t3, LAF_K_SIZE(t4) // Combine retry flag and frame size
+ stq_p t3, LAF_L_SIZE(p6)
+
+ lda t3, LAF_Q_SYS_BASE
+ sll t3, 32, t3
+ lda t3, LAF_Q_CPU_BASE(t3)
+ stq_p t3, LAF_Q_OFFSET_BASE(p6)
+
+ stq_p t5, LAF_Q_MCHK_CODE(p6)
+
+ // Being virtual, we don't have I/D caches, or cache errors.
+ stq_p $31, LAF_Q_ICPERR(p6)
+ stq_p $31, LAF_Q_DCPERR(p6)
+ stq_p $31, LAF_Q_BC_ADDR(p6)
+ stq_p $31, LAF_Q_BC_STAT(p6)
+
+ mfpr t0, ptMchk1
+ mfpr t3, ptMchk2
+ mfpr t4, ptMchk3
+ mfpr t5, ptMchk4
+ mfpr p7, ptMchk5
+ stq_p p7, LAF_Q_EXC_ADDR(p6)
+
+ stq_p $31, LAF_Q_MM_STAT(p6)
+ stq_p $31, LAF_Q_VA(p6)
+ stq_p $31, LAF_Q_ISR(p6)
+ stq_p $31, LAF_Q_ICSR(p6)
+
+ STORE_IPR qemu_palbr, LAF_Q_PAL_BASE, p6
+
+ stq_p $31, LAF_Q_EXC_MASK(p6)
+ stq_p $31, LAF_Q_EXC_SUM(p6)
+
+ STORE_IPR pt0, LAF_Q_PT+0x00, p6
+ STORE_IPR pt1, LAF_Q_PT+0x08, p6
+ STORE_IPR pt2, LAF_Q_PT+0x10, p6
+ STORE_IPR pt3, LAF_Q_PT+0x18, p6
+ STORE_IPR pt4, LAF_Q_PT+0x20, p6
+ STORE_IPR pt5, LAF_Q_PT+0x28, p6
+ STORE_IPR pt6, LAF_Q_PT+0x30, p6
+ STORE_IPR pt7, LAF_Q_PT+0x38, p6
+ STORE_IPR pt8, LAF_Q_PT+0x40, p6
+ STORE_IPR pt9, LAF_Q_PT+0x48, p6
+ STORE_IPR pt10, LAF_Q_PT+0x50, p6
+ STORE_IPR pt11, LAF_Q_PT+0x58, p6
+ STORE_IPR pt12, LAF_Q_PT+0x60, p6
+ STORE_IPR pt13, LAF_Q_PT+0x68, p6
+ STORE_IPR pt14, LAF_Q_PT+0x70, p6
+ STORE_IPR pt15, LAF_Q_PT+0x78, p6
+ STORE_IPR pt16, LAF_Q_PT+0x80, p6
+ STORE_IPR pt17, LAF_Q_PT+0x88, p6
+ STORE_IPR pt18, LAF_Q_PT+0x90, p6
+ STORE_IPR pt19, LAF_Q_PT+0x98, p6
+ STORE_IPR pt20, LAF_Q_PT+0xa0, p6
+ STORE_IPR pt21, LAF_Q_PT+0xa8, p6
+ STORE_IPR pt22, LAF_Q_PT+0xb0, p6
+ STORE_IPR pt23, LAF_Q_PT+0xb8, p6
+
+ // bsr v0, Sys_MchkLogOut
+
+ mfpr v0, ptMchk0
+
+ // Build the stack frame on the kernel stack and post the interrupt
+ mfpr p7, ptMisc
+ extwl p7, 4, p7
+ mov p6, p4 // Stash pointer to logout
+ lda a1, SCB_Q_SYSMCHK
+ blbs p7, 0f // Check if stack frame already built
+
+ mfpr p5, qemu_ps
+ mfpr p6, ptMchk5 // Reload exc_addr for double mchk
+
+ STACK_FRAME p5, p6, p7
+
+ mov IPL_K_MCHK, p5 // Raise IPL
+ mtpr p5, qemu_ps
+
+ mfpr a1, ptMisc // Isolate SCB vector
+ extwl a1, 2, a1
+
+0: mfpr p7, ptEntInt
+ lda a0, INT_K_MCHK
+
+ lda a2, -1 // Load kseg offset
+ srl a2, VA_S_SIZE-1, a2
+ sll a2, VA_S_SIZE-1, a2
+ addq a2, p4, a2 // Pass ptr to logout area
+
+ mfpr $gp, ptKgp
+ hw_ret (p7)
+
+
+MchkDouble:
+ bsr p7, UpdatePCB
+ lda v0, HLT_K_DBL_MCHK
+ br Sys_EnterConsole
+
+MchkFromPal:
+ bsr p7, UpdatePCB
+ lda v0, HLT_K_MCHK_FROM_PAL
+ br Sys_EnterConsole
+
+MchkKspInvalid:
+ bsr p7, UpdatePCB
+ lda v0, HLT_K_KSP_INVAL
+ br Sys_EnterConsole
+
+/*
+ * Update the current PCB with new SP and CC info.
+ *
+ * INPUT PARAMETERS:
+ *
+ * p7 = return linkage
+ */
+
+UpdatePCB:
+ rpcc p5
+ mfpr p4, ptPcbb
+
+ mfpr p3, qemu_ps // Check current mode
+ and p3, PS_M_CM, p3
+ beq p3, 1f
+
+ mtpr $sp, ptUsp // Save user stack pointer
+ stq_p $sp, PCB_Q_USP(p4)
+ br 2f
+
+1: mtpr $sp, ptKsp // Save kernel stack pointer
+ stq_p $sp, PCB_Q_KSP(p4)
+
+2: srl p5, 32, p3 // Merge for new time
+ addl p5, p3, p3
+ stl_p p3, PCB_L_PCC(p4) // Store new time
+
+ ret $31, (p7), 0