historical/m0-applesillicon.git/xnu-qemu-arm64-5.1.0/roms/qemu-palcode/pal.S
2024-01-16 11:20:27 -06:00

1945 lines
36 KiB
ArmAsm
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* QEMU Emulation PALcode.
Copyright (C) 2011 Richard Henderson
This file is part of QEMU PALcode.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the text
of the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not see
<http://www.gnu.org/licenses/>. */
.set noat
.set nomacro
.text
#include "pal.h"
#include "osf.h"
#include SYSTEM_H
/*
* Create a standard kernel entry stack frame.
*/
.macro STACK_FRAME save_ps, save_pc, temp, do_ps
// Test if we're currently in user mode
and \save_ps, PS_M_CM, \temp
beq \temp, 0f
// Switch to kernel mode
.ifne \do_ps
mtpr $31, qemu_ps
.endif
mtpr $sp, qemu_usp
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
/*
* Allocate a 1 page stack for use by the console.
*/
#define STACK_SIZE 8192
/*
* QEMU emulator "hardware" entry points.
*/
/*
* Reset
*
* INPUT PARAMETERS:
*
* trap_arg0 = Memory size
* trap_arg1 = Kernel entry (if loaded)
*/
.org 0x0000
.globl __start
__start:
// Initialize GP.
br $gp, .+4
ldah $gp, 0($gp) !gpdisp!1
lda $gp, 0($gp) !gpdisp!1
mtpr $gp, ptPgp
// Disable interrupts; kernel mode
lda t0, IPL_K_HIGH
mtpr t0, qemu_ps
// Initialize Stack.
SYS_WHAMI a0
lda t0, STACK_SIZE
addq a0, 1, t1
mull t0, t1, t0
ldah t1, stack($gp) !gprelhigh
lda t1, stack(t1) !gprellow
addq t0, t1, $sp
// Do any necessary system setup required for PALmode,
// e.g. setting up ptSys[01].
bsr $26, Sys_Setup
// Non-boot CPUs can go wait now.
bne a0, 1f
// Load boot arguments
mfpr a0, qemu_trap_arg0 // memsize
mfpr a1, qemu_trap_arg1 // kernel entry
mfpr a2, qemu_trap_arg2 // ncpus
// Continue in do_start, outside PALmode.
ldah $27, do_start($gp) !gprelhigh
lda $27, do_start($27) !gprellow
hw_ret ($27)
1: ldah $27, do_start_wait($gp) !gprelhigh
lda $27, do_start_wait($27) !gprellow
hw_ret ($27)
ENDFN __start
/*
* Machine Check
*
* INPUT PARAMETERS:
*
* trap_arg0 =
* trap_arg1 =
* trap_arg2 =
*/
.org 0x0080
Pal_Mchk:
mfpr p6, qemu_exc_addr // Check for palcode mchk
blbs p6, MchkFromPal
mfpr p0, ptMces // Check for double mchk
blbs p0, MchkDouble
// Since this is QEMU, the only MCHK we raise spontaneously
// is for access to non-existent memory.
//
// ??? With MemTxResult we could perhaps distinguish
// between MEMTX_DECODE_ERROR (no memory) and
// MEMTX_ERROR (device error), but it's not clear whether
// "device error" corresponds to "PCI target abort" or whatnot.
// However the main reason to handle mchk at all is to allow
// the guest OS to probe for devices, which is just "no memory".
lda t0, MCHK_K_SYS_NOMEM
br MchkLogOut
ENDFN Pal_Mchk
/*
* Interprocessor Interrupt
*
* INPUT PARAMETERS:
*
* trap_arg0 =
* trap_arg1 =
* trap_arg2 =
*
* The interprocessor interrupt is special, in that PALcode is supposed
* to clear the interupt and not wait for the OS to do it.
*/
.org 0x0100
Pal_Smp_Interrupt:
mfpr p6, qemu_exc_addr
SYS_ACK_SMP p0, p1, p2
mfpr p0, qemu_ps
STACK_FRAME p0, p6, p2, 0
mov IPL_K_IP, p0 // Raise IPL
mtpr p0, qemu_ps
mfpr p6, ptEntInt
mfpr $gp, ptKgp
lda a0, INT_K_IP
lda a1, 0
lda a2, 0
hw_ret (p6)
ENDFN Pal_Smp_Interrupt
/*
* Clock Interrupt
*
* INPUT PARAMETERS:
*
* trap_arg0 =
* trap_arg1 =
* trap_arg2 =
*
* The clock interrupt is special, in that PALcode is supposed
* to clear the interupt and not wait for the OS to do it.
*/
.org 0x0180
Pal_Clk_Interrupt:
mfpr p6, qemu_exc_addr
SYS_ACK_CLK p0, p1, p2
mfpr p0, qemu_ps
STACK_FRAME p0, p6, p2, 0
mov IPL_K_CLK, p0 // Raise IPL
mtpr p0, qemu_ps
mfpr p6, ptEntInt
mfpr $gp, ptKgp
lda a0, INT_K_CLK
lda a1, 0
lda a2, 0
9: hw_ret (p6)
ENDFN Pal_Clk_Interrupt
/*
* Device Interrupt
*
* INPUT PARAMETERS:
*
* trap_arg0 =
* trap_arg1 =
* trap_arg2 =
*/
.org 0x0200
Pal_Dev_Interrupt:
mfpr p6, qemu_exc_addr
mfpr p0, qemu_ps
STACK_FRAME p0, p6, p2, 0
mov IPL_K_DEV1, p0 // Raise IPL
mtpr p0, qemu_ps
bsr p7, Sys_Dev_Vector
mfpr p7, ptEntInt
mfpr $gp, ptKgp
lda a0, INT_K_DEV
lda a2, 0
hw_ret (p7)
ENDFN Pal_Dev_Interrupt
/*
* 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 0x0280
Pal_MMFault:
mfpr p0, qemu_ps
mfpr p6, qemu_exc_addr
blbs p6, MchkBugCheck
STACK_FRAME p0, p6, p2, 1
mfpr p0, ptEntMM
mfpr $gp, ptKgp
mfpr a0, qemu_trap_arg0
mfpr a1, qemu_trap_arg1
mfpr a2, qemu_trap_arg2
hw_ret (p0)
ENDFN Pal_MMFault
/*
* Unaligned Data
*
* INPUT PARAMETERS:
*
* trap_arg0 = faulting address
* trap_arg1 = opcode of faulting insn
* trap_arg2 = src/dst register number
*/
.org 0x0300
Pal_Unalign:
mfpr p0, qemu_ps
mfpr p6, qemu_exc_addr
blbs p6, MchkBugCheck
addq p6, 4, p6 // increment past the faulting insn
STACK_FRAME p0, p1, p2, 1
mfpr p0, ptEntUna
mfpr $gp, ptKgp
mfpr a0, qemu_trap_arg0
mfpr a1, qemu_trap_arg1
mfpr a2, qemu_trap_arg2
hw_ret (p0)
ENDFN Pal_Unalign
/*
* 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 0x0380
Pal_OpcDec:
mfpr p0, qemu_ps
mfpr p6, qemu_exc_addr
blbs p6, MchkBugCheck
STACK_FRAME p0, p6, p2, 1
mfpr p0, ptEntIF
mfpr $gp, ptKgp
mov IF_K_OPCDEC, a0
hw_ret (p0)
ENDFN Pal_OpcDec
/*
* Arithmetic Trap
*
* INPUT PARAMETERS:
*
* trap_arg0 = exception type
* trap_arg1 = register modification mask
* trap_arg2 = UNDEFINED
*/
.org 0x0400
Pal_Arith:
mfpr p0, qemu_ps
mfpr p6, qemu_exc_addr
blbs p6, MchkBugCheck
STACK_FRAME p0, p6, p2, 1
mfpr p0, ptEntArith
mfpr $gp, ptKgp
mfpr a0, qemu_trap_arg0
mfpr a1, qemu_trap_arg1
hw_ret (p0)
ENDFN Pal_Arith
/*
* 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 0x0480
Pal_Fen:
mfpr p0, qemu_ps
mfpr p6, qemu_exc_addr
blbs p6, MchkBugCheck
STACK_FRAME p0, p6, p2, 1
mfpr p0, ptEntIF
mfpr $gp, ptKgp
mov IF_K_FEN, a0
hw_ret (p0)
ENDFN Pal_Fen
/*
* 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 // FIXME store this somewhere.
mtpr $31, qemu_halt
br Sys_EnterConsole
ENDFN CallPal_Halt
/*
* Cache Flush
*
* For QEMU, this is of course a no-op.
*/
ORG_CALL_PAL_PRIV(0x01)
CallPal_Cflush:
hw_rei
ENDFN CallPal_Cflush
/*
* Drain Aborts
*
* For QEMU, this is of course a no-op.
*/
ORG_CALL_PAL_PRIV(0x02)
CallPal_Draina:
hw_rei
ENDFN CallPal_Draina
/*
* Delay for N nanoseconds.
*
* This is unique to QEMU, used only within PALcode itself.
*/
ORG_CALL_PAL_PRIV(0x03)
CallPal_Ndelay:
mfpr p0, qemu_vmtime
addq p0, a0, p0
mtpr p0, qemu_alarm
mtpr $31, qemu_wait
SYS_ACK_CLK p2, p3, p4
mfpr v0, qemu_vmtime
subq p0, v0, v0
hw_rei
ENDFN CallPal_Ndelay
ORG_CALL_PAL_PRIV(0x04)
CallPal_OpcDec04:
br CallPal_OpcDec
ENDFN CallPal_OpcDec04
ORG_CALL_PAL_PRIV(0x05)
CallPal_OpcDec05:
br CallPal_OpcDec
ENDFN CallPal_OpcDec05
ORG_CALL_PAL_PRIV(0x06)
CallPal_OpcDec06:
br CallPal_OpcDec
ENDFN CallPal_OpcDec06
ORG_CALL_PAL_PRIV(0x07)
CallPal_OpcDec07:
br CallPal_OpcDec
ENDFN CallPal_OpcDec07
ORG_CALL_PAL_PRIV(0x08)
CallPal_OpcDec08:
br CallPal_OpcDec
ENDFN CallPal_OpcDec08
/*
* Console Service
*
* INPUT PARAMETERS:
*
* r16 (a0) = Option selector
* r17..r21 (a1..a5) = Implementation specific entry parameters
*
* SIDE EFFECTS:
*
* Registers a0..a5, and v0 are UNPREDICTABLE upon return.
*/
ORG_CALL_PAL_PRIV(0x09)
CallPal_Cserve:
// Most of the entries are densely clustered around 0.
mov 0, v0
cmpule a0, 7, p0
cmovne p0, a0, v0
br p0, 1f
1: lda p0, Cserve_Table-1b(p0)
s8addq v0, p0, p0
jmp $31, (p0), 0
ENDFN CallPal_Cserve
.text 1
.align 3
/* Note that the entries in the following table are all 2 insns.
The first entry is unused, and is also where all out-of-range
commands are vectored. */
Cserve_Table:
br CallPal_Cserve_Cont
nop
Cserve_Ldqp:
ldq_p v0, 0(a1)
hw_rei
ENDFN Cserve_Ldqp
Cserve_Stqp:
stq_p a2, 0(a1)
hw_rei
ENDFN Cserve_Stqp
Cserve_Get_Wall_Time:
mfpr v0, qemu_walltime
hw_rei
ENDFN Cserve_Get_Wall_Time
Cserve_Get_Alarm:
mfpr v0, qemu_alarm
hw_rei
ENDFN Cserve_Get_Alarm
Cserve_Set_Alarm_Rel:
// Cheating here: create the absolute time and fall thru.
mfpr p0, qemu_vmtime
addq p0, a1, a1
ENDFN Cserve_Set_Alarm_Rel
Cserve_Set_Alarm_Abs:
mtpr a1, qemu_alarm
hw_rei
ENDFN Cserve_Set_Alarm_Abs
Cserve_Get_VM_Time:
mfpr v0, qemu_vmtime
hw_rei
ENDFN Cserve_Get_VM_Time
CallPal_Cserve_Cont:
// ??? For SRM compatibility and their use within Linux, use 52/53
// for these. Anyone know what other "standard" SRM Cserve entry
// points are? Certainly we don't want to be compatible with MILO,
// which puts the selector at A2.
cmpeq a0, 52, v0
bne v0, Cserve_Ena
cmpeq a0, 53, v0
bne v0, Cserve_Dis
hw_rei
ENDFN CallPal_Cserve_Cont
.previous
/*
* 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
*
* r26 (ra) = r27 (pv) = New PC
* Note that this is non-architected, but is relied on by
* the usage of SwpPal within our own console code in order
* to simplify its use within C code.
*
*/
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
ENDFN CallPal_SwpPal
.text 1
CallPal_SwpPal_Cont:
rpcc p0
mtpr a2, ptPcbb
mtpr a3, qemu_vptptr
ldq_p $sp, PCB_Q_KSP(a2)
ldq_p t0, PCB_Q_USP(a2)
ldq_p t1, PCB_Q_PTBR(a2)
ldl_p t2, PCB_L_PCC(a2)
ldq_p t3, PCB_Q_UNIQUE(a2)
ldq_p t4, PCB_Q_FEN(a2)
mtpr t0, qemu_usp
sll t1, VA_S_OFF, t1
mtpr t1, qemu_ptbr
subl t2, p0, t2
mtpr t2, qemu_pcc_ofs
mtpr t3, qemu_unique
and t4, 1, t4
mtpr t4, qemu_fen
mtpr $31, qemu_tbia // Flush TLB for new PTBR
mov a1, $26
mov a1, $27
hw_ret (a1)
ENDFN CallPal_SwpPal_Cont
.previous
ORG_CALL_PAL_PRIV(0x0B)
CallPal_OpcDec0B:
br CallPal_OpcDec
ENDFN CallPal_OpcDec0B
ORG_CALL_PAL_PRIV(0x0C)
CallPal_OpcDec0C:
br CallPal_OpcDec
ENDFN CallPal_OpcDec0C
/*
* Write Interprocessor Interrupt Request
*
* INPUT PARAMETERS:
*
* r16 (a0) = target processor number
*
* OUTPUT PARAMETERS:
*
* SIDE EFFECTS:
*
*/
ORG_CALL_PAL_PRIV(0x0D)
CallPal_WrIpir:
// Save a copy of the return address in case of machine check.
mfpr p6, qemu_exc_addr
SYS_WRIPIR a0, p0, p1, p2
hw_rei
ENDFN CallPal_WrIpir
ORG_CALL_PAL_PRIV(0x0E)
CallPal_OpcDec0E:
br CallPal_OpcDec
ENDFN CallPal_OpcDec0E
ORG_CALL_PAL_PRIV(0x0F)
CallPal_OpcDec0F:
br CallPal_OpcDec
ENDFN CallPal_OpcDec0F
/*
* 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
ENDFN CallPal_RdMces
/*
* 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
ENDFN CallPal_WrMces
ORG_CALL_PAL_PRIV(0x12)
CallPal_OpcDec12:
br CallPal_OpcDec
ENDFN CallPal_OpcDec12
ORG_CALL_PAL_PRIV(0x13)
CallPal_OpcDec13:
br CallPal_OpcDec
ENDFN CallPal_OpcDec13
ORG_CALL_PAL_PRIV(0x14)
CallPal_OpcDec14:
br CallPal_OpcDec
ENDFN CallPal_OpcDec14
ORG_CALL_PAL_PRIV(0x15)
CallPal_OpcDec15:
br CallPal_OpcDec
ENDFN CallPal_OpcDec15
ORG_CALL_PAL_PRIV(0x16)
CallPal_OpcDec16:
br CallPal_OpcDec
ENDFN CallPal_OpcDec16
ORG_CALL_PAL_PRIV(0x17)
CallPal_OpcDec17:
br CallPal_OpcDec
ENDFN CallPal_OpcDec17
ORG_CALL_PAL_PRIV(0x18)
CallPal_OpcDec18:
br CallPal_OpcDec
ENDFN CallPal_OpcDec18
ORG_CALL_PAL_PRIV(0x19)
CallPal_OpcDec19:
br CallPal_OpcDec
ENDFN CallPal_OpcDec19
ORG_CALL_PAL_PRIV(0x1A)
CallPal_OpcDec1A:
br CallPal_OpcDec
ENDFN CallPal_OpcDec1A
ORG_CALL_PAL_PRIV(0x1B)
CallPal_OpcDec1B:
br CallPal_OpcDec
ENDFN CallPal_OpcDec1B
ORG_CALL_PAL_PRIV(0x1C)
CallPal_OpcDec1C:
br CallPal_OpcDec
ENDFN CallPal_OpcDec1C
ORG_CALL_PAL_PRIV(0x1D)
CallPal_OpcDec1D:
br CallPal_OpcDec
ENDFN CallPal_OpcDec1D
ORG_CALL_PAL_PRIV(0x1E)
CallPal_OpcDec1E:
br CallPal_OpcDec
ENDFN CallPal_OpcDec1E
ORG_CALL_PAL_PRIV(0x1F)
CallPal_OpcDec1F:
br CallPal_OpcDec
ENDFN CallPal_OpcDec1F
ORG_CALL_PAL_PRIV(0x20)
CallPal_OpcDec20:
br CallPal_OpcDec
ENDFN CallPal_OpcDec20
ORG_CALL_PAL_PRIV(0x21)
CallPal_OpcDec21:
br CallPal_OpcDec
ENDFN CallPal_OpcDec21
ORG_CALL_PAL_PRIV(0x22)
CallPal_OpcDec22:
br CallPal_OpcDec
ENDFN CallPal_OpcDec22
ORG_CALL_PAL_PRIV(0x23)
CallPal_OpcDec23:
br CallPal_OpcDec
ENDFN CallPal_OpcDec23
ORG_CALL_PAL_PRIV(0x24)
CallPal_OpcDec24:
br CallPal_OpcDec
ENDFN CallPal_OpcDec24
ORG_CALL_PAL_PRIV(0x25)
CallPal_OpcDec25:
br CallPal_OpcDec
ENDFN CallPal_OpcDec25
ORG_CALL_PAL_PRIV(0x26)
CallPal_OpcDec26:
br CallPal_OpcDec
ENDFN CallPal_OpcDec26
ORG_CALL_PAL_PRIV(0x27)
CallPal_OpcDec27:
br CallPal_OpcDec
ENDFN CallPal_OpcDec27
ORG_CALL_PAL_PRIV(0x28)
CallPal_OpcDec28:
br CallPal_OpcDec
ENDFN CallPal_OpcDec28
ORG_CALL_PAL_PRIV(0x29)
CallPal_OpcDec29:
br CallPal_OpcDec
ENDFN CallPal_OpcDec29
ORG_CALL_PAL_PRIV(0x2A)
CallPal_OpcDec2A:
br CallPal_OpcDec
ENDFN CallPal_OpcDec2A
/*
* 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
ENDFN CallPal_WrFen
ORG_CALL_PAL_PRIV(0x2C)
CallPal_OpcDec2C:
br CallPal_OpcDec
ENDFN CallPal_OpcDec2C
/*
* 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
ENDFN CallPal_WrVptPtr
ORG_CALL_PAL_PRIV(0x2E)
CallPal_OpcDec2E:
br CallPal_OpcDec
ENDFN CallPal_OpcDec2E
ORG_CALL_PAL_PRIV(0x2F)
CallPal_OpcDec2F:
br CallPal_OpcDec
ENDFN CallPal_OpcDec2F
/*
* 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, qemu_usp // Save old user stack pointer
stq_p t10, PCB_Q_USP(v0)
br CallPal_SwpCtx_Cont
ENDFN CallPal_SwpCtx
.text 1
CallPal_SwpCtx_Cont:
ldq_p $sp, PCB_Q_KSP(a0) // Install new stack pointers
ldq_p t10, PCB_Q_USP(a0)
mtpr t10, qemu_usp
mfpr t10, qemu_unique // Save old unique value
stq_p t10, PCB_Q_UNIQUE(v0)
ldq_p t10, PCB_Q_UNIQUE(a0) // Install new unique value
mtpr t10, qemu_unique
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
sll t10, VA_S_OFF, t10
mtpr t10, qemu_ptbr
mtpr $31, qemu_tbia // Flush TLB, since we don't do ASNs
hw_rei
ENDFN CallPal_SwpCtx_Cont
.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, qemu_sysval
hw_rei
ENDFN CallPal_WrVal
/*
* 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, qemu_sysval
hw_rei
ENDFN CallPal_RdVal
/*
* 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
ENDFN CallPal_Tbi
/*
* 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, 6, a1
br t0, 1f
1: lda t0, WrEnt_Table-1b(t0)
s8addq a1, t0, t0
jmp $31, (t0), 0
ENDFN CallPal_WrEnt
.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
ENDFN WrEnt_Table
.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
ENDFN CallPal_SwpIpl
/*
* 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
ENDFN CallPal_RdPs
/*
* 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
ENDFN CallPal_WrKgp
/*
* 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, qemu_usp
hw_rei
ENDFN CallPal_WrUsp
/*
* 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
ENDFN CallPal_WrPerfMon
/*
* 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, qemu_usp
hw_rei
ENDFN CallPal_RdUsp
ORG_CALL_PAL_PRIV(0x3B)
CallPal_OpcDec3B:
br CallPal_OpcDec
ENDFN CallPal_OpcDec3B
/*
* 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:
SYS_WHAMI v0
hw_rei
ENDFN CallPal_Whami
/*
* 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, qemu_usp // Get the user stack pointer
andnot t9, 3, t9 // Clean return PC<1:0>
hw_ret (t9)
ENDFN CallPal_RetSys
/*
* 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:
*
* r16 (a0) = Maximum number of clock ticks to skip
*
* OUTPUT PARAMETERS:
*
* r0 (v0) = Number of clock ticks actually skipped.
*/
ORG_CALL_PAL_PRIV(0x3E)
CallPal_WtInt:
mtpr $31, qemu_wait
mov 0, v0
hw_rei
ENDFN CallPal_WtInt
/*
* 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)
.globl CallPal_Rti
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($sp) // Get a1
ldq a2, FRM_Q_A2($sp) // Get a2
lda $sp, FRM_K_SIZE($sp) // Pop the stack
andnot 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)
ENDFN CallPal_Rti
.text 1
CallPal_Rti_ToUser:
mtpr p3, qemu_ps
mtpr $sp, ptKsp
mfpr $sp, qemu_usp
hw_ret (p5)
ENDFN CallPal_Rti_ToUser
.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
beq p0, 0f
CallPal_Stack_Frame_FromUser:
// Switch to kernel mode
mtpr $31, qemu_ps
mtpr $sp, qemu_usp
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
ENDFN CallPal_Stack_Frame
.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)
ENDFN CallPal_Bpt
/*
* 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)
ENDFN CallPal_BugChk
ORG_CALL_PAL_UNPRIV(0x82)
CallPal_OpcDec82:
br CallPal_OpcDec
ENDFN CallPal_OpcDec82
/*
* 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
lda p0, MCHK_K_OS_BUGCHECK
br MchkLogOut
ENDFN CallPal_CallSys
ORG_CALL_PAL_UNPRIV(0x84)
CallPal_OpcDec84:
br CallPal_OpcDec
ENDFN CallPal_OpcDec84
ORG_CALL_PAL_UNPRIV(0x85)
CallPal_OpcDec85:
br CallPal_OpcDec
ENDFN CallPal_OpcDec85
/*
* I-Stream Memory Barrier
*
* For QEMU, this is of course a no-op.
*/
ORG_CALL_PAL_UNPRIV(0x86)
CallPal_Imb:
mb
hw_rei
ENDFN CallPal_Imb
ORG_CALL_PAL_UNPRIV(0x87)
CallPal_OpcDec87:
br CallPal_OpcDec
ENDFN CallPal_OpcDec87
ORG_CALL_PAL_UNPRIV(0x88)
CallPal_OpcDec88:
br CallPal_OpcDec
ENDFN CallPal_OpcDec88
ORG_CALL_PAL_UNPRIV(0x89)
CallPal_OpcDec89:
br CallPal_OpcDec
ENDFN CallPal_OpcDec89
ORG_CALL_PAL_UNPRIV(0x8A)
CallPal_OpcDec8A:
br CallPal_OpcDec
ENDFN CallPal_OpcDec8A
ORG_CALL_PAL_UNPRIV(0x8B)
CallPal_OpcDec8B:
br CallPal_OpcDec
ENDFN CallPal_OpcDec8B
ORG_CALL_PAL_UNPRIV(0x8C)
CallPal_OpcDec8C:
br CallPal_OpcDec
ENDFN CallPal_OpcDec8C
ORG_CALL_PAL_UNPRIV(0x8D)
CallPal_OpcDec8D:
br CallPal_OpcDec
ENDFN CallPal_OpcDec8D
ORG_CALL_PAL_UNPRIV(0x8E)
CallPal_OpcDec8E:
br CallPal_OpcDec
ENDFN CallPal_OpcDec8E
ORG_CALL_PAL_UNPRIV(0x8F)
CallPal_OpcDec8F:
br CallPal_OpcDec
ENDFN CallPal_OpcDec8F
ORG_CALL_PAL_UNPRIV(0x90)
CallPal_OpcDec90:
br CallPal_OpcDec
ENDFN CallPal_OpcDec90
ORG_CALL_PAL_UNPRIV(0x91)
CallPal_OpcDec91:
br CallPal_OpcDec
ENDFN CallPal_OpcDec91
ORG_CALL_PAL_UNPRIV(0x92)
CallPal_OpcDec92:
br CallPal_OpcDec
ENDFN CallPal_OpcDec92
ORG_CALL_PAL_UNPRIV(0x93)
CallPal_OpcDec93:
br CallPal_OpcDec
ENDFN CallPal_OpcDec93
ORG_CALL_PAL_UNPRIV(0x94)
CallPal_OpcDec94:
br CallPal_OpcDec
ENDFN CallPal_OpcDec94
ORG_CALL_PAL_UNPRIV(0x95)
CallPal_OpcDec95:
br CallPal_OpcDec
ENDFN CallPal_OpcDec95
ORG_CALL_PAL_UNPRIV(0x96)
CallPal_OpcDec96:
br CallPal_OpcDec
ENDFN CallPal_OpcDec96
ORG_CALL_PAL_UNPRIV(0x97)
CallPal_OpcDec97:
br CallPal_OpcDec
ENDFN CallPal_OpcDec97
ORG_CALL_PAL_UNPRIV(0x98)
CallPal_OpcDec98:
br CallPal_OpcDec
ENDFN CallPal_OpcDec98
ORG_CALL_PAL_UNPRIV(0x99)
CallPal_OpcDec99:
br CallPal_OpcDec
ENDFN CallPal_OpcDec99
ORG_CALL_PAL_UNPRIV(0x9A)
CallPal_OpcDec9A:
br CallPal_OpcDec
ENDFN CallPal_OpcDec9A
ORG_CALL_PAL_UNPRIV(0x9B)
CallPal_OpcDec9B:
br CallPal_OpcDec
ENDFN CallPal_OpcDec9B
ORG_CALL_PAL_UNPRIV(0x9C)
CallPal_OpcDec9C:
br CallPal_OpcDec
ENDFN CallPal_OpcDec9C
ORG_CALL_PAL_UNPRIV(0x9D)
CallPal_OpcDec9D:
br CallPal_OpcDec
ENDFN CallPal_OpcDec9D
/*
* Read Unique Value
*
* OUTPUT PARAMETERS:
*
* r0 (v0) = Returned process unique value
*/
ORG_CALL_PAL_UNPRIV(0x9E)
CallPal_RdUnique:
mfpr v0, qemu_unique
hw_rei
ENDFN CallPal_RdUnique
/*
* Write Unique Value
*
* INPUT PARAMETERS:
*
* r16 (a0) = New process unique value
*/
ORG_CALL_PAL_UNPRIV(0x9F)
CallPal_WrUnique:
mtpr a0, qemu_unique
hw_rei
ENDFN CallPal_WrUnique
ORG_CALL_PAL_UNPRIV(0xA0)
CallPal_OpcDecA0:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA0
ORG_CALL_PAL_UNPRIV(0xA1)
CallPal_OpcDecA1:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA1
ORG_CALL_PAL_UNPRIV(0xA2)
CallPal_OpcDecA2:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA2
ORG_CALL_PAL_UNPRIV(0xA3)
CallPal_OpcDecA3:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA3
ORG_CALL_PAL_UNPRIV(0xA4)
CallPal_OpcDecA4:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA4
ORG_CALL_PAL_UNPRIV(0xA5)
CallPal_OpcDecA5:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA5
ORG_CALL_PAL_UNPRIV(0xA6)
CallPal_OpcDecA6:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA6
ORG_CALL_PAL_UNPRIV(0xA7)
CallPal_OpcDecA7:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA7
ORG_CALL_PAL_UNPRIV(0xA8)
CallPal_OpcDecA8:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA8
ORG_CALL_PAL_UNPRIV(0xA9)
CallPal_OpcDecA9:
br CallPal_OpcDec
ENDFN CallPal_OpcDecA9
/*
* 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)
ENDFN CallPal_GenTrap
ORG_CALL_PAL_UNPRIV(0xAB)
CallPal_OpcDecAB:
br CallPal_OpcDec
ENDFN CallPal_OpcDecAB
ORG_CALL_PAL_UNPRIV(0xAC)
CallPal_OpcDecAC:
br CallPal_OpcDec
ENDFN CallPal_OpcDecAC
ORG_CALL_PAL_UNPRIV(0xAD)
CallPal_OpcDecAD:
br CallPal_OpcDec
ENDFN CallPal_OpcDecAD
ORG_CALL_PAL_UNPRIV(0xAE)
CallPal_OpcDecAE:
br CallPal_OpcDec
ENDFN CallPal_OpcDecAE
ORG_CALL_PAL_UNPRIV(0xAF)
CallPal_OpcDecAF:
br CallPal_OpcDec
ENDFN CallPal_OpcDecAF
ORG_CALL_PAL_UNPRIV(0xB0)
CallPal_OpcDecB0:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB0
ORG_CALL_PAL_UNPRIV(0xB1)
CallPal_OpcDecB1:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB1
ORG_CALL_PAL_UNPRIV(0xB2)
CallPal_OpcDecB2:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB2
ORG_CALL_PAL_UNPRIV(0xB3)
CallPal_OpcDecB3:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB3
ORG_CALL_PAL_UNPRIV(0xB4)
CallPal_OpcDecB4:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB4
ORG_CALL_PAL_UNPRIV(0xB5)
CallPal_OpcDecB5:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB5
ORG_CALL_PAL_UNPRIV(0xB6)
CallPal_OpcDecB6:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB6
ORG_CALL_PAL_UNPRIV(0xB7)
CallPal_OpcDecB7:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB7
ORG_CALL_PAL_UNPRIV(0xB8)
CallPal_OpcDecB8:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB8
ORG_CALL_PAL_UNPRIV(0xB9)
CallPal_OpcDecB9:
br CallPal_OpcDec
ENDFN CallPal_OpcDecB9
ORG_CALL_PAL_UNPRIV(0xBA)
CallPal_OpcDecBA:
br CallPal_OpcDec
ENDFN CallPal_OpcDecBA
ORG_CALL_PAL_UNPRIV(0xBB)
CallPal_OpcDecBB:
br CallPal_OpcDec
ENDFN CallPal_OpcDecBB
ORG_CALL_PAL_UNPRIV(0xBC)
CallPal_OpcDecBC:
br CallPal_OpcDec
ENDFN CallPal_OpcDecBC
ORG_CALL_PAL_UNPRIV(0xBD)
CallPal_OpcDecBD:
br CallPal_OpcDec
ENDFN CallPal_OpcDecBD
ORG_CALL_PAL_UNPRIV(0xBE)
CallPal_OpcDecBE:
br CallPal_OpcDec
ENDFN CallPal_OpcDecBE
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)
ENDFN CallPal_OpcDec
.org 0x3000
.text 1
/*
* 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.
*
* INPUT PARAMETERS:
*
* r8 (p0) = Machine check reason
* r14 (p6) = Exception address
*
* OUTPUT PARAMETERS:
*
* a0 (r16) = Machine check entry type
* a1 (r17) = Platform-specific interrupt vector
* a2 (r18) = Pointer to logout area
*/
#define MCHK_COMMON_SIZE 24
#define MCHK_LOGOUT_SIZE 144
MchkLogOut:
mfpr p1, qemu_ps
// ??? Apparently we skip the insn that caused the mchk.
// ??? This is used by the kernel for mcheck_expected.
addq p6, 4, p6
STACK_FRAME p1, p6, p2, 0
// Restore the real EXC_ADDR for the logout frame.
subq p6, 4, p6
// Locate logout frame
br $gp, .+4
ldah $gp, 0($gp) !gpdisp!2
lda $gp, 0($gp) !gpdisp!2
ldah p1, mchk_logout($gp) !gprelhigh
lda p1, mchk_logout(p1) !gprellow
SYS_WHAMI p2
mull p2, MCHK_LOGOUT_SIZE, p2
addq p2, p1, a2
// Populate the minimal logout frame
lda p2, MCHK_LOGOUT_SIZE
stl p2, 0(a2) // size
stl $31, 4(a2) // flags
lda p1, MCHK_COMMON_SIZE
stl p1, 8(a2) // proc_offset
stl p2, 12(a2) // sys_offset
stl p0, 16(a2) // mchk_code
stl $31, 20(a2) // frame_rev
// EV6 portion, format copied from Linux kernel
// although there's not much we can fill in.
stq $31, 24(a2) // I_STAT
stq $31, 32(a2) // DC_STAT
stq $31, 40(a2) // C_ADDR
stq $31, 48(a2) // DC1_SYNDROME
stq $31, 56(a2) // DC0_SYNDROME
stq $31, 64(a2) // C_STAT
stq $31, 72(a2) // C_STS
stq $31, 80(a2) // MM_STAT
stq p6, 88(a2) // EXC_ADDR
stq $31, 96(a2) // IER_CM
stq $31, 104(a2) // ISUM
stq $31, 112(a2) // RESERVED0
mfpr p2, qemu_palbr
stq p2, 120(a2) // PAL_BASE
stq $31, 128(a2) // I_CTL
stq $31, 136(a2) // PCTX
mov IPL_K_MCHK, p1 // Raise IPL
mtpr p1, qemu_ps
mfpr p6, ptEntInt
mfpr $gp, ptKgp
lda a0, INT_K_MCHK
lda a1, 0 // "vector"
hw_ret (p6)
ENDFN MchkLogOut
MchkDouble:
bsr p7, UpdatePCB
lda v0, HLT_K_DBL_MCHK
br Sys_EnterConsole
ENDFN MchkDouble
MchkBugCheck:
MchkFromPal:
bsr p7, UpdatePCB
lda v0, HLT_K_MCHK_FROM_PAL
br Sys_EnterConsole
ENDFN MchkFromPal
MchkKspInvalid:
bsr p7, UpdatePCB
lda v0, HLT_K_KSP_INVAL
br Sys_EnterConsole
ENDFN MchkKspInvalid
/*
* 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, qemu_usp // 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
mfpr p5, qemu_unique // Save unique
stq_p p5, PCB_Q_UNIQUE(p4)
ret $31, (p7), 0
ENDFN UpdatePCB
/*
* FIXME
*/
Sys_EnterConsole:
halt
/*
* Allocate the initial bootup stack.
*/
.section .bss.stack
.align 3
.globl stack
.type stack,@object
.size stack,STACK_SIZE * 4
stack: .skip STACK_SIZE * 4
.globl mchk_logout
.type mchk_logout,@object
.size mchk_logout,MCHK_LOGOUT_SIZE * 4
mchk_logout:
.skip MCHK_LOGOUT_SIZE * 4