📄 ppctrap.s
字号:
// TITLE("Interrupt and Exception Processing")
//++
//
// Copyright (c) 1996-2000 Microsoft Corporation. All rights reserved.
//
// Module Name:
//
// ppctrap.s
//
// Abstract:
//
// This module implements the code necessary to field and process PowerPC
// interrupt and exception conditions.
//
// WARNING: Some of the code in this module runs with relocation disabled and
// cannot directly reference kernel global data. However, the kernel data page is
// chosen to have the same virtual and physical address (0x5800) and can be used
// with relocation disabled.
//
// Environment:
//
// Kernel mode only.
//
// Revision History:
//
//--
#include "ksppc.h"
#include "nkintr.h"
#include "psyscall.h"
#include "mem_ppc.h"
#include "kpage.h"
//
// Constants
//
#define HwInterruptVector 0x500 // Hardware interrupt vector
#define DecrementerVector 0x900 // Decrementer exception vector
//
// Externs from mdppc.c
//
.extern CEProcessorType // DWORD CEProcessorType;
.extern ProcessorLevel // WORD ProcessorLevel;
.extern ProcessorRevision // WORD ProcessorRevision;
#if 0 // SAVEGP
.globl _gp // Global pointer value set by linker
#endif
.globl KPageBlock
.globl NKSignon
.globl ObjectCall
.globl HandleException
.globl ServerCallReturn
.globl KernelRelocate
.globl OEMInitDebugSerial
.globl OEMInit
.globl OEMWriteDebugString
.globl KernelFindMemory
.globl KernelInit
.globl ExceptionDispatch
#if CELOG
.globl CeLogInterrupt
#endif
#define MSR_CLR_EE(reg)\
rlwinm reg, reg, 0, ~MSR_EE
#define MSR_CLR_ME(reg)\
rlwinm reg, reg, 0, ~MSR_ME
#define MSR_CLR_RI(reg)\
rlwinm reg, reg, 0, ~MSR_RI
#define MSR_CLR_POW(reg) \
rlwinm reg, reg, 0, ~MSR_POW
//
// TLB management routines.
//
// Include the processor-specific TLB management routines here:
//
#if PPC403
#include "ppc403.s"
#endif
#if PPC821
#include "ppc821.s"
#endif
//
// Shared low memory interrupt code
//
// This code is put into the kernel data page so that it can execute
// with relocation enabled or disabled. It performs its initial work without
// relocation and then enables relocation and jumps to the kernel handler in
// the kernel "un-mapped" space.
//
.text
KPageHandlers:
// Low memory API call and return handler.
//
// Prepare a thread for an API call. Since this is a C level function
// call, it is not necessary to save the volatile CPU state.
//
// This code is located in the kernel page at 0x5000 so that it can
// run with relocation enabled or disabled and in kernel mode or user mode.
// The sequence is:
// Entry in kernel mode with relocation disabled
// Enable relocation
// decode the API
// Switch to user mode
// invoke the API or return to API caller
//
// Entry (r3-r10) = API arguments
// (r11) = API call address (SRR0) - FIRST_METHOD
// (r12) = previous Status (SRR1)
// Exit to API dispatch code in kernel with:
// (r1) = kernel stack pointer
// (r11) = API set & index
// (r12) = caller's stack pointer
// Uses r0, r11, r12, CR0, CR5
//
// Fake Prologue required for unwinding. Save GP and RA on stack
//
.set KPageAPIHandler, ($ - KPageHandlers) + LowHandlers
mfmsr r0 // Get current MSR settings
ori r0, r0, (MSR_IR | MSR_DR | MSR_EE | MSR_RI | MSR_ME)
// OR in new bits (in low half word)
mtmsr r0 // enable relocation & interrupts
rlwinm r12, r12, MSR_BIT_PR+1, 1
// (r12) = previous processor mode
cmpwi r11, -APICALL_SCALE
stw r3, CrParameter0(r1) // store args onto the stack
stw r4, CrParameter1(r1) // ...
beq APIReturn // go pop the callstack for an API return
stw r5, CrParameter2(r1) // ...
stw r6, CrParameter3(r1) // ...
stw r7, CrParameter4(r1) // ...
stw r8, CrParameter5(r1) // ...
stw r9, CrParameter6(r1) // ...
stw r10, CrParameter7(r1) // ...
mflr r4 // (r4) = Arg1, return address
addi r5, r1, CrParameter0 // (r5) = Arg2, ptr to API parameters
srawi r6, r11, 2 // (r6) = Arg3, API set & index
stwu r1, -StackFrameHeaderLength-8(r1)
lis r3, [hia]ObjectCall
addi r3, r3, [lo]ObjectCall // (r0) == ptr to ObjectCall
mtctr r3
addi r3, r1, StackFrameHeaderLength
// (r3) = Arg0, ptr to OCALLINFO struct
stw r12, 0(r3) // store previous thread execution mode
stw r2, 4(r3) // store caller's Global pointer
lwz r2, NKGp(0)
bctrl // call ObjectCall(poci, ra, args, iMethod)
// Reload argument registers and invoke an API function.
//
// (r3) = pointer to an API function to invoke (0 if API completed)
lwz r12, StackFrameHeaderLength(r1)
// (r12) = thread mode
lwz r1, 0(r1) // clear working frame from the stack
cmpwi r12, 0
mtctr r3
lwz r3, CrParameter0(r1) // reload argument registers from the stack
lwz r4, CrParameter1(r1) // ...
lwz r5, CrParameter2(r1) // ...
lwz r6, CrParameter3(r1) // ...
lwz r7, CrParameter4(r1) // ...
lwz r8, CrParameter5(r1) // ...
lwz r9, CrParameter6(r1) // ...
lwz r10, CrParameter7(r1) // ...
beq APICall // invoke the function in kernel mode
li r0, SYSCALL_RETURN
mtlr r0 // setup for api return interrupt
mfmsr r0 // Get current MSR
ori r0, r0, (MSR_PR | MSR_EE | MSR_ME)
// Set problem state bit to user mode
mtmsr r0 // switch to user mode
bctr // and jump to the API function
// Invoke an API function in kernel mode. This may be due to the api being a
// kernel function or the thread running in kernel mode.
//
// (ctr) = function address
// (r2) = function's Global pointer
// (r3-r10) = API arguments
APICall:
bctrl // call API function
.set APICallReturn, ($ - KPageHandlers) + LowHandlers
li r12, 0 // (r12) = KERNEL_MODE
stw r3, CrParameter0(r1) // save return value onto the stack
stw r4, CrParameter1(r1) // ...
APIReturn:
stwu r1, -StackFrameHeaderLength-16(r1)
lis r3, [hia]ServerCallReturn
addi r3, r3, [lo]ServerCallReturn
// (r3) = Ptr to ServerCallReturn
mtctr r3
addi r3, r1, StackFrameHeaderLength
// (r3) = Arg0, ptr to OCALLINFO struct
stw r12, 0(r3) // store previous thread execution mode
lwz r2, NKGp(0)
bctrl // call ServerCallReturn(poci)
lwz r12, StackFrameHeaderLength(r1)
// (r12) = thread mode
lwz r2, StackFrameHeaderLength+4(r1)
// (r2) = original caller's Global ptr
lwz r1, 0(r1) // clear working frame from the stack
mtlr r3
cmpwi r12, 0
lwz r3, CrParameter0(r1) // restore return value registers from
// the stack
lwz r4, CrParameter1(r1) // ...
beqlr // return to kernel mode caller
mfmsr r0 // Get current MSR
ori r0, r0, (MSR_PR | MSR_EE | MSR_ME)
// Set problem state bit to user mode,
// enable interrupts and machine check
mtmsr r0 // Switch to user mode
blr // and return
//
// Low memory common interrupt handling code
//
// This code is put into the kernel data page at so that it can execute
// with relocation enabled or disabled. It performs its initial work without
// relocation and then enables relocation and jumps to the kernel handler in
// the kernel "un-mapped" space.
//
//
// KPageHwInterruptHandler - Handler used for decrementer and hw interrupt
// exceptions. The code assumes the following entry and is running w/o
// relocations or interrupts.
//
// (r5) = Address of OEMInterruptHandler or OEMDecrementer
// (SPRG1) = Original r14
// (SPRG2) = Original r5
//
.set KPageHwInterruptHandler, ($ - KPageHandlers) + LowHandlers
lha r14, ReschedFlag(0)
mtspr SPRG3, r0
mfcr r0 // (r0) = saved condition register
subi r14, r14, 256
mtcrf 0x80, r14 // copy r6 sign bit to bit 0 of CR
sth r14, ReschedFlag(0)
lwz r14, CurThdPtr(0) // (r6) = ptr to Current Thread struct
bt- 0, hwh10 // nested interrupt
rlwinm r14, r14, 0, 0x7fffffff // (r6) = real address of THREAD
stw r1, TcxR1(r14)
li r1, KStack // switch to kernel's stack
b hwh15
//
// A nested exception has occured. Create a temporary thread structure
// on the stack and save the current state into that.
//
hwh10:
subi r14, r1, TcxSizeof + STK_SLACK_SPACE
stw r1, TcxR1(r14)
subi r1, r14, StackFrameHeaderLength
hwh15:
stw r0, TcxCr(r14)
stw r3, TcxR3(r14)
stw r4, TcxR4(r14)
mfspr r0, SRR0 // (r0) = faulting instr. address
mfspr r3, SRR1 // (r3) = MSR at fault
stw r0, TcxIar(r14)
stw r3, TcxMsr(r14)
//
// Save the remaining context to allow for C calling convention:
//
// (r14) = non-volatile thread context
// (r5) = Address of OEMInterruptHandler or OEMDecrementer
// (r6) = real address ptr to THREAD
// (SPRG1) = original R14 value
// (SPRG2) = original R5 value
// (SPRG3) = original R0 value
//
// R1, R3, CR, SRR0, & SRR1 saved into THREAD.ctx
//
stw r7, TcxR7(r14)
mfspr r0, SPRG1 // (r0) = original R4 value
mfspr r7, SPRG2 // (r7) = original R5 value
stw r0, TcxR14(r14)
stw r7, TcxR5(r14)
mfspr r0, SPRG3 // (r0) = original R0 value
stw r0, TcxR0(r14)
mfxer r7
stw r7, TcxXer(r14)
mfctr r0
mflr r7
stw r0, TcxCtr(r14)
stw r7, TcxLr(r14)
stw r2, TcxR2(r14) // save Thread's Global pointer
lwz r2, NKGp(0) // (r2) = kernel's GP
stw r6, TcxR6(r14)
stw r8, TcxR8(r14) // save volatile register state
stw r9, TcxR9(r14) // ...
stw r10, TcxR10(r14) // ...
stw r11, TcxR11(r14) // ...
stw r12, TcxR12(r14) // ...
stw r13, TcxR13(r14) // ...
//
// Call the OEM supplied ISR. The ISR requires that relocations be on so
// we use the rfi instruction to simultaneously enable relocations and jump
// to the ISR continue point (ISRContinue). ISRContinue will call the OEM
// supplied ISR code.
//
// (r5) = KSEG address of the ISR (OEMDecrementer or OEMInterruptHandler)
// (r14) = non-volatile thread context
// R0-R11, Cr, Lr, Ctr, SRR0, & SRR1 saved into THREAD.ctx
//
//
// Setup the MSR that will be used while running ISR. We
// need:
//
// - Relocations
// - Interrupts OFF
//
// NOTE: We do not explicitly turn interrupts off because this code enters
// with interrupts off.
//
// (r14) = Non-volatile thread ctx
//
mfmsr r0 // Get current MSR
MSR_CLR_ME(r0) // Machine check off
ori r0, r0, (MSR_IR | MSR_DR | MSR_RI)
// Relocations ON
//
// Setup SRR0 and SRR1 which are used for the rfi instruction
//
lis r3, [hia]IsrContinue // Load address of KSEG ISR continue point
addi r3, r3, [lo]IsrContinue // ...
mtspr SRR1, r0 // MSR at fault
mtspr SRR0, r3 // address of IsrContinue code
oris r14, r14, 0x8000 // (r3) = virtual address of THREAD
rfi // jump to KSEG ISR continue point with relocations
//
// KPageGeneralHandler - General Handler for non-TLB and non-HW related interrupts.
// Exceptions handled include: alignment, machine check, page fault, access
// violation, etc.
//
// (r4) = interrupt type
// (r5) = interrupt data (DAR or SRR0)
// (SPRG1) = original R4 value
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -