NT4/private/ntos/ke/ppc/miscasm.s
2020-09-30 17:12:29 +02:00

657 lines
18 KiB
ArmAsm
Raw Permalink 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.

//++
//
// Copyright (c) 1993 IBM Corporation
//
// Module Name:
//
// miscasm.s
//
// Abstract:
//
// This module implements machine dependent miscellaneous kernel functions.
//
// Author:
//
// Rick Simpson July 26, 1993
//
// Environment:
//
// Kernel mode only.
//
// Revision History:
//
// plj September 15, 1993 Added routines KiDisableInterrupts and
// KiRestoreInterrupts.
// Mark Mergen 09/93-10/93 Ke/KiFlush/FillTb KiSwapProcess subroutines.
// Pat Carr 11/93 Mods for 603: Ke/KiFlush/FillTb routines.
// Ying Chan 02/94 Mods for 604: Ke/KiFlush/FillTb routines.
// plj 09/94 MP support + use PIDs for VSIDs
// plj 02/95 KiSwapProcess moved to ctxswap.s
// patcarr 02/95 Added support for 603+, 604+
//
//--
//list(off)
#include "ksppc.h"
//list(on)
// Globals referenced within this file:
.globl ..KiContinue
.globl ..KeTestAlertThread
.globl ..KiExceptionExit
.globl ..KiRaiseException
//++
//
// KPCR *
// KiGetPcr ()
//
// Routine Description:
//
// This function returns the effective address of the Processor
// Control Region (KPCR *). This address is constant, and
// this routine merely copies that constant into GPR 3 and returns.
//
// Arguments:
//
// None.
//
// Return Value:
//
// Effective address of this processor's PCR.
//
//--
LEAF_ENTRY (KiGetPcr)
KIPCR(r.3)
LEAF_EXIT (KiGetPcr)
//++
//
// void
// KiSetDbat
//
// Routine Description:
//
// Writes a set of values to DBAT n
//
// No validation of parameters is done. Protection is set for kernel
// mode access only.
//
// Arguments:
//
// r.3 Number of DBAT
// r.4 Physical address
// r.5 Virtual Address
// r.6 Length (in bytes)
// r.7 Coherence Requirements (WIM)
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY (KiSetDbat)
mfpvr r.9 // different format for
// 601 vs other 6xx processors
cmpwi cr.5, r.3, 1
cmpwi cr.6, r.3, 2
cmpwi cr.7, r.3, 3
rlwinm. r.10, r.9, 0, 0xfffe0000// Check for 601
// calculate mask (ie BSM) If we knew the number passed in was
// always a power of two we could just subtract 1 and shift right
// 17 bits. But to be sure we will use a slightly more complex
// algorithm than will always generate a correct mask.
//
// the mask is given by
//
// ( 1 << ( 32 - 17 - cntlzw(Length - 1) ) ) - 1
// == ( 1 << ( 15 - cntlzw(Length - 1) ) ) - 1
addi r.6, r.6, -1
oris r.6, r.6, 1 // ensure min length 128KB
ori r.6, r.6, 0xffff
cntlzw r.6, r.6
subfic r.6, r.6, 15
li r.10, 1
slw r.6, r.10, r.6
addi r.6, r.6, -1
beq cr.0, KiSetDbat601
// processor is not a 601.
rlwinm r.7, r.7, 3, 0x38 // position WIM (G = 0)
rlwinm r.6, r.6, 2, 0x1ffc // restrict BAT maximum (non 601)
// after left shifting by 2.
// if caching is Inhibited, set the Guard bit as well.
rlwimi r.7, r.7, 30, 0x8 // copy G bit from I bit.
ori r.6, r.6, 0x2 // Valid (bit) in supervisor state only
ori r.7, r.7, 2 // PP = 0x2
or r.5, r.5, r.6 // = Virt addr | BL | Vs | Vp
or r.4, r.4, r.7 // = Phys addr | WIMG | 0 | PP
beq cr.5, KiSetDbat1
beq cr.6, KiSetDbat2
beq cr.7, KiSetDbat3
KiSetDbat0:
mtdbatl 0, r.4
mtdbatu 0, r.5
b KiSetDbatExit
KiSetDbat1:
mtdbatl 1, r.4
mtdbatu 1, r.5
b KiSetDbatExit
KiSetDbat2:
mtdbatl 2, r.4
mtdbatu 2, r.5
b KiSetDbatExit
KiSetDbat3:
mtdbatl 3, r.4
mtdbatu 3, r.5
b KiSetDbatExit
// 601 has different format BAT registers and actually only has
// one set unlike other PowerPC processors which have seperate
// Instruction and Data BATs. The 601 BAT registers are set
// with the mtibat[u|l] instructions.
KiSetDbat601:
rlwinm r.7, r.7, 3, 0x70 // position WIMG (601 has no G bit)
rlwinm r.6, r.6, 0, 0x3f // restrict BAT maximum (601 = 8MB)
ori r.6, r.6, 0x40 // Valid bit
ori r.7, r.7, 4 // Ks = 0 | Ku = 1 | PP = 0b00
or r.4, r.4, r.6 // = Phys addr | Valid | BL
or r.5, r.5, r.7 // = Virt addr | WIM | Ks | Ku | PP
beq cr.5, KiSet601Bat1
beq cr.6, KiSet601Bat2
beq cr.7, KiSet601Bat3
KiSet601Bat0:
mtibatl 0, r.4
mtibatu 0, r.5
b KiSetDbatExit
KiSet601Bat1:
mtibatl 1, r.4
mtibatu 1, r.5
b KiSetDbatExit
KiSet601Bat2:
mtibatl 2, r.4
mtibatu 2, r.5
b KiSetDbatExit
KiSet601Bat3:
mtibatl 3, r.4
mtibatu 3, r.5
KiSetDbatExit:
isync
LEAF_EXIT(KiSetDbat)
//++
//
// void
// KiSetDbatInvalid(BAT)
//
// Routine Description:
//
// Clears the valid bit(s) in DBAT n
//
// Arguments:
//
// r.3 Number of DBAT
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KiSetDbatInvalid)
mfpvr r.9 // different format for
// 601 vs other 6xx processors
cmpwi cr.5, r.3, 1
cmpwi cr.6, r.3, 2
cmpwi cr.7, r.3, 3
rlwinm. r.10, r.9, 0, 0xfffe0000// Check for 601
li r.0, 0 // no valid bit
beq cr.0, KiInvalidateBat601
// processor is not a 601.
beq cr.5, KiInvalidateDbat1
beq cr.6, KiInvalidateDbat2
beq cr.7, KiInvalidateDbat3
KiInvalidateDbat0:
mtdbatu 0, r.0
b KiSetDbatInvalidExit
KiInvalidateDbat1:
mtdbatu 1, r.0
b KiSetDbatInvalidExit
KiInvalidateDbat2:
mtdbatu 2, r.0
b KiSetDbatInvalidExit
KiInvalidateDbat3:
mtdbatu 3, r.0
b KiSetDbatInvalidExit
// 601 has different format BAT registers and actually only has
// one set unlike other PowerPC processors which have seperate
// Instruction and Data BATs. The 601 BAT registers are set
// with the mtibat[u|l] instructions.
KiInvalidateBat601:
beq cr.5, KiInvalidate601Bat1
beq cr.6, KiInvalidate601Bat2
beq cr.7, KiInvalidate601Bat3
KiInvalidate601Bat0:
mtibatl 0, r.0
b KiSetDbatInvalidExit
KiInvalidate601Bat1:
mtibatl 1, r.0
b KiSetDbatInvalidExit
KiInvalidate601Bat2:
mtibatl 2, r.0
b KiSetDbatInvalidExit
KiInvalidate601Bat3:
mtibatl 3, r.0
KiSetDbatInvalidExit:
isync
LEAF_EXIT(KiSetDbatInvalid)
//++
//
// ULONG
// KiGetPvr ()
//
// Routine Description:
//
// Returns the contents of PVR, the Processor Version Register.
// This is a read-only register, so there is no corresponding
// function to write the PVR.
//
// Arguments:
//
// None.
//
// Return Value:
//
// Contents of PVR
//
//--
LEAF_ENTRY (KiGetPvr)
mfpvr r.3 // read PVR
LEAF_EXIT (KiGetPvr)
//++
//
// BOOLEAN
// KiDisableInterrupts (VOID)
//
// Routine Description:
//
// This function disables interrupts and returns whether interrupts
// were previously enabled.
//
// Arguments:
//
// None.
//
// Return Value:
//
// A boolean value that determines whether interrupts were previously
// enabled (TRUE) or disabled (FALSE).
//
//--
LEAF_ENTRY(KiDisableInterrupts)
DISABLE_INTERRUPTS(r.3, r.4) // turn off interrupts, old MSR
// in r.3
extrwi r.3, r.3, 1, MSR_EE // isolate enable bit
LEAF_EXIT(KiDisableInterrupts)
//++
//
// VOID
// KiRestoreInterrupts (IN BOOLEAN Enable)
//
// Routine Description:
//
// This function restores the interrupt enable that was returned by
// the disable interrupts function.
//
// Arguments:
//
// Enable (r.3) - Supplies the interrupt enable value.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KiRestoreInterrupts)
mfmsr r.4 // get current processor state
insrwi r.4, r.3, 1, MSR_EE // insert external interrupt
// enable/disable
mtmsr r.4 // set new state
cror 0,0,0 // N.B. 603e/ev Errata 15
LEAF_EXIT(KiRestoreInterrupts)
//++
//
// NTSTATUS
// NtContinue (
// IN PCONTEXT ContextRecord,
// IN BOOLEAN TestAlert
// )
//
// Routine Description:
//
// This routine is called as a system service to continue execution after
// an exception has occurred. Its functions is to transfer information from
// the specified context record into the trap frame that was built when the
// system service was executed, and then exit the system as if an exception
// had occurred.
//
// Arguments:
//
// ContextRecord (r.3) - Supplies a pointer to a context record.
//
// TestAlert (r.4) - Supplies a boolean value that specifies whether alert
// should be tested for the previous processor mode.
//
// Return Value:
//
// Normally there is no return from this routine. However, if the specified
// context record is misaligned or is not accessible, then the appropriate
// status code is returned.
//
//--
.struct 0
con_cr_hdr: .space StackFrameHeaderLength
con_ex_frame: .space ExceptionFrameLength
con_tr_frame: .space 4
con_test_alert: .space 4
con_saved_lr: .space 4
.align 3
con_cr_length:
NESTED_ENTRY (NtContinue,con_cr_length,0,0)
PROLOGUE_END (NtContinue)
stw r.4, con_test_alert (r.sp) // save test alert argument
stw r.12, con_tr_frame (r.sp) // save the trap frame address
//
// Transfer information from the context frame to the exception and trap
// frames.
//
// r.3 points to Context (1st parm)
la r.4, con_ex_frame (r.sp) // r.4 = addr of Exception Frame (2nd parm)
ori r.5, r.12, 0 // Pass the real trap frame
bl ..KiContinue // transfer context to kernel frames
//
// If the kernel continuation routine returns success, then exit via the
// exception exit code. Otherwise return to the system service dispatcher.
//
cmpwi r.3, 0 // test return value
bne con_20 // branch if non-zero (failed)
//
// Check to determine if alert should be tested for the previous processor
// mode and restore the previous mode in the thread object.
//
lwz r.4, KiPcr+PcCurrentThread(r.0) // get current thread address
lwz r.5, con_test_alert (r.sp) // get test alert argument
lwz r.12, con_tr_frame (r.sp) // get trap frame address
cmpwi r.5, 0 // test test alert flag
lwz r.6, TrTrapFrame (r.12) // get old trap frame address
lbz r.7, TrPreviousMode (r.12) // get old previous mode
lbz r.3, ThPreviousMode (r.4) // get current previous mode
stw r.6, ThTrapFrame (r.4) // restore old trap frame address
stb r.7, ThPreviousMode (r.4) // restore old previous mode
beq con_10 // if flag zero, don't test for alert
bl ..KeTestAlertThread // test alert for current thread
//
// Exit the system via exception exit which will restore the nonvolatile
// machine state.
//
con_10:
la r.3, con_ex_frame (r.sp) // parm 1 = Exception Frame addr
lwz r.4, con_tr_frame (r.sp) // set the original trap frame addr
b ..KiExceptionExit // finish in exception exit
//
// Context record is misaligned or not accessible.
//
con_20:
NESTED_EXIT (NtContinue,con_cr_length,0,0)
//++
//
// NTSTATUS
// NtRaiseException (
// IN PEXCEPTION_RECORD ExceptionRecord,
// IN PCONTEXT ContextRecord,
// IN BOOLEAN FirstChance
// )
//
// Routine Description:
//
// This routine is called as a system service to raise an exception.
// The exception can be raised as a first or second chance exception.
//
// Arguments:
//
// ExceptionRecord (r.3) - Supplies a pointer to an exception record.
//
// ContextRecord (r.4) - Supplies a pointer to a context record.
//
// FirstChance (r.5) - Supplies a boolean value that determines whether
// this is the first (TRUE) or second (FALSE) chance for dispatching
// the exception.
//
// N.B. Register r.12 is assumed to contain the address of a trap frame.
// (HACK!) See above description of NtContinue().
//
// Return Value:
//
// Normally there is no return from this routine. However, if the specified
// context record or exception record is misaligned or is not accessible,
// then the appropriate status code is returned.
//
//--
.struct 0
rai_cr_hdr: .space StackFrameHeaderLength
rai_ex_frame: .space ExceptionFrameLength
rai_tr_frame: .space 4
rai_saved_lr: .space 4
.align 3
rai_cr_length:
NESTED_ENTRY (NtRaiseException,rai_cr_length,0,0)
PROLOGUE_END (NtRaiseException)
stw r.12, rai_tr_frame (r.sp) // save incoming Trap Frame pointer
ori r.7, r.5, 0 // move "first chance" arg to 5th position
//
// Save the nonvolatile machine state so that it can be restored by exception
// exit if it is not overwritten by the specified context record.
//
la r.5, rai_ex_frame (r.sp) // point r.5 to the Exception Frame
stw r.13, ExGpr13 (r.5) // save non-volatile GPRs
stw r.14, ExGpr14 (r.5)
stw r.15, ExGpr15 (r.5)
stw r.16, ExGpr16 (r.5)
stw r.17, ExGpr17 (r.5)
stw r.18, ExGpr18 (r.5)
stw r.19, ExGpr19 (r.5)
stw r.20, ExGpr20 (r.5)
stw r.21, ExGpr21 (r.5)
stw r.22, ExGpr22 (r.5)
stw r.23, ExGpr23 (r.5)
stw r.24, ExGpr24 (r.5)
stw r.25, ExGpr25 (r.5)
stw r.26, ExGpr26 (r.5)
stw r.27, ExGpr27 (r.5)
stw r.28, ExGpr28 (r.5)
stw r.29, ExGpr29 (r.5)
stw r.30, ExGpr30 (r.5)
stw r.31, ExGpr31 (r.5)
stfd f.14, ExFpr14 (r.5) // save non-volatile FPRs
stfd f.15, ExFpr15 (r.5)
stfd f.16, ExFpr16 (r.5)
stfd f.17, ExFpr17 (r.5)
stfd f.18, ExFpr18 (r.5)
stfd f.19, ExFpr19 (r.5)
stfd f.20, ExFpr20 (r.5)
stfd f.21, ExFpr21 (r.5)
stfd f.22, ExFpr22 (r.5)
stfd f.23, ExFpr23 (r.5)
stfd f.24, ExFpr24 (r.5)
stfd f.25, ExFpr25 (r.5)
stfd f.26, ExFpr26 (r.5)
stfd f.27, ExFpr27 (r.5)
stfd f.28, ExFpr28 (r.5)
stfd f.29, ExFpr29 (r.5)
stfd f.30, ExFpr30 (r.5)
stfd f.31, ExFpr31 (r.5)
//
// Call the raise exception kernel routine which will marshall the arguments
// and then call the exception dispatcher.
//
// r.3 addr of Exception Record
// r.4 addr of Context Record
// r.5 addr of Exception Frame
// r.6 addr of Trap Frame
// r.7 "first chance" boolean
//
ori r.6, r.12, 0 // move Trap Frame pointer into call arg
bl ..KiRaiseException // call Raise Exception routine
//
// If the raise exception routine returns success, then exit via the exception
// exit code. Otherwise return to the system service dispatcher.
//
lwz r.5, KiPcr+PcCurrentThread(r.0) // get current thread address
lwz r.4, rai_tr_frame (r.sp) // parm 2 = Trap Frame addr
lwz r.6, TrTrapFrame (r.4) // get old trap frame address
cmpwi r.3, 0 // test return value
stw r.6, ThTrapFrame (r.5) // restore old trap frame address
bne rai10 // branch if dispatch not successful
//
// Exit the system via exception exit which will restore the nonvolatile
// machine state.
//
la r.3, rai_ex_frame (r.sp) // parm 1 = Exception Frame addr
b ..KiExceptionExit // finish in Exception Exit
//
// The context or exception record is misaligned or not accessible, or the
// exception was not handled.
//
rai10:
NESTED_EXIT (NtRaiseException,rai_cr_length,0,0)
//++
//
// PKTHREAD
// KeGetCurrentThread (VOID)
//
// Routine Description:
//
// Arguments:
//
// None.
//
// Return Value:
//
// Returns a pointer to the executing thread object.
//
//--
LEAF_ENTRY(KeGetCurrentThread)
lwz r.3, KiPcr+PcCurrentThread(r.0)
LEAF_EXIT(KeGetCurrentThread) // return
//++
//
// KIRQL
// KeGetCurrentIrql (VOID)
//
// Routine Description:
//
// Arguments:
//
// None.
//
// Return Value:
//
// Returns a pointer to the executing thread object.
//
//--
LEAF_ENTRY(KeGetCurrentIrql)
lbz r.3, KiPcr+PcCurrentIrql(r.0)
LEAF_EXIT(KeGetCurrentIrql) // return