// TITLE( "Start System" ) //++ // // Copyright (c) 1992 Digital Equipment Corporation // // Module: // // start.s // // Abstract: // // This module implements the code necessary to iniitially start NT // on an alpha - it includes the routine that first receives control // when the loader executes the kernel. // // Author: // // Joe Notarangelo 02-Apr-1992 // // Environment: // // Kernel Mode only. // // Revision History: // //-- #include "ksalpha.h" // // Define the total frame size. // #define TotalFrameLength (KERNEL_STACK_SIZE - (TrapFrameLength + \ ExceptionFrameLength) ) // // Define variables to hold the address of the PCR and current thread // on uniprocessor systems. // .data #ifdef NT_UP .globl KiPcrBaseAddress KiPcrBaseAddress: .quad 0 : 1 .globl KiCurrentThread KiCurrentThread: .quad 0 : 1 #endif //NT_UP SBTTL( "System Startup" ) //++ // // Routine Description: // // This routine represents the final stage of the loader and is also // executed as each additional processor is brought online is a multi- // processor system. It is responsible for installing the loaded PALcode // image and transfering control kernel startup code. // // N.B. This code assumes that the I-cache is coherent. // // N.B. This routine does not execute in the context of the operating // system but instead executes in the context of the firmware // PAL environment. This routine can only use those services // guaranteed to exist in the firmware. The only PAL services // that can be counted on are: swppal, imb, and halt. // // Arguments: // // a0 - Supplies pointer to loader parameter block. // // Return Value: // // None. // //-- .struct 0 SsRa: .space 8 // Save ra .space 8 // for stack alignment SsFrameLength: // NESTED_ENTRY(KiSystemStartup, SsFrameLength, ra) ALTERNATE_ENTRY(KiStartProcessor) lda sp, -SsFrameLength(sp) // allocate stack frame stq ra, SsRa(sp) // save return address PROLOGUE_END // // Save the loader block address in a register that is preserved during // the pal swap. // ldl s0, LpbPcrPage(a0) // get PCR page frame number LDIP s1, KSEG0_BASE // get kseg0 base address bis a0, zero, s2 // ldl s3, LpbPdrPage(s2) // get pdr page number sll s3, PAGE_SHIFT, s3 // compute virtual address of PDR bis s3, s1, s3 // // // Swap PAL code and enter the kernel initialization routine. // // a0 - Physical base address of PAL. // a1 - Page frame number of PCR. // a2 - The virtual address of the PDR (AXP64 systems only). // ra - Return address from PAL call. // LDP a0, LpbPalBaseAddress(s2) // get PAL base address sll a0, 32 + 3, a0 // clear upper address bits srl a0, 32 + 3, a0 // bis s0, zero, a1 // set PCR page frame number bis s3, zero, a2 // set level 1 page directory address lda ra, KiStartupContinue // set return address SWPPAL // swap PAL images // // Control should never get here! // ldq ra, SsRa(sp) // Restore ra lda sp, SsFrameLength(sp) // Restore stack pointer ret zero, (ra) // shouldn't get here .end KiSystemStartup SBTTL( "Startup Continue" ) //++ // // Routine Description: // // This routine is called when NT begins execution after loading the // Kernel environment from the PAL. It registers exception routines // and system values with the pal code, calls kernel initialization // and falls into the idle thread code. // // Arguments: // // s0 - Supplies the PCR page frame number. // // s1 - Supplies the base address of KSEG0. // // s2 - Supplies a pointer to the loader parameter block. // // s3 - Supplies the virtual address of the PDR. // // Return Value: // // None. // //-- LEAF_ENTRY(KiStartupContinue) // // Set kernel stack pointer and kernel global pointer from loader // parameter block. // LDP sp, LpbKernelStack(s2) // set kernel stack pointer LDP gp, LpbGpBase(s2) // set kernel global pointer // // Initialize PAL values, sp, gp, pcr, pdr, initial thread. // // sp - Kernel stack pointer. // gp - System global pointer. // a0 - Page directory (PDR) address. // a1 - Idle thread address. // a2 - Idle thread Teb address. // a3 - Panic stack address. // a4 - Maximum kernel stack allocation size. // bis s3, zero, a0 // set level 1 page directory address LDP a1, LpbThread(s2) // get idle thread address bis zero, zero, a2 // zero Teb for initial thread LDP a3, LpbPanicStack(s2) // get panic stack base ldil a4, TotalFrameLength // set maximum kernel stack size INITIALIZE_PAL // // Save copies of the per processor values in global variables for // uniprocessor systems. // sll s0, PAGE_SHIFT, s0 // compute physical address of pcr bis s0, s1, s0 // compute address of pcr #ifdef NT_UP lda t0, KiPcrBaseAddress // save PCR address STP s0, 0(t0) // LDP t1, LpbThread(s2) // get idle thread address lda t0, KiCurrentThread // save idle thread address STP t1, 0(t0) // #endif //NT_UP #if 0 lda a0, BdSystemName // set system name address bis zero, zero, a1 // set system base address lda a2, BdDebugOptions // set debug options address bsr ra, BdInitDebugger // initialize special debugger bsr ra, DbgBreakPoint // break into debugger #endif // // Register kernel exception entry points with the PALcode. // lda a0, KiPanicException // bugcheck entry point ldil a1, entryBugCheck // WRITE_KERNEL_ENTRY_POINT // lda a0, KiGeneralException // general exception entry point ldil a1, entryGeneral // WRITE_KERNEL_ENTRY_POINT // lda a0, KiMemoryManagementException // memory mgmt exception entry ldil a1, entryMM // WRITE_KERNEL_ENTRY_POINT // lda a0, KiInterruptException // interrupt exception entry point ldil a1, entryInterrupt // WRITE_KERNEL_ENTRY_POINT // lda a0, KiSystemServiceException // syscall entry point ldil a1, entrySyscall // WRITE_KERNEL_ENTRY_POINT // // // Initialize fields in the pcr. // ldil t1, PCR_MINOR_VERSION // get minor version ldil t2, PCR_MAJOR_VERSION // get major version stl t1, PcMinorVersion(s0) // store minor version number stl t2, PcMajorVersion(s0) // store major version number LDP t0, LpbThread(s2) // save idle thread in pcr STP t0, PcIdleThread(s0) // LDP t0, LpbPanicStack(s2) // save panic stack in pcr STP t0, PcPanicStack(s0) // ldl t0, LpbProcessorType(s2) // save processor type in pcr stl t0, PcProcessorType(s0) // ldl t0, LpbProcessorRevision(s2) // save processor revision stl t0, PcProcessorRevision(s0) // ldl t0, LpbPhysicalAddressBits(s2) // save physical address bits stl t0, PcPhysicalAddressBits(s0) // ldl t0, LpbMaximumAddressSpaceNumber(s2) // save max asn stl t0, PcMaximumAddressSpaceNumber(s0) // ldl t0, LpbFirstLevelDcacheSize(s2) // save first level dcache size stl t0, PcFirstLevelDcacheSize(s0) // ldl t0, LpbFirstLevelDcacheFillSize(s2) // save dcache fill size stl t0, PcFirstLevelDcacheFillSize(s0) // ldl t0, LpbFirstLevelIcacheSize(s2) // save first level icache size stl t0, PcFirstLevelIcacheSize(s0) // ldl t0, LpbFirstLevelIcacheFillSize(s2) // save icache fill size stl t0, PcFirstLevelIcacheFillSize(s0) // ldl t0, LpbSystemType(s2) // save system type stl t0, PcSystemType(s0) // ldl t0, LpbSystemType+4(s2) // stl t0, PcSystemType+4(s0) // ldl t0, LpbSystemVariant(s2) // save system variant stl t0, PcSystemVariant(s0) // ldl t0, LpbSystemRevision(s2) // save system revision stl t0, PcSystemRevision(s0) // ldl t0, LpbSystemSerialNumber(s2) // save system serial number stl t0, PcSystemSerialNumber(s0) // ldl t0, LpbSystemSerialNumber+4(s2) // stl t0, PcSystemSerialNumber+4(s0) // ldl t0, LpbSystemSerialNumber+8(s2) // stl t0, PcSystemSerialNumber+8(s0) // ldl t0, LpbSystemSerialNumber+12(s2) // stl t0, PcSystemSerialNumber+12(s0) // ldl t0, LpbCycleClockPeriod(s2) // save cycle counter period stl t0, PcCycleClockPeriod(s0) // LDP t0, LpbRestartBlock(s2) // save Restart Block address STP t0, PcRestartBlock(s0) // ldq t0, LpbFirmwareRestartAddress(s2) // save firmware restart stq t0, PcFirmwareRestartAddress(s0) // ldl t0, LpbFirmwareRevisionId(s2) // save firmware revision stl t0, PcFirmwareRevisionId(s0) // LDP t0, LpbDpcStack(s2) // save Dpc Stack address STP t0, PcDpcStack(s0) // LDP t0, LpbPrcb(s2) // save Prcb address STP t0, PcPrcb(s0) // stl zero, PbDpcRoutineActive(t0) // clear DPC Active flag stl zero, PcMachineCheckError(s0) // indicate no HAL mchk handler // // Set system service dispatch address limits used by get and set context. // lda t0, KiSystemServiceDispatchStart // set start address of range STP t0, PcSystemServiceDispatchStart(s0) // lda t0, KiSystemServiceDispatchEnd // set end address of range STP t0, PcSystemServiceDispatchEnd(s0) // // // Initialize the system. // LDP a0, LpbProcess(s2) // get idle process address LDP a1, LpbThread(s2) // get idle thread address bis a1, zero, s1 // save idle thread address LDP a2, LpbKernelStack(s2) // get idle thread stack LDP a3, LpbPrcb(s2) // get processor block address bis a3, zero, s0 // save processor block address LoadByte(a4, PbNumber(a3)) // get processor number bis s2, zero, a5 // get loader parameter block bsr ra, KiInitializeKernel // initialize system data // // Set the wait IRQL of the idle thread, and lower IRQL to DISPATCH_LEVEL. // ldil a0, DISPATCH_LEVEL // get dispatch level IRQL StoreByte(a0, ThWaitIrql(s1)) // set wait IRQL of idle thread bsr ra, KeLowerIrql // lower IRQL ENABLE_INTERRUPTS // enable interrupts bis zero, zero, ra // set bogus RA to stop debugger br zero, KiIdleLoop // continue in idle loop .end KiStartupContinue // // The following code represents the idle loop for all processors. The idle // loop executes at DISPATCH_LEVEL and continually polls for work. // NESTED_ENTRY(KiIdleLoop, ExceptionFrameLength, zero) lda sp, -ExceptionFrameLength(sp) // allocate context frame stq ra, ExIntRa(sp) // set bogus RA to stop debugger PROLOGUE_END lda t0, KiIdleReturn // set swap context return address stq t0, ExSwapReturn(sp) // // // Lower IRQL back to DISPATCH_LEVEL and restore global register values. // // N.B. The address of the current processor block (s0) is preserved across // the switch from idle call. // KiIdleReturn: // ldil a0, DISPATCH_LEVEL // set IRQL to dispatch level SWAP_IRQL // #if DBG bis zero, zero, s2 // reset breakin loop counter #endif lda s3, PbDpcListHead(s0) // get DPC listhead address #if !defined(NT_UP) ldil s4, LockQueueDispatcherLock * 2 // compute per processor SPADDP s4, s0, s4 // lock queue entry address lda s4, PbLockQueue(s4) // lda s5, KiDispatcherLock // get address of dispatcher lock #endif // // Continually scan for debugger break in, a nonempty DPC list, or a new // thread ready for execution. // IdleLoop: // #if DBG subl s2, 1, s2 // decrement breakin loop counter bge s2, 5f // if ge, not time for breakin check ldil s2, 200 * 1000 // set breakin loop counter bsr ra, KdPollBreakIn // check if breakin is requested beq v0, 5f // if eq, then no breakin requested lda a0, DBG_STATUS_CONTROL_C // bsr ra, DbgBreakPointWithStatus // 5: // #endif //DBG // // Disable interrupts and check if there is any work in the DPC list // of the current processor or a target processor. // CheckDpcList: // ENABLE_INTERRUPTS // give interrupts a chance DISABLE_INTERRUPTS // to interrupt spinning // // Process the deferred procedure call list for the current processor. // ldl t0, PbDpcQueueDepth(s0) // get current queue depth beq t0, CheckNextThread // if eq, DPC list is empty // // Clear dispatch interrupt. // ldil a0, DISPATCH_LEVEL //clear any pending software interrupts ldl t0, PbSoftwareInterrupts(s0) // bic t0, a0, t1 stl t1, PbSoftwareInterrupts(s0) // DEASSERT_SOFTWARE_INTERRUPT // clear any PAL-requested interrupts. bsr ra, KiRetireDpcList // process the DPC list #if DBG bis zero, zero, s2 // clear breakin loop counter #endif // // Check if a thread has been selected to run on this processor. // CheckNextThread: // LDP a0, PbNextThread(s0) // get address of next thread object beq a0, IdleProcessor // if eq, no thread selected // // A thread has been selected for execution on this processor. Acquire // dispatcher database lock, get the thread address again (it may have // changed), clear the address of the next thread in the processor block, // and call swap context to start execution of the selected thread. // // N.B. If the dispatcher database lock cannot be obtained immediately, // then attempt to process another DPC rather than spinning on the // dispatcher database lock. // // N.B. This is a very special acquire of the dispatcher lock in that it // will not be acquired unless it is free. Therefore, it is known // that there cannot be any queued lock requests. // #if !defined(NT_UP) 130: LDP_L t0, 0(s5) // get current lock value bis s4, zero, t1 // set lock ownership value bne t0, CheckDpcList // if ne, spin lock owned STP_C t1, 0(s5) // set spin lock owned beq t1, 135f // if eq, store conditional failed mb // synchronize reads after acquire bis s5, LOCK_QUEUE_OWNER, t0 // set lock owner bit in lock entry STP t0, LqLock(s4) // #endif // // Raise IRQL to sync level and re-enable interrupts // ldl a0, KiSynchIrql // SWAP_IRQL // ENABLE_INTERRUPTS // LDP s2, PbNextThread(s0) // get address of next thread LDP s1, PbIdleThread(s0) // get address of current thread STP zero, PbNextThread(s0) // clear next thread address STP s2, PbCurrentThread(s0) // set address of current thread // // Set new thread's state to running. Note this must be done under the // dispatcher lock so that KiSetPriorityThread sees the correct state. // ldil t0, Running // set thread state to running StoreByte(t0, ThState(s2)) // // // Acquire the context swap lock so the address space of the old thread // cannot be deleted and then release the dispatcher database lock. In // this case the old thread is the idle thread, but the context swap code // releases the context swap lock so it must be acquired. // // N.B. This lock is used to protect the address space until the context // switch has sufficiently progressed to the point where the address // space is no longer needed. This lock is also acquired by the reaper // thread before it finishes thread termination. // #if !defined(NT_UP) ldil a0, LockQueueContextSwapLock * 2 // compute per processor SPADDP a0, s0, a0 // lock queue entry address lda a0, PbLockQueue(a0) // bsr ra, KeAcquireQueuedSpinLockAtDpcLevel // acquire context swap lock bis s4, zero, a0 // set lock queue endtry address bsr ra, KeReleaseQueuedSpinLockFromDpcLevel // release dispatcher lock #endif // // Swap context to the new thread from the idle thread. // // N.B. Control returns directly from this call to the top of the idle // loop. // bsr ra, SwapFromIdle // swap context to new thread br zero, KiIdleReturn // control should not reach here // // There are no entries in the DPC list and a thread has not been selected // for execution on this processor. Call the HAL so power management can // be performed. // // N.B. The HAL is called with interrupts disabled. The HAL will return // with interrupts enabled. // IdleProcessor: // lda ra, IdleLoop // set return address lda a0, PbPowerState(s0) // Get the Pointer to the current // C State Handler and Jump to it. // The Handler that gets called expects // A0 to contain the PState pointer. LDP t0, PpIdleFunction(a0) jmp zero, (t0) // // // Conditional store of dispatcher lock failed. Retry. Do not spin in cache // here. If the lock is owned, we want to check the DPC list again. // #if !defined(NT_UP) 135: ENABLE_INTERRUPTS // enable interrupts DISABLE_INTERRUPTS // disable interrupts br zero, 130b // try again #endif .end KiIdleLoop SBTTL("Retire Deferred Procedure Call List") //++ // // Routine Description: // // This routine is called to retire the specified deferred procedure // call list. // // N.B. Interrupts must be disabled entry to this routine. Control is // returned to the caller with the same conditions true. // // Arguments: // // s0 - Address of the processor control block. // // Return value: // // None. // //-- .struct 0 DpRa: .space 8 // return address .space 8 // fill DpcFrameLength: // frame length NESTED_ENTRY(KiRetireDpcList, DpcFrameLength, zero) lda sp, -DpcFrameLength(sp) // allocate stack frame stq ra, DpRa(sp) // save return address PROLOGUE_END // // Process the DPC list. // 10: ldl t0, PbDpcQueueDepth(s0) // get current DPC queue depth beq t0, 60f // if eq, list is empty 15: stl t0, PbDpcRoutineActive(s0) // set DPC routine active lda t2, PbDpcListHead(s0) // compute DPC list head address #if !defined(NT_UP) 20: LDP_L t1, PbDpcLock(s0) // get current lock value bis s0, zero, t3 // set lock ownership value bne t1, 25f // if ne, spin lock owned STP_C t3, PbDpcLock(s0) // set spin lock owned beq t3, 25f // if eq, store conditional failed mb // synchronize memory access ldl t0, PbDpcQueueDepth(s0) // get current DPC queue depth beq t0, 50f // if eq, DPC list is empty #endif LDP a0, LsFlink(t2) // get address of next entry LDP t1, LsFlink(a0) // get address of next entry lda a0, -DpDpcListEntry(a0) // compute address of DPC object STP t1, LsFlink(t2) // set address of next in header STP t2, LsBlink(t1) // set address of previous in next LDP a1, DpDeferredContext(a0) // get deferred context argument LDP a2, DpSystemArgument1(a0) // get first system argument LDP a3, DpSystemArgument2(a0) // get second system argument LDP t1, DpDeferredRoutine(a0) // get deferred routine address STP zero, DpLock(a0) // clear DPC inserted state subl t0, 1, t0 // decrement DPC queue depth stl t0, PbDpcQueueDepth(s0) // update DPC queue depth #if DBG stl zero, PbDebugDpcTime(s0) // clear the time spent in dpc #endif #if !defined(NT_UP) mb // synchronize previous writes STP zero, PbDpcLock(s0) // set spinlock not owned #endif ENABLE_INTERRUPTS // enable interrupts jsr ra, (t1) // call DPC routine DISABLE_INTERRUPTS // disable interrupts br zero, 10b // // // Unlock DPC list and clear DPC active. // 50: // #if !defined(NT_UP) mb // synchronize previous writes STP zero, PbDpcLock(s0) // set spin lock not owned #endif 60: stl zero, PbDpcRoutineActive(s0) // clear DPC routine active stl zero, PbDpcInterruptRequested(s0) // clear DPC interrupt requested // // Check one last time that the DPC list is empty. This is required to // close a race condition with the DPC queuing code where it appears that // a DPC routine is active (and thus an interrupt is not requested), but // this code has decided the DPC list is empty and is clearing the DPC // active flag. // #if !defined(NT_UP) mb // #endif ldl t0, PbDpcQueueDepth(s0) // get current DPC queue depth bne t0, 65f // if ne, DPC list not empty ldq ra, DpRa(sp) // restore return address lda sp, DpcFrameLength(sp) // deallocate stack frame ret zero, (ra) // return 65: br zero, 15b // #if !defined(NT_UP) 25: LDP t1, PbDpcLock(s0) // spin in cache until lock free beq t1, 20b // retry spinlock br zero, 25b // #endif .end KiRetireDpcList #if 0 SBTTL("Initialize Traps") //++ // // Routine Description: // // This function connects the PAL code to the boot debugger trap // routines. // // Arguments: // // None. // // Return Value: // // None. // //-- NESTED_ENTRY(BdInitializeTraps, 8, ra) lda sp, -8(sp) // allocate stack frame stq ra, 0(sp) // save return address lda a0, BdGeneralException // general exception entry point ldil a1, entryGeneral // WRITE_KERNEL_ENTRY_POINT // lda a0, BdMemoryManagementException // memory mgmt exception entry ldil a1, entryMM // WRITE_KERNEL_ENTRY_POINT // ldq ra, 0(sp) // restore return address lda sp, 8(sp) // deallocate stack frame ret zero, (ra) // return .end BdInitializeTraps SBTTL("General Exception Dispatch") //++ // // Routine Description: // // The following code is never executed. Its purpose is to allow the // kernel debugger to walk call frames backwards through an exception // to support unwinding through exceptions for system services, and to // support get/set user context. // // N.B. The volatile registers must be saved in this prologue because // the compiler will occasionally generate code that uses volatile // registers to save the contents of nonvolatile registers when // a function only calls another function with a known register // signature (such as _OtsDivide). // //-- NESTED_ENTRY(BdGeneralExceptionDispatch, TrapFrameLength, zero) .set noreorder stq sp, TrIntSp(sp) // save stack pointer stq ra, TrIntRa(sp) // save return address stq ra, TrFir(sp) // save return address stq fp, TrIntFp(sp) // save frame pointer stq gp, TrIntGp(sp) // save global pointer bis sp, sp, fp // set frame pointer .set reorder stq v0, TrIntV0(sp) // save integer register v0 stq t0, TrIntT0(sp) // save integer registers t0 - t7 stq t1, TrIntT1(sp) // stq t2, TrIntT2(sp) // stq t3, TrIntT3(sp) // stq t4, TrIntT4(sp) // stq t5, TrIntT5(sp) // stq t6, TrIntT6(sp) // stq t7, TrIntT7(sp) // stq a4, TrIntA4(sp) // save integer registers a4 - a5 stq a5, TrIntA5(sp) // stq t8, TrIntT8(sp) // save integer registers t8 - t12 stq t9, TrIntT9(sp) // stq t10, TrIntT10(sp) // stq t11, TrIntT11(sp) // stq t12, TrIntT12(sp) // .set noat stq AT, TrIntAt(sp) // save integer register AT .set at PROLOGUE_END //++ // // Routine Description: // // PALcode dispatches to this kernel entry point when a "general" // exception occurs. These general exceptions are any exception // other than an interrupt, system service call or memory management // fault. The types of exceptions that will dispatch through this // routine will be: breakpoints, unaligned accesses, machine check // errors, illegal instruction exceptions, and arithmetic exceptions. // The purpose of this routine is to save the volatile state and // enter the common exception dispatch code. // // Arguments: // // fp - Supplies a pointer to the trap frame. // gp - Supplies a pointer to the system short data area. // sp - Supplies a pointer to the trap frame. // a0 = Supplies a pointer to the exception record. // a3 = Supplies the previous psr. // // Note: Control registers, ra, sp, fp, gp have already been saved // argument registers a0-a3 have been saved as well // //-- ALTERNATE_ENTRY(BdGeneralException) bsr ra, KiGenerateTrapFrame // store volatile state br ra, BdExceptionDispatch // handle the exception .end BdGeneralExceptionDispatch SBTTL("Exception Dispatch") //++ // // Routine Description: // // This routine begins the common code for raising an exception. // The routine saves the non-volatile state and dispatches to the // next level exception dispatcher. // // Arguments: // // fp - Supplies a pointer to the trap frame. // sp - Supplies a pointer to the trap frame. // a0 = Supplies a pointer to the exception record. // a3 = Supplies the previous psr. // // gp, ra - saved in trap frame // a0-a3 - saved in trap frame // // Return Value: // // None. // //-- NESTED_ENTRY(BdExceptionDispatch, ExceptionFrameLength, zero ) // // Build exception frame // lda sp, -ExceptionFrameLength(sp) // allocate exception frame stq ra, ExIntRa(sp) // save ra stq s0, ExIntS0(sp) // save integer registers s0 - s5 stq s1, ExIntS1(sp) // stq s2, ExIntS2(sp) // stq s3, ExIntS3(sp) // stq s4, ExIntS4(sp) // stq s5, ExIntS5(sp) // stt f2, ExFltF2(sp) // save floating registers f2 - f9 stt f3, ExFltF3(sp) // stt f4, ExFltF4(sp) // stt f5, ExFltF5(sp) // stt f6, ExFltF6(sp) // stt f7, ExFltF7(sp) // stt f8, ExFltF8(sp) // stt f9, ExFltF9(sp) // PROLOGUE_END ldil a4, TRUE // first chance to true bis zero, zero, a3 // set previous mode bis fp, zero, a2 // set pointer to trap frame bis sp, zero, a1 // set pointer to exception frame lda a0, TrExceptionRecord(fp) // set address of exception record LDP t0, BdDebugRoutine // get address of debug routine jsr ra, (t0) // call kernel debugger ldq s0, ExIntS0(sp) // restore integer registers s0 - s5 ldq s1, ExIntS1(sp) // ldq s2, ExIntS2(sp) // ldq s3, ExIntS3(sp) // ldq s4, ExIntS4(sp) // ldq s5, ExIntS5(sp) // ldl a0, TrPsr(fp) // get previous psr bsr ra, KiRestoreNonVolatileFloatState // restore nv float state bsr ra, KiRestoreTrapFrame // restore volatile state bis zero, zero, a1 // assume softwareinterrupt requested // // a0 = previous psr // a1 = sfw interrupt requests // RETURN_FROM_TRAP_OR_INTERRUPT // return from exception .end BdExceptionDispatch SBTTL("Memory Management Exception Dispatch") //++ // // Routine Description: // // The following code is never executed. Its purpose is to allow the // kernel debugger to walk call frames backwards through an exception // to support unwinding through exceptions for system services, and to // support get/set user context. // // N.B. The volatile registers must be saved in this prologue because // the compiler will occasionally generate code that uses volatile // registers to save the contents of nonvolatile registers when // a function only calls another function with a known register // signature (such as _OtsMove). // //-- NESTED_ENTRY(BdMemoryManagementDispatch, TrapFrameLength, zero) .set noreorder stq sp, TrIntSp(sp) // save stack pointer stq ra, TrIntRa(sp) // save return address stq ra, TrFir(sp) // save return address stq fp, TrIntFp(sp) // save frame pointer stq gp, TrIntGp(sp) // save global pointer bis sp, sp, fp // set frame pointer .set reorder stq v0, TrIntV0(sp) // save integer register v0 stq t0, TrIntT0(sp) // save integer registers t0 - t7 stq t1, TrIntT1(sp) // stq t2, TrIntT2(sp) // stq t3, TrIntT3(sp) // stq t4, TrIntT4(sp) // stq t5, TrIntT5(sp) // stq t6, TrIntT6(sp) // stq t7, TrIntT7(sp) // stq a4, TrIntA4(sp) // save integer registers a4 - a5 stq a5, TrIntA5(sp) // stq t8, TrIntT8(sp) // save integer registers t8 - t12 stq t9, TrIntT9(sp) // stq t10, TrIntT10(sp) // stq t11, TrIntT11(sp) // stq t12, TrIntT12(sp) // .set noat stq AT, TrIntAt(sp) // save integer register AT .set at PROLOGUE_END //++ // // Routine Description: // // This routine is called from the PALcode when a translation not valid // fault or an access violation is encountered. This routine will // call MmAccessFault to attempt to resolve the fault. If the fault // cannot be resolved then the routine will dispatch to the exception // dispatcher so the exception can be raised. // // Arguments: // // fp - Supplies a pointer to the trap frame. // gp - Supplies a pointer to the system short data area. // sp - Supplies a pointer to the trap frame. // a0 = Supplies the load/store indicator, 1 = store, 0 = load. // a1 = Supplies the bad virtual address. // a2 = Supplies the previous mode. // a3 = Supplies the previous psr. // // gp, ra - saved in trap frame // a0-a3 - saved in trap frame // // Return Value: // // None. // //-- ALTERNATE_ENTRY(BdMemoryManagementException) bsr ra, KiGenerateTrapFrame // store volatile state STP a0, TrExceptionRecord + ErExceptionInformation(fp) // set load/store #if defined(_AXP64_) stq a1, TrExceptionRecord + ErExceptionInformation + 8(fp) // set bad va #else stl a1, TrExceptionRecord + ErExceptionInformation + 4(fp) // set bad va #endif lda a0, TrExceptionRecord(fp) // get exception record address ldil v0, STATUS_ACCESS_VIOLATION // get access violation code stl v0, ErExceptionCode(a0) // save exception code stl zero, ErExceptionFlags(a0) // set exception flags STP zero, ErExceptionRecord(a0) // set associated record bis zero, 2, t0 // set number of parameters stl t0, ErNumberParameters(a0) // set number of parameters br ra, BdExceptionDispatch // dispatch exception .end BdMemoryManagementDispatch #endif