268 lines
7.6 KiB
ArmAsm
268 lines
7.6 KiB
ArmAsm
// TITLE("Thread Startup")
|
||
//++
|
||
//
|
||
// Module Name:
|
||
//
|
||
// threadbg.s
|
||
//
|
||
// Abstract:
|
||
//
|
||
// This module implements the MIPS machine dependent code necessary to
|
||
// startup a thread in kernel mode.
|
||
//
|
||
// Author:
|
||
//
|
||
// Bernard Lint 19-Mar-1996
|
||
//
|
||
// Environment:
|
||
//
|
||
// Kernel mode only, IRQL APC_LEVEL.
|
||
//
|
||
// Revision History:
|
||
//
|
||
// Based on MIPS version (David N. Cutler (davec) 28-Mar-1990)
|
||
//
|
||
//--
|
||
|
||
#include "ksia64.h"
|
||
|
||
//
|
||
// Globals used
|
||
//
|
||
|
||
PublicFunction(KeBugCheck)
|
||
PublicFunction(KiRestoreExceptionFrame)
|
||
PublicFunction(KiExceptionExit)
|
||
|
||
SBTTL("Thread Startup")
|
||
|
||
//++
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This routine is called at thread startup. Its function is to call the
|
||
// initial thread procedure. If control returns from the initial thread
|
||
// procedure and a user mode context was established when the thread
|
||
// was initialized, then the user mode context is restored and control
|
||
// is transfered to user mode. Otherwise a bug check will occur.
|
||
//
|
||
// When this thread was created, a switch frame for SwapContext was pushed
|
||
// onto the stack and initialized such that SwapContext will return to
|
||
// the first instruction of this routine when this thread is first switched to.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// s0 (saved) - Supplies a boolean value that specified whether a user
|
||
// mode thread context was established when the thread was initialized.
|
||
//
|
||
// s1 (saved) - Supplies the starting context parameter for the initial
|
||
// thread procedure.
|
||
//
|
||
// s2 (saved) - Supplies the starting address of the initial thread routine.
|
||
//
|
||
// N.B. This is a function pointer.
|
||
//
|
||
// s3 - Supplies the starting address of the initial system routine.
|
||
//
|
||
// N.B. This is an entry point.
|
||
//
|
||
// On entry:
|
||
//
|
||
// Since SwapConext deallocates the switch frame sp points to either:
|
||
// for system thread sp -> bottom of kernel stack;
|
||
// for user thread sp -> exception frame (or higher fp savearea
|
||
// if not FPLAZY)
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
NESTED_ENTRY(KiThreadDispatch)
|
||
|
||
//
|
||
// N.B. The following code is never executed. Its purpose is to allow the
|
||
// kernel debugger to walk call frames backwards through thread startup
|
||
// and to support get/set user context.
|
||
//
|
||
|
||
.regstk 0,2,2,0
|
||
.prologue 0xC, loc0
|
||
|
||
.fframe ExceptionFrameLength
|
||
add sp = -ExceptionFrameLength, sp
|
||
;;
|
||
add t0 = ExFltS19+STACK_SCRATCH_AREA, sp
|
||
add t1 = ExFltS18+STACK_SCRATCH_AREA, sp
|
||
;;
|
||
|
||
.save.gf 0x0, 0xC0000
|
||
stf.spill [t0] = fs19, ExFltS17-ExFltS19
|
||
stf.spill [t1] = fs18, ExFltS16-ExFltS18
|
||
;;
|
||
|
||
.save.gf 0x0, 0x30000
|
||
stf.spill [t0] = fs17, ExFltS15-ExFltS17
|
||
stf.spill [t1] = fs16, ExFltS14-ExFltS16
|
||
mov t10 = bs4
|
||
;;
|
||
|
||
.save.gf 0x0, 0xC000
|
||
stf.spill [t0] = fs15, ExFltS13-ExFltS15
|
||
stf.spill [t1] = fs14, ExFltS12-ExFltS14
|
||
mov t11 = bs3
|
||
;;
|
||
|
||
.save.gf 0x0, 0x3000
|
||
stf.spill [t0] = fs13, ExFltS11-ExFltS13
|
||
stf.spill [t1] = fs12, ExFltS10-ExFltS12
|
||
mov t12 = bs2
|
||
;;
|
||
|
||
.save.gf 0x0, 0xC00
|
||
stf.spill [t0] = fs11, ExFltS9-ExFltS11
|
||
stf.spill [t1] = fs10, ExFltS8-ExFltS10
|
||
mov t13 = bs1
|
||
;;
|
||
|
||
.save.gf 0x0, 0x300
|
||
stf.spill [t0] = fs9, ExFltS7-ExFltS9
|
||
stf.spill [t1] = fs8, ExFltS6-ExFltS8
|
||
mov t14 = bs0
|
||
;;
|
||
|
||
.save.gf 0x0, 0xC0
|
||
stf.spill [t0] = fs7, ExFltS5-ExFltS7
|
||
stf.spill [t1] = fs6, ExFltS4-ExFltS6
|
||
mov t15 = ar.lc
|
||
;;
|
||
|
||
.save.gf 0x0, 0x30
|
||
stf.spill [t0] = fs5, ExFltS3-ExFltS5
|
||
stf.spill [t1] = fs4, ExFltS2-ExFltS4
|
||
;;
|
||
|
||
.save.f 0xC
|
||
stf.spill [t0] = fs3, ExFltS1-ExFltS3 // save fs3
|
||
stf.spill [t1] = fs2, ExFltS0-ExFltS2 // save fs2
|
||
;;
|
||
|
||
.save.f 0x3
|
||
stf.spill [t0] = fs1, ExBrS4-ExFltS1 // save fs1
|
||
stf.spill [t1] = fs0, ExBrS3-ExFltS0 // save fs0
|
||
;;
|
||
|
||
.save.b 0x18
|
||
st8 [t0] = t10, ExBrS2-ExBrS4 // save bs4
|
||
st8 [t1] = t11, ExBrS1-ExBrS3 // save bs3
|
||
;;
|
||
|
||
.save.b 0x6
|
||
st8 [t0] = t12, ExBrS0-ExBrS2 // save bs2
|
||
st8 [t1] = t13, ExIntS2-ExBrS1 // save bs1
|
||
;;
|
||
|
||
.save.b 0x1
|
||
st8 [t0] = t14, ExIntS3-ExBrS0 // save bs0
|
||
;;
|
||
|
||
.save.gf 0xC, 0x0
|
||
.mem.offset 0,0
|
||
st8.spill [t0] = s3, ExIntS1-ExIntS3 // save s3
|
||
.mem.offset 8,0
|
||
st8.spill [t1] = s2, ExIntS0-ExIntS2 // save s2
|
||
;;
|
||
|
||
.save.gf 0x3, 0x0
|
||
.mem.offset 0,0
|
||
st8.spill [t0] = s1, ExApLC-ExIntS1 // save s1
|
||
.mem.offset 8,0
|
||
st8.spill [t1] = s0, ExApEC-ExIntS0 // save s0
|
||
;;
|
||
|
||
.savepsp ar.pfs, ExceptionFrameLength-ExApEC-STACK_SCRATCH_AREA
|
||
st8 [t1] = t16, ExIntNats-ExApEC
|
||
mov t4 = ar.unat // captured Nats of s0-s3
|
||
;;
|
||
|
||
.savepsp ar.lc, ExceptionFrameLength-ExApLC-STACK_SCRATCH_AREA
|
||
st8 [t0] = t15
|
||
.savepsp @priunat, ExceptionFrameLength-ExIntNats-STACK_SCRATCH_AREA
|
||
st8 [t1] = t4 // save Nats of s0-s3
|
||
;;
|
||
|
||
|
||
ALTERNATE_ENTRY(KiThreadStartup)
|
||
|
||
alloc t0 = 0,2,2,0 // allocate call frame
|
||
mov savedpfs = zero // setup bogus brp and pfs
|
||
mov savedbrp = zero // to stop stack unwind
|
||
// by the debugger
|
||
;;
|
||
|
||
PROLOGUE_END
|
||
|
||
//
|
||
// restore the preserved states from the switch frame and then deallocate it
|
||
//
|
||
|
||
add out0 = SwExFrame+STACK_SCRATCH_AREA,sp
|
||
br.call.sptk brp = KiRestoreExceptionFrame
|
||
;;
|
||
|
||
//
|
||
// Lower IRQL to APC_LEVEL
|
||
//
|
||
|
||
add sp = SwitchFrameLength, sp
|
||
mov bt0 = s3 // setup call to system routine
|
||
mov t0 = APC_LEVEL
|
||
;;
|
||
|
||
SET_IRQL(t0)
|
||
|
||
mov out0 = s2 // arg 1 = thread routine (a function pointer)
|
||
mov out1 = s1 // arg 2 = thread context
|
||
br.call.sptk brp = bt0 // call system routine
|
||
;;
|
||
|
||
//
|
||
// Finish in common exception exit code which will restore the nonvolatile
|
||
// registers and exit to user mode.
|
||
//
|
||
// N.B. predicate register alias pUstk & pKstk must be the same as trap.s
|
||
// and they must be set up correctly upon entry into KiExceptionExit.
|
||
//
|
||
//
|
||
// If pKstk is set, an attempt was made to enter user mode for a thread
|
||
// that has no user mode context. Generate a bug check.
|
||
//
|
||
|
||
pUstk = ps3
|
||
pKstk = ps4
|
||
|
||
cmp.eq pKstk, pUstk = zero, s0 // if s0 is zero, no user context (system thread)
|
||
mov out0 = NO_USER_MODE_CONTEXT // set bug check code
|
||
(pKstk) br.call.spnt brp = KeBugCheck
|
||
|
||
//
|
||
// Set up for branch to KiExceptionExit
|
||
//
|
||
// s0 = trap frame
|
||
// s1 = exception frame
|
||
//
|
||
|
||
//
|
||
// Interrupts must be disabled before calling KiExceptionExit
|
||
// because the unwind code cannot unwind from that point.
|
||
//
|
||
|
||
FAST_DISABLE_INTERRUPTS
|
||
add s1 = STACK_SCRATCH_AREA, sp
|
||
add s0 = ExceptionFrameLength, sp
|
||
br KiExceptionExit
|
||
;;
|
||
|
||
NESTED_EXIT(KiThreadDispatch)
|