⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ppctrap.s

📁 可用于嵌入式编程学习
💻 S
📖 第 1 页 / 共 5 页
字号:
// (SPRG2) = original R5 value
//

.set KPageGeneralHandler, ($ - KPageHandlers) + LowHandlers
    stw     r6, SaveR6(0)
    lha     r6, ReschedFlag(0)
    mtspr   SPRG3, r0
    mfcr    r0                      // (r0) = saved condition register
    subi    r6, r6, 256
    mtcrf   0x80, r6                // copy r6 sign bit to bit 0 of CR
    sth     r6, ReschedFlag(0)
    lwz     r6, CurThdPtr(0)        // (r6) = ptr to Current Thread struct
    bt-     0, gh10                 // nested interrupt
    rlwinm  r6, r6, 0, 0x7fffffff   // (r6) = real address of THREAD
    stw     r1, TcxR1(r6)
    li      r1, KStack              // switch to kernel's stack
    b   gh15

    //
    // A nested exception has occured. Create a temporary thread structure
    // on the stack and save the current state into that.
    //
    //  (r4) = interrupt type
    //

gh10:
    subi    r6, r1, TcxSizeof + STK_SLACK_SPACE
    stw     r1, TcxR1(r6)
    subi    r1, r6, StackFrameHeaderLength

gh15:
    stw     r0, TcxCr(r6)
    stw     r3, TcxR3(r6)
    mfspr   r0, SRR0                // (r0) = faulting instr. address
    mfspr   r3, SRR1                // (r3) = MSR at fault
    stw     r0, TcxIar(r6)
    stw     r3, TcxMsr(r6)
    oris    r3, r6, 0x8000          // (r3) = virtual address of THREAD

// Handle a fault.
//
//  (r3) = ptr to THREAD (virtual address)
//  (r4) = interrupt type
//  (r5) = interrupt data (DAR or SRR0)
//  (r6) = real address ptr to THREAD
//  (SaveR6) = original R6 value
//  (SPRG1) = original R4 value
//  (SPRG2) = original R5 value
//  (SPRG3) = original R0 value
//  R1, R3, CR, SRR0, & SRR1 saved into THREAD.ctx

    stw     r7, TcxR7(r6)
    mfspr   r0, SPRG1               // (r0) = original R4 value
    mfspr   r7, SPRG2               // (r7) = original R5 value
    stw     r0, TcxR4(r6)
    stw     r7, TcxR5(r6)
    mfspr   r0, SPRG3               // (r0) = original R0 value
    lwz     r7, SaveR6(0)           // (r7) = original R6 value
    stw     r0, TcxR0(r6)
    stw     r7, TcxR6(r6)
    mfxer   r7
    stw     r7, TcxXer(r6)
    mfctr   r0
    mflr    r7
    stw     r0, TcxCtr(r6)
    stw     r7, TcxLr(r6)
    stw     r2, TcxR2(r6)           // save Thread's Global pointer
    lwz     r2, NKGp(0)             // (r2) = kernel's GP
    stw     r8, TcxR8(r6)           // save volatile register state
    stw     r9, TcxR9(r6)           // ...
    stw     r10, TcxR10(r6)         // ...
    stw     r11, TcxR11(r6)         // ...
    stw     r12, TcxR12(r6)         // ...
    stw     r13, TcxR13(r6)         // ...
    stw     r14, TcxR14(r6)         // save R14
    mr      r14, r3                 // (r14) = save pointer to THREAD


//
//  Determine whether load/store occurred, if appropriate
//

#if PPC821
    mfspr   r7, DSISR                           // (r6) = interrupt info
    rlwinm  r6, r7, 6+1, 31, 31                 // Isolate Load/Store bit
#endif

#if PPC403
    mfspr   r7, ESR                             // Exception Status Register

//
//  Map the Program trap bits from the ESR into the architected SRR1 positions:
//

    rlwinm. r0, r7, 32+6-14, 12, 14     // Copy bits to SRR1 positions
    beq     Srr1Zero                    // No bits set; continue
    lwz     r7, TcxMsr(r6)              // Get SRR1 value
    or      r7, r7, r0                  // Insert program trap bits
    stw     r7, TcxMsr(r6)              // and update
Srr1Zero:
    rlwinm  r6, r7, 8+1, 31, 31         // Isolate Load/Store bit

