blob: 64941a897bba8f459b5b3cb4b350134d71b06426 [file] [log] [blame]
/* 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