📄 shexcept.src
字号:
; 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.b @(bPowerOff-bResched,r9), r0 ; (r0) = "power off" flag
mov #_NextThread, r8
tst r0, r0
bf PowerOff ; go do power off processing
mov.b r0, @(bProfileOn-bResched,r9) ; clear profiling bit
renextthread:
mov.b @r9, r0
cmp/eq #1, r0
bf nonextthread
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
add #aSections-bResched, r9 ; (r9) = ptr to SectionTable
mov.l r0, @(hCurProc-lpvTls,r6); save current process handle in KPage
mov.l @(PrcVMBase,r1), r0 ; (r0) = memory section base address |
mov #2-VA_SECTION, r2 ; (r2) = right shift count |
mov.l @(ThTlsPtr,r14), r3 ; (r3) = thread local storage pointer |
shld r2, r0 ; (r0) = section index * 4 |
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.l @(r0,r9), r2 ; (r2) = process's memory section |
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
mov #_KData+bResched, r12
ldc r10, SR ; (SR) = privileged, bank 1, blocked
;++++ now in bank 1 ++++
mov.w @r12, r0 ; (r0) = kernel reentrancy flag
mov.l @(CtxR10,r11), r10
cmp/eq #1, r0
bt resched ; reschedule required
shlr8 r0
add #1, r0
mov.b r0, @(1,r12) ; save reentrancy level
; if high bit of wPriority is set, profiling should be on, else profiling off
;
; (r12) = ptr to bResched
; (r14) = ptr to current thread
mov.w @(ThwInfo,r14), r0 ; (r0) = thread's wInfo field
mov r11, r5
shlr16 r0 ; (r0) = 0xFFFF iff high bit was set
mov.b r0, @(bProfileOn-bResched,r12)
add #CtxR11, r5 ; (r5) = ptr to CtxR11
mov.l @r5+, r11
mov.l @r5+, r12
mov.l @r5+, r13
mov.l @r5+, r14
mov.l @r5+, r15 ; restore stack pointer
ldc @r5+, SPC
ldc @r5+, SSR
rte
nop
.nopool
; PC is below the end of the INTERLOCKED APIs, check lower bound and adjust the PC
; to restart the routine.
;
; (r5) = resume address
; (r9) = ptr to CtxR2 in Current Thread's context
; (r14) = ptr to current thread.
geh70: mov #INTERLOCKED_START, r1 ; (r1) = start of interlocked api block
mov #1, r0
tst r0,r5
bf geh75 ; PC is odd, don't change it
cmp/hi r5, r1 ; 'T' = r1 > r5
bt geh75 ; out of range, no backup
mov #-8, r1
and r1, r5 ; (old PC) &= ~7
.aif INTRLOCK_LEDS eq 1
mov #h'AA001010, r2 ; (r2) = LED address
mov.l @r2, r0
add #1,r0
mov.l r0, @r2 ; put it in lights
.aendi
mov.l r5, @(CtxFir-CtxR2,r9) ; backup PC to start of intrlocked sequence
geh75: bra geh45
nop
.nopool
; There are no threads which are ready to run. Put the cpu to sleep until
; something is made ready. Since an interrupt may occur between when NextThread
; returns and we get here, the reschedule flag must be checked. To avoid a timing
; race between checking the flag and sleeping, interrupts are blocked but not
; masked before checking the flag. The CPU will acknowledge interrupts regardless
; of the block bit when it is in sleep state.
;
; (r9) = ptr to bResched
Idle: mov #PR_B0_BK, r1
mov #_OEMIdle, r8
ldc r1, SR ; (SR) = privileged, bank 0, exceptions blocked
mov.b @r9, r0 ; (r0) = reschedule flag
tst r0, r0
bf geh55 ; reschedule needed, don't sleep
jsr @r8 ; call OEMIdle to sleep
nop
mov #_KData+bResched, r1
mov #1, r0
mov.b r0, @r1 ; (r0) = reschedule flag
bra geh55
nop
.nopool
; The power off flag has been set. Mask off interrupts, and call DoPowerOff() to
; notify the file system and invoke OEMPowerOff. Since the cpu state may be unknown
; upon return, the kernel's well known bank 1 registers must restored.
;
; (r9) = ptr to bResched
; (r14) = current thread
PowerOff:
mov #PR_B0_IM, r1
mov #_DoPowerOff, r2
ldc r1, SR ; (SR) = privileged, bank 0, ints masked
mov #0, r0
jsr @r2
mov.w r0, @r9 ; clear reschedule, still in kernel
mov #SH3CTL_BASE, r0
ldc r0, r7_bank ; (r7_priv) = ptr to SH3 control registers
mov #0, r14 ; (r14) = 0 (no current thread)
mov #0, r0
bra geh55
mov.b r0, @(bPowerOff-bResched,r9)
.endf
.PAGE
.org h'400
; TLB Miss handler
;
; Bank 1 registers are pre-loaded with the following values:
;
; (r4) - ptr to current thread
; (r5) - ptr to context save area
; (r7) - SH3CTL_BASE (used to access MMU & exception data)
LEAF_ENTRY TLBMissHandler
mov.l @(MMUTEA,r7), r1 ; (r1) = faulting virtual address
mov.l @(MMUTTB,r7), r0 ; (r0) = ptr to SectionTable array
tlb10: cmp/pz r1
bf tlb55 ; address >2GB, out of SectionTable bounds
shlr8 r1
mov r1, r2 ; (r2) = TEA >> 8
shlr16 r1 ; (r1) = TEA >> 24
shlr r1 ; (r1) = section table index (TEA>>25)
shll2 r1
mov.l @(r1,r0), r0 ; (r0) = ptr to section
mov r2, r1 ; (r1) = TEA >> 8
mov #BLOCK_MASK, r3
shlr8 r1 ; (r1) = TEA >> 16
and r3, r1 ; (r1) = block index
shll2 r1
mov.l @(r1,r0), r1 ; (r1) = ptr to MEMBLOCK structure
mov.l @(ThAKey,r4), r3 ; (r3) = thread's access key
cmp/pz r1
bt/s tlb60 ; unmapped block
mov r2, r0 ; (r0) = TEA >> 8
mov.l @(mb_lock,r1), r2 ; (r2) = block's access lock
add #mb_pages, r1 ; (r1) = ptr to array of TLB entries
tst r2, r3 ; (T) = 1 iff access is allowed
bt tlb60 ; thread cannot access this block
.aif VA_PAGE eq 12
shlr2 r0 ; (r0) = TEA >> 10
.aendi
and #PAGE_MASK4, r0 ; (r0) = page index * 4
mov.l @(r0,r1), r0 ; (r0) = TLB entry
tst #1, r0
bt tlb60 ; invalid entry
tlb40:
.aif SH_CPU eq h'40
mov.l r0, r1
add #-1, r0 ; // clear "write through" bit
mov #-9, r3
shld r3, r1
mov #1, r3
tst r3, r1
mov #-20, r3
shld r3, r1
bt tlb40a
add #16, r1
tlb40a:
mov.l r1, @(MMUPTEA,r7) ; set assistance part of TLB entry
.aendi
mov.l r0, @(MMUPTEL,r7) ; set lower part of TLB entry
ldtlb
nop
nop
.aif CELOG eq h'01
;
; Update the TLBMiss counter for CELOG
;
mov #_dwCeLogTLBMiss, r2
mov.l @r2, r1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -