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

📄 shexcept.src

📁 可用于嵌入式编程学习
💻 SRC
📖 第 1 页 / 共 5 页
字号:
        add     #1, r1
        mov.l   r1, @r2
  .aendi

tlb45:	rte
	nop
	.nopool

; Sh3 chip bug work around. When an RTS at a page boundary causes an address
; error (PSL return) and delay slot fetch causes a TLB miss, the CPU incorrectly
; reports the TEA as the address error value instead of the TLB miss address.
;
;	(r1) = TEA
;	(r4) = ptr to current thread

tlb55:
  .aif SH_CPU eq h'40
	mov r1, r0
  	mov #-26, r3
  	shld r3, r0
  	and #h'3f, r0
  	mov #h'38, r3
  	cmp/eq r0, r3
  	bf tlb56
	mov	#h'E0000000, r0
	sub r0, r1
	mov #h'fff00000, r0
	and r0, r1
	mov #_dwStoreQueueBase, r0
	mov @r0, r0
	add r1, r0
	bra tlb40
	nop
tlb56:
	.aendi
	cmp/eq	r4, r1
	bf	tlb60			; TEA != ptr to current thread, fault
	stc	SPC, r1			; (r1) = SHDB address of RTS
	bra	tlb10			; continue with correct TEA
	add	#8, r1			; put into the next page

; Invalid virtual address or this thread's key does not allow access to the
; memory block. Jump to the general exception handler to process the fault.

tlb60:
	bra	TLBMissError
	nop
	.nopool

	.PAGE
	ALTERNATE_ENTRY _LoadKPage
; Load User KPage entry into TLB.	
	mov	#KPAGE_PTEL, r1
	mov	#SH3CTL_BASE, r3
	mov	@(MMUPTEH,r3), r0	; (r0) = ASID in LSByte
	mov	#USER_KPAGE, r4
	and	#h'FF, r0		; (r0) = ASID
	or	r4, r0			; (r0) = User KPage | ASID
	shll	r1
	mov.l	r0, @(MMUPTEH,r3)
	shlr	r1			; clear hit bit of entry
	mov.l	r1, @(MMUPTEL,r3)
	ldtlb
	nop
	nop
	rts
	nop
	.nopool

	.PAGE
	ALTERNATE_ENTRY	_VerifyAccess
; VerifyAccess(PVOID pvAddr, DWORD dwFlags, ACCESSKEY aky)
;		- verify access to a pointer
;
;	VerifyAccess checks to see if the current thread has access to
; the given address. If bWrite is TRUE, both read & write access are
; verified.
;
;	Entry	(r4) = virtual address to verify
;		(r5) = type of access to verify
;		(r6) = access key to use for validation
;	Return	TRUE - access is OK
;		FALSE - if access is not valid
;	Uses	r0, r1, r2, r3

	mov	#SH3CTL_BASE, r0
	mov.l	@(MMUTTB,r0), r0	; (r0) = ptr to SectionTable array
	cmp/pz	r4
	bf	vfy60			; address >2GB, out of SectionTable bounds
	mov	r4, r1
	shlr8	r1
	mov	r1, r2
	shlr16	r2			; (r2) = TEA >> 24
	shlr	r2			; (r2) = section table index
	shll2	r2
	mov.l	@(r2,r0), r0		; (r0) = ptr to section
	mov	r1, r2
	mov	#BLOCK_MASK, r3
	shlr8	r1
	and	r3, r1			; (r1) = block index
	shll2	r1
	mov.l	@(r1,r0), r1		; (r1) = ptr to MEMBLOCK structure
	cmp/pz	r1
	bt/s	vfy35			; unmapped block
	mov	r2, r0
	mov.l	@(mb_lock,r1), r2	; (r2) = block's access lock
	add	#mb_pages, r1		; (r1) = ptr to array of TLB entries
  .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	r2, r6			; (T) = 1 iff access is allowed
	bt	vfy50			; thread cannot access this block
	tst	#1, r0
	bt	vfy50			; invalid entry
  .aif VA_PAGE eq 12
	mov	#h'fff, r1
  .aelse
	mov	#h'3ff, r1
  .aendi