#endif


    //
    // Call HandleException.  This involves turning interrupts and relocations
    // on and jumping to HandleException.  This is done using the PPC rfi mechanism
    // to simultaneously enable interrupts and relocations and jump to
    // HandleException.
    //
    //
    //  (r3) = ptr to THREAD (virtual address)
    //  (r4) = interrupt type
    //  (r5) = interrupt data (DAR or SRR0)
    //  (r14) = Non-volatile thread ctx
    //  R0-R11, Cr, Lr, Ctr, SRR0, & SRR1 saved into THREAD.ctx
    //

    lis     r7, [hia]HandleException    // Get Ptr to HandleException
    addi    r7, r7, [lo]HandleException // ...

    //
    // Setup the MSR that will be used while running HandleException.  We
    // need:
    //
    //  - Relocations
    //  - Interrupts ON
    //

    mfmsr   r0                          // Get current MSR
    MSR_CLR_ME(r0)                      // Machine check off
    ori r0, r0, (MSR_IR | MSR_DR | MSR_RI | MSR_EE)
                                        // Relocation and interrupts on
    mtspr   SRR1, r0                    // MSR that will be used to execute handle
    mtspr   SRR0, r7                    // Address of the HandleException

    //
    // When the HandleException finishes it will return to KSEG address that
    // does the final portion of the interrupt processing.
    //

    lis     r8, [hia]HandleExceptionReturn      // Get Ptr to HandleExceptionReturn
    addi    r8, r8, [lo]HandleExceptionReturn   // ...
    mtlr    r8                                  // Upon return, run out of KSEG
    rfi                                         // jump to HandleException


   .set KPageJumpSwitch, ($ - KPageHandlers) + LowHandlers


//
// KPageJumpSwitch - switch to user mode and jump to user function
//  This code is used to invoke user mode exception handler functions.
//
//  Entry   (r3-r6) = function parameters
//          (r8) = Msr value
//          (ctr) = function address
//          (lr) = return address - 4 (must skip an instruction)
//

//
//

	lwz		r9, CurThdPtr(0)	// (r9) = pCurThread
	addi	r7, r1, CfCstk		// (r7) = pcstk (on our stack)
	lwz		r9, ThPcstkTop(r9)	// (r9) = pCurThread->pcstkTop
	stw		r9, CstkNext(r7)	// pcstk->pcstkNext = pCurThread->pcstkTop
	lwz		r9, CurThdPtr(0)	// (r9) = pCurThread
	stw		r7, ThPcstkTop(r9)	// pCurThread->pcstkTop = pcstk
	mr		r9, r7				// (r9) = pcstk
	mflr	r7
	addi	r7, r7, 4			// (r7) = return address

    li      r0, SYSCALL_RETURN
    stw     r7, CstkRa(r9)
    mtlr    r0                  // set return addr to trap
    li      r0, 0
    stw     r0, CstkPrcLast(r9) // return to kernel mode
    li      r0, 0
    stw     r0, CstkAkyLast(r9)
    mtmsr   r8
    bctr

KPageHandlers.End:
    .set KPageEnd, ($ - KPageHandlers) + LowHandlers


.text

//
// IsrContinue - KPage routine uses rfi to jump to here with relocations enabled
//
//  (r5) = KSEG address of the ISR (OEMDecrementer or OEMInterruptHandler)
//  (r14) = Virtual Address of THREAD
//

IsrContinue:

#if CELOG
        //
        // NOTE : "C" calling convention to CeLogInterrupt
        //
        // I'm assuming that at this point the only register of these that
        // I need to preserve is r5 (ISR address) and that R13 is available
        // as storage (non-volatile for function call)
        //

	mr	r13, r5			// save r5

	lis	r3, 0x8000		// r3 = mark as ISR entry
        bl      CeLogInterrupt		// call CeLogInterrupt function

	mr	r5, r13			// restore r5
#endif

	mtlr	r5			// LR = OEMDecrementer or OEMInterruptHandler address
	blrl				// call OEMDecrementer or OEMInterruptHandler

	//
	// Return from ISR
	//
	// (r3) = SYSINTR value
	//

    lwz     r4, TcxMsr(r14)
    MSR_CLR_POW(r4)
    stw     r4, TcxMsr(r14)


    //
    // Disable interrupts so that the setting of necessary reschedule flags
    // and PendEvents is atomic
    //

    mfmsr   r4                          // Get the MSR
    MSR_CLR_EE(r4)                      // Clear External Interrupts bit
    mtmsr   r4                          // Write back MSR

