📄 ppctrap.s
字号:
// (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 + -