vfy20:	mov	#VERIFY_WRITE_FLAG, r2
	tst	r2, r5
	bf	vfy40			; need to validate write permission
vfy30:	and	r1, r4			; (r4) = offset w/in page
	not	r1, r1			; (r1) = PFN mask
	and	r1, r0			; (r0) = physical page address
	mov	#h'80000000, r1		; (r1) = unmapped region base
	or	r4, r0			; (r0) = physical byte address
	rts
	or	r1, r0			; (r0) = unmapped byte address
	.nopool

; Unmapped virtual address. If the address is the kernel data page, load a
; shared TLB entry to map that page. Otherwise, jump to the general exception
; handler to process the fault.
;
;	(r0) = Address >> 8

vfy35:	shlr2	r0			; (r0) = Address >> 10
	cmp/eq	#USER_KPAGE_SHR10, r0
	mov	#KPAGE_PTEL, r0
	mov	#h'3ff, r1		; (r1) = page offset mask (KPage is always 1K)
	bt	vfy20			; the address is the User KPage
	;** Fall through to vfy40. The write verify will fail.

; Verify write access.
;
;	(r0) = page table entry

vfy40:	tst	#h'20, r0
	bf	vfy30			; access allowed
	;** Fall through into vfy50 to return failure.

; Invalid virtual address or this thread's key does not allow access to the
; memory block. Return 0 to indicate an invalid address.

vfy50:	rts
	mov	#0, r0
	.nopool

; Address is in the kernel's memory space. Check the caller indicated that
; kernel access was OK and that the address is not within the kernel mapped
; address space from 0xC0000000 to 0xE0000000.
;
;	(r4) = address to verify

vfy60:	mov	#h'C0000000, r3
	mov	#VERIFY_KERNEL_OK, r2
	tst	r2, r5
	bf	vfy61			; access OK - flag was set
	stc	r4_bank, r5		; (r5) = pCurThd
	add	#THREAD_CONTEXT_OFFSET+CtxR2, r5
	mov.l 	@(CtxPsr-CtxR2, r5), r5
	shll	r5
	shll	r5			; 'T' bit = Kernel mode status
	bf	vfy50			; access not allowed - not in kernel mode

vfy61:	cmp/hs	r3, r4			; 'T' set if Addr >= 0xC0000000
	mov	#h'E0000000, r2
	bf	vfy62			; access OK
	cmp/hs	r2, r4			; 'T' set if Addr >= 0xE0000000
	bf	vfy50			; don't allow access to kernel mapped space

vfy62:	rts
	mov	r4, r0			; access OK, return pointer unchanged
	.endf

	.PAGE
	LEAF_ENTRY _ZeroPage
;	void ZeroPage(void *vpPage)
;
;	Entry	(r4) = (vpPage) = ptr to address of page to zero
;	Return	none
;	Uses	r0, r1, r4

	mov	#1 << (VA_PAGE-4), r1	; (r1) = # of 16 bytes units to zero
	mov	#0, r0
zp10:	mov.l	r0, @r4
	mov.l	r0, @(4,r4)
	mov.l	r0, @(8,r4)
	mov.l	r0, @(12,r4)
	dt	r1			; (r1) = # of units left
	bf/s	zp10
	add	#16, r4			; (r4) = next 16 byte unit
	rts
	nop
	.endf

	.PAGE	

	LEAF_ENTRY _UnusedHandler
	rts
	mov	#SYSINTR_NOP, r0	; ignore the interrupt
	.endf

	.PAGE
	.org	h'600
; An interrupt exception has occured. Dispatch to an interrupt handler based
; upon the higest unmasked pending interrupt bit which is set.
;
; 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 InterruptExceptionHandler
	mov.l	@(INTEVT,r7), r6

	mov	#ExceptionTable, r0
	mov	r6, r2
	shlr2	r2
	shlr	r2			; (r1) = exception code >> 3
	mov.l	@(r0,r2), r1		; (r1) = interrupt handler function
	shlr2	r2
	mov #_IntrPrio, r0
	add #-16, r2
	mov.b	@(r0,r2), r3

	mov	#_KData+bResched, r2
	mov.b	@(1,r2), r0		; (r0) = kernel reentrancy flag
	dt	r0					; decrement for each entry
	bf/s	ieh01			; nested exception
	mov.b	r0, @(1,r2)		; save reentrancy level
	mov	r15, r2
	mov	#_KStack, r15		; switch to kernel's stack
	mov.l	r2, @-r15		; save stack pointer
