📄 shexcept.src
字号:
mov #h'e0, r1 ; (r1) = address error load/excecute code
cmp/eq r1, r0
; Skip the Syscall process if it is not an address error
bf/s geh30 ; not an address error,
or #h'20, r0 ; turn TLB load into 0x60 instead of 0x40
; Address error on load or execute: check if system call. System calls are generated as
; a jump to an odd address at the high end of the address space.
mov #FIRST_METHOD, r1
stc SPC, r0
mov #API_MAX, r3 ; (r3) = lower bound of API addresses
tst #1, r0
; Skip the Syscall process and jump to the code which handles other general
; exceptions.
bt geh35 ; SPC even: not a system call
cmp/hs r3, r0 ; 'T' set iff SPC >= API_MAX
; Skip the Syscall process and jump to the code which handles other general
; exceptions.
bf geh35 ; address is outside of API range
; Yes, this is a syscall!
sub r1, r0
shar r0 ; (r0) = method index
stc SSR, r2 ; (r2) = previous status
mov #PR_B0_IE, r1
; Preserve the methed index and saved SR by placing them on bank 0 registers.
; (remember we are still in bank 1 now :)
ldc r0, r3_user ; pass method index
ldc r2, r2_user ; pass previous mode
.aif SH_CPU eq h'30
; Preserve the DSP specific bits in the saved SR
; Obtain the DSP specific SR Mask
mov #SR_DSP_MASK, r3
; Mask out non-DSP specific bits. (r2) = DSP specific SR bits
and r3, r2
; Prepare to merge the DSP bits back to the current SR
or r2, r1
.aendi
; Switch to bank 0 and enable the interrupt
ldc r1, SR ; (SR) = privileged, bank 0, unblocked
; jump to the handler
mov #SyscallHandler, r1
jmp @r1
nop
.endf
;++
; The following code is never executed. Its purpose is to support unwinding
; through the call to the exception dispatcher.
;--
NESTED_ENTRY GeneralException
;;add #CtxR8-CtxSizeof, r14 ; (r14) = ptr to CtxR8
mov.l r14, @(CtxR14-CtxR8,r14) ; save R14
mov.l r15, @(CtxR15-CtxR8,r14) ; save stack pointer
stc SSR, r1
mov.l r1, @(CtxPsr-CtxR8,r14) ; save processor status
stc SPC, r1
mov.l r1, @(CtxFir-CtxR8,r14) ; save original PC
add #-CtxR8, r14 ; (r14) = ptr to
sts PR, r1
mov.l r1, @(CtxPR,r14)
add #-THREAD_CONTEXT_OFFSET, r14
PROLOG_END
; Non-address error load exeception. Check for TLB Miss due to invalid entry and send
; to the tlb miss handler if necessary.
;
; (r0) = EXPEVT | 0x20
.align 4
geh30: cmp/eq #h'60, r0
bf geh35 ; not a TLB Miss
bra TLBMissHandler
nop
.nopool
; General exception or TLB miss which cannot be resolved by the TLB miss handler.
TLBMissError: ; return here from TLB miss handler if invalid address
geh35: mov #_KData+bResched, r1
mov.b @(1,r1), r0 ; (r0) = kernel reentrancy flag
dt r0 ; decrement for each entry
bf/s geh33 ; nested exception
mov.b r0, @(1,r1) ; save reentrancy level
; Handle a general exception that is NOT a system call.
;
; (r5) = ptr to CtxPSR+4.
; in register bank 1
stc SSR, @-r5 ; save status register
stc SPC, @-r5 ; save PC
mov.l r15, @-r5 ; save stack pointer
mov.l r14, @-r5 ; save register for ptr to current thread
mov r4, r14 ; (r14) = ptr to current thread
mov #_KStack, r15 ; switch to kernel's stack
geh36: mov.l @(EXPEVT,r7), r0 ; (r0) = exception event code
mov #h'160, r2
mov.l @(MMUTEA,r7), r1 ; (r1) = translation address
cmp/eq r0, r2
bf geh41 ; not a TRAPA exception
bra geh41
mov.l @(TRPA,r7), r1 ; (r1) = trapa value
.nopool
; A nested exception has occured. Create a temporary thread
; structure on the stack and save the current state into that.
;
; (r2) = old stack pointer
; in register bank 1
geh33: mov r15, r5 ; (r5) = ptr to context save area
.aif SH_CPU eq h'40
add #h'80-CtxSizeof, r5
add #(CtxPsr+4)-h'80, r5 ; (r5) = ptr to PSR save
.aelse
add #(CtxPsr+4)-CtxSizeof, r5 ; (r5) = ptr to PSR save
.aendi
stc SSR, @-r5 ; save status register
stc SPC, @-r5 ; save PC
mov.l r15, @-r5 ; save stack pointer
mov.l r14, @-r5 ; save register for ptr to current thread
mov r5, r15
add #-CtxR14, r15
add #-THREAD_CONTEXT_OFFSET, r15
mov r15, r14 ; (r14) = ptr to fake thread
mov #-1, r3
mov.l r3, @(ThAKey, r14) ; Set access key to FFFFFFFF
bra geh36
add #-16, r15 ; make room for argument spill area
.nopool
; An interrupt has caused a reschedule. Setup the registers for a general
; exception and jump into the context save & exception dispatch.
;
; (r4) = ptr to current thread
; (r5) - ptr to context save area
; (r7) - SH3CTL_BASE (used to access MMU & exception data)
; cNest == 0 (not inside another exception)
; in register bank 1
InterruptResched:
stc SSR, @-r5 ; save status register
stc SPC, @-r5 ; save PC
mov.l r15, @-r5 ; save stack pointer
mov.l r14, @-r5 ; save register for ptr to current thread ptr
mov #0, r0 ; (r0) = fake EXPEVT value
mov #_KStack, r15 ; switch to kernel's stack
mov r4, r14 ; (r14) = ptr to current thread
geh41: mov.l r13, @-r5
mov.l r12, @-r5
mov.l r11, @-r5
mov.l r10, @-r5
mov.l r9, @-r5
mov.l r8, @-r5
stc r7_user, @-r5
stc r6_user, @-r5
stc r5_user, @-r5
stc r4_user, @-r5
stc r3_user, @-r5
stc r2_user, @-r5
stc r1_user, @-r5
stc r0_user, @-r5
ldc r1, r6_user ; (r6) = TEA or TRAPA value (arg2)
stc GBR, @-r5
sts MACL, @-r5
mov #CONTEXT_FULL, r1
sts MACH, @-r5
sts PR, @-r5
mov.l r1, @-r5 ; set context flags
mov #PR_B0_IE, r1
mov r0, r8 ; (r8) = exception cause
ldc r1, SR ; (SR) = privileged, bank 0, unblocked
; Check for interlocked API in progress. The interlocked apis setup the registers
; as follows: (r1) = starting address of sequence, (r2) = ending address of
; sequence, (r3) = (r1) ^ INTRLOCK_KEY.
;
; (r6) = TEA or TRAPA code (arg2)
; (r8) = exception cause (from EXPEVT, 0 if interrupt reschedule)
; (r14) = ptr to current thread
; in register bank 0.
mov #INTERLOCKED_END, r1 ; (r1) = end of interlocked api block
mov r14, r9
add #THREAD_CONTEXT_OFFSET+CtxR2, r9
mov.l @(CtxFir-CtxR2,r9), r5 ; (r5) = resume address
cmp/hi r5, r1 ; 'T' = r1 > r5
bt geh70 ; PC < INTERLOCKED_END
; Dispatch general exception.
;
; (r6) = TEA or TRAPA code (arg2)
; (r8) = exception cause
; (r9) = ptr to CtxR2 in Current Thread's context
; (r14) = ptr to current thread
; All user registers saved into thread context
; in register bank 0
geh45: tst r8, r8
bt geh55 ; this is a reschedule request
mov #_HandleException, r1
mov r8, r5 ; (r5) = exception cause (arg1)
jsr @r1
mov r14, r4 ; (r4) = ptr to current thread (arg0)
tst r0,r0
bt geh55 ; must reschedule
bra geh60 ; resume the current thread
nop
.nopool
; The current thread is yielding. Save the permanent registers into the
; thread's context structure and invoke NextThread.
;
; (r14) = ptr to current thread
; in register bank 0
.align 4
SaveAndResched:
mov r14, r4
add #THREAD_CONTEXT_OFFSET, r4; (r4) = ptr to CtxFlags
mov #0, r0
mov.l r0, @(CtxContextFlags,r4)
add #CtxR8, r4 ; (r4) = ptr to CtxR8
mov.l r8, @(CtxR8-CtxR8,r4)
mov.l r9, @(CtxR9-CtxR8,r4)
mov.l r10, @(CtxR10-CtxR8,r4)
mov.l r11, @(CtxR11-CtxR8,r4)
mov.l r12, @(CtxR12-CtxR8,r4)
mov.l r13, @(CtxR13-CtxR8,r4)
; The current thread has been blocked or a reschedule is pending.
; Call the scheduler to obtain the highest priority thread to run.
;
; (r14) = ptr to current thread
; register bank unknown
resched:
geh55: mov #PR_B0_IE, r1
mov #_KData+bResched, r9
ldc r1, SR ; (SR) = privileged, bank 0, unblocked
mov #0, r0 ; (r0) = 0
mov.b r0, @(bProfileOn-bResched,r9) ; clear profiling bit
renextthread:
mov.b @r9, r0
cmp/eq #1, r0
bf nonextthread
mov #_NextThread, r8
mov #0, r0
jsr @r8
mov.w r0, @r9 ; clear reschedule, still in kernel
nonextthread:
mov @(dwKCRes-bResched, r9), r0
cmp/eq #1, r0
bf nokcresched
mov #_KCNextThread, r8
mov #0, r0
jsr @r8
mov r0, @(dwKCRes-bResched, r9)
mov @(dwKCRes-bResched,r9), r0
cmp/eq #1, r0
bt renextthread
nokcresched:
mov #_RunList, r1
mov @(4,r1), r0
cmp/eq #0, r0
bt Idle ; no thread to run
cmp/eq r0, r14
bt geh60 ; resume current thread
; Switch to a different thread. Update current thread, current process, thread
; local storage data, and process virtual memory context.
;
; (r0) = ptr to thread to dispatch
; (r9) = ptr to bResched
.align 4
geh56: mov #_KData+lpvTls, r6 ; (r6) = &lpvTLS in KPage
mov r0, r14 ; (r14) = ptr to thread
mov.l @(ThHandle,r14), r0 ; (r0) = thread's handle
mov #SH3CTL_BASE, r7
mov.l r0, @(hCurThread-lpvTls,r6) ; save current thread handle in KPage
mov.l @(ThProc,r14), r1 ; (r1) = ptr to current process
mov.l r14, @(pCurThd-bResched,r9) ; save current thread ptr in KPage
mov.l r1, @(pCurPrc-bResched,r9) ; save current process ptr
mov.l @(PrcHandle,r1), r0 ; (r0) = process's handle
mov.l r0, @(hCurProc-lpvTls,r6); save current process handle in KPage
mov.l @(ThTlsPtr,r14), r3 ; (r3) = thread local storage pointer |
mov.l r3, @r6 ; set TLS pointer |
ldc r14, r4_bank ; (r4_bank1) = ptr to current thread |
ERRNZ PrcID ; |
mov.b @r1, r4 ; (r4) = process ID |
mov #_NKSection, r2 ; (r2) = process's vm section, init to NKSection
tst r4, r4 ; is it NK?
bt/s geh57 ; use NKSection if it's NK
add #aSections-bResched, r9 ; (r9) = ptr to SectionTable (delay slot)
;
; not NK, find it from Seciton table
;
mov.l @(PrcVMBase,r1), r0 ; (r0) = memory section base address |
mov #2-VA_SECTION, r2 ; (r2) = right shift count |
shld r2, r0 ; (r0) = section index * 4 |
mov.l @(r0,r9), r2 ; (r2) = process's memory section |
geh57:
mov.l r4, @(MMUPTEH,r7) ; set ASID |
mov.l r2, @r9 ; swap in default process slot |
; Restore thread state.
;
; (r14) = ptr to thread structure
geh60: mov r14, r7
add #THREAD_CONTEXT_OFFSET, r7
mov r7, r11
mov.l @r7+, r0 ; (r0) = ContextFlags
lds @r7+, PR ; restore return address
tst r0, r0
bt geh65 ; only partial restore needed
lds @r7+, MACH
lds @r7+, MACL
ldc @r7+, GBR
add #4, r7
mov.l @r7+, r1
mov.l @r7+, r2
mov.l @r7+, r3
mov.l @r7+, r4
mov.l @r7+, r5
mov.l @r7+, r6
mov.l @r7, r7
; Reload thread's permanent registers and return value.
;
; (r11) = ptr to Current Thread's context structure
; (r13) = ptr to float save area
; (r14) = ptr to current thread
geh65: mov.l @(CtxR8,r11), r8
mov.l @(CtxR9,r11), r9
mov #PR_B1_BK, r10 ; (r10) = new SR value
mov.l @(CtxR0,r11), r0 ; (r0) = return value
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -