NT4/private/ntos/fw/mips/fwtrap.s
2020-09-30 17:12:29 +02:00

656 lines
22 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.

#if defined(JAZZ) && defined(R4000)
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
fw4trap.s
Abstract:
This module contains the fw exception handling functions.
Author:
Lluis Abello (lluis) 4-Sep-91
--*/
//
// include header file
//
#include <ksmips.h>
#include <selfmap.h>
.data
//
// Declare the table where to store the processor registers.
// also align it so that we can store doubles.
//
.align 4
ALTERNATE_ENTRY(RegisterTable)
.space RegisterTableSize
ALTERNATE_ENTRY(EndRegisterTable)
.text
.set noat
.set noreorder
SBTTL("User TLB dispatcher")
/*++
Routine Description:
This routine gets control on a User TLB Miss exception.
It reads the TLB Miss handler address from the System
Parameter Block and jumps to it.
Arguments:
None.
Return Value:
None.
--*/
LEAF_ENTRY(FwTbMissStartAddress)
li k0,KSEG0_BASE
lw k0,0x1018(k0)// Load address of UTLB handler
nop
jal k1,k0 // jump to handler saving return
nop // address in k1
mtc0 k0,epc // Handler returns return address in K0
nop // 2 cycle hazard
nop //
eret // restore from exception
nop
ALTERNATE_ENTRY(FwTbMissEndAddress)
.end FwTbMissStartAddress
SBTTL("General Exception dispatcher")
/*++
Routine Description:
This routine gets control on a General exception.
It reads the General exception handler address from the System
Parameter Block and jumps to it.
Arguments:
None.
Return Value:
None.
--*/
LEAF_ENTRY(FwGeneralExceptionStartAddress)
li k0,KSEG0_BASE
lw k0,0x1014(k0)// Load address of GE handler
nop
jal k1,k0 // jump to handler saving return
nop // address in k1
mtc0 k0,epc // Handler returns return address in K0
nop // 2 cycle hazard
nop //
eret // restore from exception
nop
ALTERNATE_ENTRY(FwGeneralExceptionEndAddress)
.end FwGeneralExceptionStartAddress
SBTTL("CacheError Exception dispatcher")
/*++
Routine Description:
This routine gets control on a cache error exception.
It jumps to the Monitor exception handler.
It gets copied to address 0xA0000100
Arguments:
None.
Return Value:
None.
--*/
LEAF_ENTRY(FwCacheErrorExceptionStartAddress)
la k0,CacheExceptionMonitorEntry // load address of Monitor entry
li k1,KSEG1_BASE // convert address to non cached
or k0,k0,k1 //
j k0
nop
ALTERNATE_ENTRY(FwCacheErrorExceptionEndAddress)
.end FwCacheErrorExceptionStartAddress
SBTTL("Firmware Exception intialize")
/*++
Routine Description:
This routine copies the User TLB dispatcher and
the General Exception dispatcher to the R4000 vector
addresses.
Arguments:
None.
Return Value:
None.
--*/
//
// Copy the TB miss and general exception dispatchers to low memory.
//
NESTED_ENTRY(FwExceptionInitialize,4, zero)
subu sp,sp,4 // decrement stack pointer
sw ra,0(sp) // save ra
la t2,FwTbMissStartAddress // get user TB miss start address
la t3,FwTbMissEndAddress // get user TB miss end address
li t4,KSEG1_BASE // get copy address
10: lw t5,0(t2) // copy code to low memory
addu t2,t2,4 // advance copy pointers
sw t5,0(t4) //
bne t2,t3,10b // if ne, more to copy
addu t4,t4,4 //
la t2,FwGeneralExceptionStartAddress // get general exception start address
la t3,FwGeneralExceptionEndAddress // get general exception end address
li t4,KSEG1_BASE + 0x180 // get copy address
20: lw t5,0(t2) // copy code to low memory
addu t2,t2,4 // advance copy pointers
sw t5,0(t4) //
bne t2,t3,20b // if ne, more to copy
addu t4,t4,4 //
la t2,FwCacheErrorExceptionStartAddress // get cache error exception start address
la t3,FwCacheErrorExceptionEndAddress // get cache error exception end address
li t4,KSEG1_BASE + 0x100 // get copy address
30: lw t5,0(t2) // copy code to low memory
addu t2,t2,4 // advance copy pointers
sw t5,0(t4) //
bne t2,t3,30b // if ne, more to copy
addu t4,t4,4 //
//
// Set the Monitor exception handler address in the vector.
//
li t0,KSEG0_BASE
la t1,FwExceptionHandler
sw t1,0x1014(t0) // Init GE vector
sw t1,0x1018(t0) // Init UTLB vector
jal HalSweepIcache // sweep the instruction cache
nop
jal HalSweepDcache // sweep the data cache
nop
//
// Clear the BEV in the psr and enable IO device interrupts
//
li t0,(1<<PSR_CU1) | (1 << PSR_IE) | (1<< (PSR_INTMASK+3))
mtc0 t0,psr // set new psr.
nop //
nop //
nop //
lw ra,0(sp) // load return address
addiu sp,sp,4 // restore stack pointer
j ra // return to caller
nop
.end FwExceptionInitialize
SBTTL("Monitor Exception Handler")
/*++
Routine Description:
This routine implements the exception handler for
the monitor.
Arguments:
k1 specifies the caller source in the following way:
- If k1 contains a word aligned address. The exception is
either a UTLB or a GE. The cause register supplies the cause
of the exception.
- Otherwise k1 contains a value that identifies the caller.
None.
Return Value:
None.
--*/
LEAF_ENTRY(FwExceptionHandler)
mfc0 k0,cause // read cause register
nop
andi k0,k0,R4000_XCODE_MASK // isolate cause of exception
bne k0,zero,10f // if not interrupt go to Monitor
nop
subu sp,sp,FwFrameSize // decrement state pointer
sw k1,FwFrameK1(sp) // save volatile state
sw ra,FwFrameRa(sp) // save volatile state
sw a0,FwFrameA0(sp) // save volatile state
sw a1,FwFrameA1(sp) // save volatile state
sw a2,FwFrameA2(sp) // save volatile state
sw a3,FwFrameA3(sp) // save volatile state
sw v0,FwFrameV0(sp) // save volatile state
sw v1,FwFrameV1(sp) // save volatile state
sw t0,FwFrameT0(sp) // save volatile state
sw t1,FwFrameT1(sp) // save volatile state
sw t2,FwFrameT2(sp) // save volatile state
sw t3,FwFrameT3(sp) // save volatile state
sw t4,FwFrameT4(sp) // save volatile state
sw t5,FwFrameT5(sp) // save volatile state
sw t6,FwFrameT6(sp) // save volatile state
sw t7,FwFrameT7(sp) // save volatile state
sw t8,FwFrameT8(sp) // save volatile state
sw t9,FwFrameT9(sp) // save volatile state
mfc0 a0,cause // read cause register
mfc0 a1,psr // read psr.
sw AT,FwFrameAT(sp) // save volatile state
jal FwInterruptHandler // call c routine
and a0,a0,a1 // mask IM to clear disabled interrupts.
move k0,v0 // save return value in k0
lw k1,FwFrameK1(sp) // restore volatile state
lw ra,FwFrameRa(sp) // restore volatile state
lw a0,FwFrameA0(sp) // restore volatile state
lw a1,FwFrameA1(sp) // restore volatile state
lw a2,FwFrameA2(sp) // restore volatile state
lw a3,FwFrameA3(sp) // restore volatile state
lw v0,FwFrameV0(sp) // restore volatile state
lw v1,FwFrameV1(sp) // restore volatile state
lw t0,FwFrameT0(sp) // restore volatile state
lw t1,FwFrameT1(sp) // restore volatile state
lw t2,FwFrameT2(sp) // restore volatile state
lw t3,FwFrameT3(sp) // restore volatile state
lw t4,FwFrameT4(sp) // restore volatile state
lw t5,FwFrameT5(sp) // restore volatile state
lw t6,FwFrameT6(sp) // restore volatile state
lw t7,FwFrameT7(sp) // restore volatile state
lw t8,FwFrameT8(sp) // restore volatile state
lw t9,FwFrameT9(sp) // restore volatile state
lw AT,FwFrameAT(sp) // save volatile state
beq k0,zero,10f // if routine returned false do not return
addiu sp,sp,FwFrameSize // restore stack pointer
mfc0 k0,epc // get return address
nop
j k1 // return to caller
nop //
//
// Control reaches here if an exception other than an interrupt occurred
// or if the interrupt handler returned false meaning that it didn't
// know how to handle the interrupt exception.
//
// At this time no state has been destroyed and register k1 still contains
// the address where to return.
//
10:
addiu k0,k0,-XCODE_BREAKPOINT // substract breakpoint code
beq k0,zero,10f // if eq Bp exception, call KD unconditionally
la k0,KdInstalled // load address of boolean
lbu k0,0(k0) // read boolean
beq k0,zero,MonitorExceptionHandler // if false go to the monitor
nop // otherwise
10: j KiGeneralException // go to the debugger.
nop
//
// This is the entry point when the monitor is called.
// Set k1 to 3 to tell the Monitor than can execute a j ra
// to quit.
//
ALTERNATE_ENTRY(FwMonitor)
b MonitorExceptionHandler
li k1,3 // set k1 to 3 to indicate we don't get
nop // here because of an exception
// The monitor returns to ra which points
// to where we got called from.
ALTERNATE_ENTRY(CacheExceptionMonitorEntry)
la k0,RegisterTable // get address of table.
or k0,k0,k1 // set it non cached.
b MonitorEntry // go to monitor
ori k1,zero,CACHE_EXCEPTION // set flag to tell that parity error occurred
ALTERNATE_ENTRY(MonitorExceptionHandler)
//
// Save the registers.
//
la k0,RegisterTable // get address of table.
ALTERNATE_ENTRY(MonitorEntry)
sw zero,zeroRegTable(k0)
sw AT,atRegTable(k0)
sw v0,v0RegTable(k0)
sw v1,v1RegTable(k0)
sw a0,a0RegTable(k0)
sw a1,a1RegTable(k0)
sw a2,a2RegTable(k0)
sw a3,a3RegTable(k0)
sw t0,t0RegTable(k0)
sw t1,t1RegTable(k0)
sw t2,t2RegTable(k0)
sw t3,t3RegTable(k0)
sw t4,t4RegTable(k0)
sw t5,t5RegTable(k0)
sw t6,t6RegTable(k0)
sw t7,t7RegTable(k0)
sw s0,s0RegTable(k0)
sw s1,s1RegTable(k0)
sw s2,s2RegTable(k0)
sw s3,s3RegTable(k0)
sw s4,s4RegTable(k0)
sw s5,s5RegTable(k0)
sw s6,s6RegTable(k0)
sw s7,s7RegTable(k0)
sw t8,t8RegTable(k0)
sw t9,t9RegTable(k0)
sw k0,k0RegTable(k0)
sw k1,k1RegTable(k0)
sw gp,gpRegTable(k0)
sw sp,spRegTable(k0)
sw s8,s8RegTable(k0)
sw ra,raRegTable(k0)
//
// Store coprocessor1 registers.
//
cfc1 v0,fsr
sdc1 f0,f0RegTable(k0)
sdc1 f2,f2RegTable(k0)
sdc1 f4,f4RegTable(k0)
sdc1 f6,f6RegTable(k0)
sdc1 f8,f8RegTable(k0)
sdc1 f10,f10RegTable(k0)
sdc1 f12,f12RegTable(k0)
sdc1 f14,f14RegTable(k0)
sdc1 f16,f16RegTable(k0)
sdc1 f18,f18RegTable(k0)
sdc1 f20,f20RegTable(k0)
sdc1 f22,f22RegTable(k0)
sdc1 f24,f24RegTable(k0)
sdc1 f26,f26RegTable(k0)
sdc1 f28,f28RegTable(k0)
sdc1 f30,f30RegTable(k0)
sw v0,fsrRegTable(k0)
//
// Store cop0 registers.
//
mfc0 v1,index
mfc0 v0,random
sw v1,indexRegTable(k0)
sw v0,randomRegTable(k0)
mfc0 v1,entrylo0
nop
mfc0 v0,entrylo1
sw v1,entrylo0RegTable(k0)
sw v0,entrylo1RegTable(k0)
mfc0 v1,context
mfc0 v0,pagemask
sw v1,contextRegTable(k0)
sw v0,pagemaskRegTable(k0)
mfc0 v1,wired
mfc0 v0,badvaddr
sw v1,wiredRegTable(k0)
sw v0,badvaddrRegTable(k0)
mfc0 v1,count
mfc0 v0,entryhi
sw v1,countRegTable(k0)
sw v0,entryhiRegTable(k0)
mfc0 v1,compare
mfc0 v0,psr
sw v1,compareRegTable(k0)
sw v0,psrRegTable(k0)
mfc0 v1,cause
mfc0 v0,epc
sw v1,causeRegTable(k0)
sw v0,epcRegTable(k0)
mfc0 v1,prid
mfc0 v0,config
sw v1,pridRegTable(k0)
sw v0,configRegTable(k0)
mfc0 v1,lladdr
mfc0 v0,watchlo
sw v1,lladdrRegTable(k0)
sw v0,watchloRegTable(k0)
mfc0 v1,watchhi
mfc0 v0,ecc
sw v1,watchhiRegTable(k0)
sw v0,eccRegTable(k0)
mfc0 v1,cacheerr
mfc0 v0,taglo
sw v1,cacheerrorRegTable(k0)
sw v0,tagloRegTable(k0)
mfc0 v1,taghi
mfc0 v0,errorepc
sw v1,taghiRegTable(k0)
sw v0,errorepcRegTable(k0)
li k0,CACHE_EXCEPTION
bne k0,k1,10f // check if parity exception
la k0,Monitor // Set address where to return
li t0,KSEG1_BASE // convert it to non cached
or k0,k0,t0 //
mtc0 k0,errorepc // set in errorepc
li sp, RAM_TEST_STACK_ADDRESS | KSEG1_BASE
andi a0,k1,0x3 // pass caller source in a0 just 2 bits.
eret // jump to the monitor and leave exception level
10:
la k0,Monitor // Set address where to
mtc0 k0,epc // return from the exception.
li k0,0x3
beq k0,k1,10f // if k1=3 do not change sp
andi a0,k1,0x3 // pass caller source in a0 just 2 bits.
li sp,RAM_TEST_STACK_ADDRESS // set the stack pointer.
eret // jump to the monitor and leave exception level
10: j Monitor
.end MonitorExceptionHandler
/*++
ARC_STATUS
FwInvoke(
IN ULONG ExecAddr,
IN ULONG StackAddr,
IN ULONG Argc,
IN PCHAR Argv[],
IN PCHAR Envp[]
)
Routine Description:
This routine invokes a loaded program.
Arguments:
ExecAddr - Supplies the address of the routine to call.
StackAddr - Supplies the address to which the stack pointer is set.
Argc, Argv, Envp - Supply the arguments and endvironment to pass to
Loaded program.
The stack pointer is saved in register s0 so that when the loaded
program returns, the old stack pointer can be restored.
In addition, the value stored in InvokeSavedSp is read and if zero,
this is the first loaded program, thus the current stack pointer
is the firmware stack pointer and it is saved in order to
be able to restore the Firmware stack pointer when a loaded program
calls ReturnFromMain.
Return Value:
ESUCCESS is returned if the address is valid.
EFAULT indicates an invalid addres.
--*/
{
NESTED_ENTRY(FwInvoke,0x20,zero)
subu sp,sp,0x20 // allocate room in the stack.
sw ra,0x1C(sp) // save ra
sw s0,0x18(sp) // save s0
move v1,a0 // save address of routine to call
andi v0,v1,0x3 // check for alignment.
bne v0,zero,20f // if not aligned return error.
li v0,6 // set EFAULT = 6 a return value.
move a0,a2 // move argc to first argument
move s0,sp // save stack pointer in s0
lw a2,0x30(sp) // load Envp argument into second.
move sp,a1 // set new stack pointer.
subu sp,sp,0x10 // make room for arguments.
jal v1 // call program
move a1,a3 // move argv to right argument
//
// If loaded program returns, s0 has the previous stack pointer.
//
move sp,s0 // set old stack pointer.
move v0,zero // set ESUCCESS as return value.
lw ra,0x1C(sp) // restore ra
lw s0,0x18(sp) // restore s0
20:
j ra // return to caller
addiu sp,sp,0x20 // restore sp.
.end FwInvoke
SBTTL("FwExecute")
/*++
Routine Description:
This routine is the entry point for the Execute service.
It behaves in two different ways depending on where it is
called from:
1) If it's called from the Firmware it saves the stack pointer
in a fixed location and then saves all the saved registers
in the stack. This is the stack that will be used to restore
the saved state when returning to the firmware.
2) If called from a loaded program the program to be loaded
and executed can overwrite the current program and it's
stack, therefore a temporary stack is set.
Arguments:
a0 IN PCHAR Path,
a1 IN ULONG Argc,
a2 IN PCHAR Argv[],
a3 IN PCHAR Envp[]
Return Value:
ARC_STATUS returned by FwPrivateExecute.
Always returns to the Firmware.
--*/
LEAF_ENTRY(FwExecute)
la t0, FwSavedSp // load address where to save Fw SP
lw t1, 0(t0) // read saved stack
beq t1, zero,CallFromFw // if zero first call from Fw.
nop
//
// A loaded program wants to be replaced by another program
// therefore the current stack and state will be trashed and a
// new temporary stack needs to be set.
//
la t0, FwTemporaryStack // load address of Fw temporary stack
lw sp, 0(t0) // load Tmp Stack value.
jal FwPrivateExecute // go to do the job
nop
//
// if the program returns it's caller is gone, therefore
// we restore the initiali fw stack and returned to the
// firmware instead.
//
la t0, FwSavedSp // get address of saved stack
lw sp, 0(t0) // restore saved stack.
b RestoreFwState // go to restore state
nop
CallFromFw:
subu sp,sp,0x30 // make room in the stack
sw sp, 0(t0) // save new stack
sw ra, 0x4(sp) // save also return address
sw s0, 0x8(sp) // save state that must be preserved.
sw s1, 0xC(sp)
sw s2, 0x10(sp)
sw s3, 0x14(sp)
sw s4, 0x18(sp)
sw s5, 0x1C(sp)
sw s6, 0x20(sp)
sw s7, 0x24(sp)
sw s8, 0x28(sp)
jal FwPrivateExecute // go to do the job
sw gp, 0x2C(sp) // save global pointer
RestoreFwState:
lw ra, 0x4(sp) // restore ra
lw s0, 0x8(sp) // restore Fw state
lw s1, 0xC(sp)
lw s2, 0x10(sp)
lw s3, 0x14(sp)
lw s4, 0x18(sp)
lw s5, 0x1C(sp)
lw s6, 0x20(sp)
lw s7, 0x24(sp)
lw s8, 0x28(sp)
lw gp, 0x2C(sp)
j ra // return to Firmware.
addu sp,sp,0x30 // restore sp.
.end FwExecute
SBTTL("Termination Functions")
/*++
Routine Description:
This routine implements the Firmware ReturnFromMain
termination function.
Arguments:
None.
Return Value:
returns to where the program was called from.
--*/
ALTERNATE_ENTRY(FwReturnFromMain)
la t0,FwSavedSp // get address where SP was saved
lw sp,0(t0) // set old stack pointer.
b RestoreFwState
move v0,zero // set ESUCCESS as return value.
.end FwReturnFromMain
#endif // defined(JAZZ) && defined(R4000)