ieh01:

  .aif CELOG eq h'01
        ;
        ; NOTE : To make things relatively consistent, I'm going to make
        ; the registers R0-R3, R6 available for use. On entry to CeLogInterruptSHx
        ; R0 will contain the value to be logged (cNest + SYSINTR value)
        ;
        ; I'm assuming that at this point the only register of these that
        ; I need to preserve is R1, R3, and PR
        ;
        sts     PR, @-r15               ; save current return address
        mov.l   r0, @-r15               ; save registers
        mov.l   r1, @-r15               ; save registers
        mov.l   r2, @-r15               ; save registers
        mov.l   r3, @-r15               ; save registers
        mov.l   r6, @-r15               ; save registers

        mov     #_CeLogInterruptSHx, r2
	mov	#h'80000000, r3		; r3 = mark as ISR entry
        jsr     @r2                     ; CeLogInterruptSHx(dwLogValue)
        mov     r3, r0			; delay slot: r0 = r3

        mov.l   @r15+, r6               ; Restore register
        mov.l   @r15+, r3               ; Restore register
        mov.l   @r15+, r2               ; Restore register
        mov.l   @r15+, r1               ; Restore register
        mov.l   @r15+, r0               ; Restore register
        lds     @r15+, PR               ; Restore return address
  .aendi

	sts	PR, @-r15
	stc	SPC, @-r15
	stc	SSR, @-r15
	stc	r0_user, @-r15
	stc	r1_user, @-r15
	stc	r2_user, @-r15
	stc	r3_user, @-r15
	stc	r6_user, @-r15

	ldc	r1, r1_user

	mov	#PR_B0_IE, r2

	shll2	r3
	shll2	r3
	or	r3, r2

	ldc	r2, SR		; bank 0, lower prio interrupts masked

	jsr	@r1			; invoke interrupt service routine
	nop

	mov #PR_B1_BK, r2
	ldc r2, SR

	stc r0_user, r3

	ldc @r15+, r6_user
	ldc @r15+, r3_user
	ldc @r15+, r2_user
	ldc @r15+, r1_user
	ldc @r15+, r0_user
	ldc @r15+, SSR
	ldc @r15+, SPC
	lds @r15+, PR

  .aif CELOG eq h'01
        ;
        ; NOTE : To make things relatively consistent, I'm going to make
        ; the registers R0-R3, R6 available for use. On entry to CeLogInterruptSHx
        ; R0 will contain the value to be logged (cNest + SYSINTR value)
        ;
        ; I'm assuming that at this point the only register of these that
        ; I need to preserve is R3 (SYSINTR value) and PR (return address)
        ;
        sts     PR, @-r15               ; save current return address
        mov.l   r3, @-r15               ; save registers
        mov     #_KData+cNest, r1
        mov.b   @r1, r1                 ; r1 = nest level (0, -1, -2, etc)
        neg     r1, r1                  ; r1 = nest level (0,  1,  2, etc)
        shll16  r1                      ; r1 <<= 16

        mov     #_CeLogInterruptSHx, r2
        or      r1, r3                  ; r3 = (-cNest << 16) | SYSINTR_val
        jsr     @r2                     ; CeLogInterruptSHx(dwLogValue)
        mov     r3, r0

        mov.l   @r15+, r3               ; Restore register
        lds     @r15+, PR               ; Restore return address
  .aendi

	mov	#_KData+bResched, r2
	mov.b @(1,r2), r0
	add #1, r0
	mov.b r0, @(1,r2)
	cmp/eq #1, r0
	bf ieh02
	mov @r15, r15
ieh02:

  	mov r3, r0

	mov	#SH3CTL_BASE, r7
	cmp/eq	#SYSINTR_NOP, r0
	bt	ieh50			; no additional processing needed
	cmp/eq	#SYSINTR_BREAK, r0
	bt	ieh60			; external break button pushed
	add	#-SYSINTR_DEVICES, r0
	cmp/pz	r0
	bf ieh40
	mov	#_KData+PendEvents, r1	; r1 = &PendEvents
	mov	#1, r3
	mov.l	@r1, r2				; r2 = PendEvents
	shld	r0, r3				; r3 = bit signifying current interrupt
	or	r3, r2					; r2 = all interrupts so far (bitmask)
	mov.l r2, @r1				; store PendEvents
ieh40:	mov	#_KData+bResched, r1
	mov.b @(1,r1), r0			; cNest
	mov #1, r2
	cmp/eq #1, r0
	bf ieh49
	bra	InterruptResched	; jump to general exception handler
	mov.w	r2, @r1
	.nopool

; Check for interlocked API in progress. The interlocked apis are all located
; at the end of the user kernel page. If the PC is less than INTERLOCKED_END and
; greater than INTERLOCKED_START, then the PC is adjusted to restart the routine.
;
;	in register bank 1.

ieh49:	mov.b	r2, @r1			; set bResched flag
ieh50:	mov	#INTERLOCKED_END, r1	; (r1) = end of interlocked api block
	stc	SPC, r0			; (r0) = interrupted PC
	cmp/hi	r0, r1			; 'T' = r1 > r0
	bt	ieh70			; PC < INTERLOCKED_END
ieh55:	rte
	nop
	.nopool

; External break button. Trap into the debugger.

ieh60:	mov	#16, r0
	mov	r0, @(TRPA,r7)		; set trapa code to 16 (trapa #4)
	mov	#h'160, r0		; (r0) = trapa expevt value
	bra	TLBMissError
	mov	r0, @(EXPEVT,r7)	; set event code
	.nopool

; PC is below the end of the INTERLOCKED APIs, check lower bound and adjust the PC
; to restart the routine.
;
;	(r0) = interrupted PC

ieh70:	mov	#INTERLOCKED_START, r1	; (r1) = start of interlocked api block
	tst	#1,r0
	bf	ieh55			; PC is odd, don't change it
	cmp/hi	r0, r1			; 'T' = r1 > r0
	bt	ieh55			; out of range, no backup
	mov	#-8, r1
	and	r1, r0			; (old PC) &= ~7
	ldc	r0, SPC			; update PC

	.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
	rte
	nop

	.endf

	NESTED_ENTRY xKCall
;++
; The following code is never executed. Its purpose is to support unwinding
; through the call to the exception dispatcher.
;--
	mov.l	r15, @(0,r15)		; caller's stack pointer
	sts.l	PR, @-r15		; return address
	add	#-16, r15		; argument save area
	PROLOG_END

	ALTERNATE_ENTRY _KCall
; KCall - call kernel function
;
;	KCall invokes a kernel function in a non-preemtable state by incrementing
; the kernel nest level and switching onto a kernel stack.
;
;	While in a preemtible state, the thread's register save area is
; volatile. On the way in, nothing can be saved into the thread
; structure until KNest is set and on the way out anything needed from the
; thread structure must be loaded before restoring KNest.
;
;	The sequence of stack switching must be handled carefully because
; whenever KNest != 1, the general exception handler assumes that the kernel
; stack is current and will not switch stacks. On the way in, we must switch
; to the kernel stack before setting KNest but not use it until after KNest
; is set.  On the way out, we must reset KNest before restoring the thread's
; stack pointer.
;
;	Entry	(r4) = ptr to function to call
;		(r5) = first function arg
;		(r6) = second fucntion arg
;		(r7) = third function arg
;	Exit	(r0) = function return value
;	Uses	r0-r7

	mov	#_KData+bResched, r1
	mov	r4, r3			; (r3) = ptr to function to call
	mov.b	@(1,r1), r0		; (r0) = kernel nest level
	mov	r5, r4			; ripple args down

⌨️ 快捷键说明

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