#if CELOG
        //
        // NOTE : "C" calling convention to CeLogInterrupt
        //
        // I'm assuming that at this point the only register of these that
        // I need to preserve is r3 (SYSINTR value) and that R13 is available
        // as storage (non-volatile for function call)
        //
        mr      r13, r3                 // save copy of R3
        lbz     r4, KNest(0)            // Get Nesting level
        extsb.  r4, r4                  // Sign extend KNest byte
        neg     r4, r4
        rlwinm  r4, r4, 16, 0, 31       // r4 = r4 << 16
        or      r3, r3, r4              // r3 = (-cNest << 16) | SYSINTR_val
        bl      CeLogInterrupt

        mr      r3, r13                 // restore R3

#endif

    //
    // Load up constant 1
    //

    li      r10, 1

	//
	// Dispatch to specific handler.  The default is a hardware interrupt.
	//		

    cmpwi   r3, SYSINTR_BREAK           // Check for a SYSINTR_BREAK
    beq     SysintrBreak                // ...
    cmpwi   r3, SYSINTR_NOP             // Check for a SYSINTR_NOP
    beq     SysintrNop                  // ...
    cmpwi   r3, SYSINTR_RESCHED         // Check for a SYSINTR_RESCHED
    beq     SysintrResched              // ...

SysintrDevice:

    //
    // If none of the other match, we have a device interrupt. The code block
    // below implements the following algorithm:
    //
    //      - Subtract SYSINTR_DEVICES from the ISR returned SYSINTR
    //      - Shift 1 left by this returned value and OR the resulting
    //        mask into PendEvents
    //

    subi    r11,r3,SYSINTR_DEVICES      // convert to Device ID
    cmpwi   r11, SYSINTR_MAX_DEVICES
    bge-    SysintrResched              // if r3 > SYSINTR_MAX_DEVICES, continue

    lwz     r9,PendEvents(0)            // Load current PendEvents
    slw     r11,r10,r11                 // (1 << SYSINTR - SYSINTR_DEVICES)
    or      r11,r11,r9                  // Or interrupt back into PendEvents
    stw     r11,PendEvents(0)           // Write PendEvents back

SysintrResched:

    //
    // Handle the reschedule case.  This will be entered through a device
    // interrupt or a direct SYSINTR_RESCHED
    //

	stb	    r10, ReschedFlag(0)         // set reschedule flag

SysintrNop:

    //
    // All paths fall through to the SYSINTR_NOP handler.  This includes
    // a SYSINTR_DEVICE, a SYSINTR_RESCHED and SYSINTR_NOP.
    //

    lwz     r3, ReschedFlag(0)          // Load ReschedFlag + KNest
    cmpwi   r3, 1                       // Compare flag to 1
    bne	    ContinueCurThread           // no reschedule
    lbz     r3, KNest(0)                // Get Nesting level
    extsb.  r3, r3                      // Sign extend KNest byte
    beq     Reschedule                  // Continue our current thread
    b       ContinueCurThread           // Reschedule

SysintrBreak:

    //
    // The break button has been pushed. Call HandleException with a FAKE
    // interrupt ID of ID_HW_BREAK
    //

    mr      r3, r14                     // Load context record in arg1
    .lwi    r4, ID_HW_BREAK             // HW break type exception
    bl      HandleException             // Call general exception handler

HandleExceptionReturn:

    //
    // (r14) contains the current thread
    //

    cmpwi   r3, 0                       // HandleException returns TRUE for cont
    bne     ContinueCurThread           // If value is TRUE, continue current thrd

Reschedule:

    //
    // Generic reschedule point. Several sources jump to this point to
    // trigger a reschedule.  It also is the result of returned reschedule
    // condition from HandleException.
    //
    //  (r14) = Contains the current thread context
    //


    mfmsr   r0                          // Get current MSR
    ori     r0, r0, MSR_EE              // Interrupts On
    mtmsr   r0                          // Update MSR


    //
    // Check for power off
    //

    lbz     r3, BPowerOff(0)            // Load current value of BPowerOff
    cmpwi   r3, 0                       // Sign Extend
    beq     CheckResched                // If power off is not needed check for resched
    bl      DoPowerOff                  // Call Kernels power down routine.
    li      r3, 0                       // Get zero register
    stb     r3, BPowerOff(0)            // Clear Power off


CheckResched:

    lbz     r5, ReschedFlag(0)          // Load the reschedule flag
    cmpwi   r5, 0                       // Sign extend the reschedule flag
    beq     CheckKCResched              // If resched not set,check KCResched
    li      r3, 0                       // Get zero register
    stb     r3, ReschedFlag(0)          // Clear reschedule flag
    bl      NextThread                  // Call Next Thread and let the scheduler do its thing

CheckKCResched:

    lwz     r4, dwKCRes(0)              // Load the KCResched Flag

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -