You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
7.8 KiB
267 lines
7.8 KiB
// 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)
|