diff options
author | Richard Henderson <rth@twiddle.net> | 2011-04-06 16:02:02 -0700 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2011-04-06 16:02:02 -0700 |
commit | e00c70db6ec09b5015ba5602a781d282134d3fcd (patch) | |
tree | 8cf83340683dbb2ac8116f7c2921d4f693ebb1f5 | |
download | qemu-palcode-e00c70db6ec09b5015ba5602a781d282134d3fcd.zip qemu-palcode-e00c70db6ec09b5015ba5602a781d282134d3fcd.tar.gz qemu-palcode-e00c70db6ec09b5015ba5602a781d282134d3fcd.tar.bz2 |
TEMP
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | impure.h | 339 | ||||
-rw-r--r-- | osf.h | 208 | ||||
-rw-r--r-- | pal.S | 1774 |
4 files changed, 2327 insertions, 0 deletions
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 @@ -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 + @@ -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 |