@
@ Most of the stack format comes from struct pt_regs, but with
@ the addition of 8 bytes for storing syscall args 5 and 6.
@
.macro zero_fp
mov fp,
.endm
.macro alignment_trap, rtemp
ldw \rtemp, .LCcralign
ldw \rtemp, [\rtemp]
movc p0.c1, \rtemp,
.endm
.macro load_user_sp_lr, rd, rtemp, offset = 0
mov \rtemp, asr
xor \rtemp, \rtemp,
mov.a asr, \rtemp @ switch to the SUSR mode
ldw sp, [\rd+],
ldw lr, [\rd+],
xor \rtemp, \rtemp,
mov.a asr, \rtemp @ switch back to the PRIV mode
.endm
.macro priv_exit, rpsr
mov.a bsr, \rpsr
ldm.w (r0 - r15), [sp]+
ldm.b (r16 - pc), [sp]+ @ load r0 - pc, asr
.endm
.macro restore_user_regs, fast = 0, offset = 0
ldw r1, [sp+],
ldw lr, [sp+],
mov.a bsr, r1 @ save in bsr_priv
.if \fast
add sp, sp,
ldm.w (r1 - r15), [sp]+ @ get calling r1 - r15
ldur (r16 - lr), [sp]+ @ get calling r16 - lr
.else
ldm.w (r0 - r15), [sp]+ @ get calling r0 - r15
ldur (r16 - lr), [sp]+ @ get calling r16 - lr
.endif
nop
add sp, sp,
mov.a pc, lr @ return
@ and move bsr_priv into asr
.endm
.macro get_thread_info, rd
mov \rd, sp >>
mov \rd, \rd <<
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
ldw \base, =(PKUNITY_INTC_BASE)
ldw \irqstat, [\base+],
ldw \tmp, [\base+],
and.a \irqstat, \irqstat, \tmp
beq 1001f
cntlz \irqnr, \irqstat
rsub \irqnr, \irqnr,
1001:
.endm
.macro printreg, reg, temp
adr \temp, 901f
stm (r0-r3), [\temp]+
stw lr, [\temp+],
mov r0, \reg
b.l printhex8
mov r0,
b.l printch
mov r0, pc
b.l printhex8
adr r0, 902f
b.l printascii
adr \temp, 901f
ldm (r0-r3), [\temp]+
ldw lr, [\temp+],
b 903f
901: .word 0, 0, 0, 0, 0 @ r0-r3, lr
902: .asciz ": epip4d\n"
.align
903:
.endm
scno .req r21 @ syscall number
tbl .req r22 @ syscall table pointer
why .req r22 @ Linux syscall (!= 0)
tsk .req r23 @ current thread_info
.macro intr_handler
1: get_irqnr_and_base r0, r6, r5, lr
beq 2f
mov r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@
adr lr, 1b
b asm_do_IRQ
2:
.endm
.macro priv_entry
sub sp, sp,
stm (r1 - r15), [sp]+
add r5, sp,
stm (r16 - r28), [r5]+
ldm (r1 - r3), [r0]+
add r5, sp,
mov r4,
add r0, sp,
stw.w r1, [sp+],
@ from the exception stack
mov r1, lr
@
@ We are now ready to fill in the remaining blanks on the stack:
@
@ r0 - sp_priv
@ r1 - lr_priv
@ r2 - lr_<exception>, already fixed up for correct return/restart
@ r3 - bsr_<exception>
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
@
stm (r0 - r4), [r5]+
.endm
.macro user_entry
sub sp, sp,
stm (r1 - r15), [sp+]
add r4, sp,
stm (r16 - r28), [r4]+
ldm (r1 - r3), [r0]+
add r0, sp,
mov r4,
stw r1, [sp] @ save the "real" r0 copied
@ from the exception stack
@
@ We are now ready to fill in the remaining blanks on the stack:
@
@ r2 - lr_<exception>, already fixed up for correct return/restart
@ r3 - bsr_<exception>
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
@
@ Also, separately save sp_user and lr_user
@
stm (r2 - r4), [r0]+
stur (sp, lr), [r0-]
@
@ Enable the alignment trap while in kernel mode
@
alignment_trap r0
@
@ Clear FP to mark the first stack frame
@
zero_fp
.endm
.text
@
@ __invalid - generic code for failed exception
@ (re-entrant version of handlers)
@
__invalid:
sub sp, sp,
stm (r1 - r15), [sp+]
add r1, sp,
stm (r16 - r28, sp, lr), [r1]+
zero_fp
ldm (r4 - r6), [r0]+
add r0, sp,
mov r7,
stw r4, [sp] @ save preserved r0
stm (r5 - r7), [r0]+ @ lr_<exception>,
@ asr_<exception>, "old_r0"
mov r0, sp
mov r1, asr
b bad_mode
ENDPROC(__invalid)
.align 5
__dabt_priv:
priv_entry
@
@ get ready to re-enable interrupts if appropriate
@
mov r17, asr
cand.a r3,
bne 1f
andn r17, r17,
1:
@
@ Call the processor-specific abort handler:
@
@ r2 - aborted context pc
@ r3 - aborted context asr
@
@ The abort handler must return the aborted address in r0, and
@ the fault status register in r1.
@
movc r1, p0.c3,
movc r0, p0.c4,
@
@ set desired INTR state, then call main handler
@
mov.a asr, r17
mov r2, sp
b.l do_DataAbort
@
@ INTRs off again before pulling preserved data off the stack
@
disable_irq r0
@
@ restore BSR and restart the instruction
@
ldw r2, [sp+],
priv_exit r2 @ return from exception
ENDPROC(__dabt_priv)
.align 5
__intr_priv:
priv_entry
intr_handler
mov r0,
movc p0.c5, r0,
nop; nop; nop; nop; nop; nop; nop; nop
ldw r4, [sp+],
priv_exit r4 @ return from exception
ENDPROC(__intr_priv)
.ltorg
.align 5
__extn_priv:
priv_entry
mov r0, sp @ struct pt_regs *regs
mov r1, asr
b bad_mode @ not supported
ENDPROC(__extn_priv)
.align 5
__pabt_priv:
priv_entry
@
@ re-enable interrupts if appropriate
@
mov r17, asr
cand.a r3,
bne 1f
andn r17, r17,
1:
@
@ set args, then call main handler
@
@ r0 - address of faulting instruction
@ r1 - pointer to registers on stack
@
mov r0, r2 @ pass address of aborted instruction
mov r1,
mov.a asr, r17
mov r2, sp @ regs
b.l do_PrefetchAbort @ call abort handler
@
@ INTRs off again before pulling preserved data off the stack
@
disable_irq r0
@
@ restore BSR and restart the instruction
@
ldw r2, [sp+],
priv_exit r2 @ return from exception
ENDPROC(__pabt_priv)
.align 5
.LCcralign:
.word cr_alignment
.align 5
__dabt_user:
user_entry
cff ip, s31
cand.a ip,
beq 209f
ldw ip, [sp+],
add ip, ip,
stw ip, [sp+],
@
@ fall through to the emulation code, which returns using r19 if
@ it has emulated the instruction, or the more conventional lr
@ if we are to treat this as a real extended instruction
@
@ r0 - instruction
@
1: ldw.u r0, [r2]
adr r19, ret_from_exception
adr lr, 209f
@
@ fallthrough to call do_uc_f64
@
get_thread_info r20 @ get current thread
and r8, r0,
mov r7,
stb r7, [r20+],
@ F64 hardware support entry point.
@ r0 = faulted instruction
@ r19 = return address
@ r20 = fp_state
enable_irq r4
add r20, r20,
cff r1, s31 @ get fpu FPSCR
andn r2, r1,
ctf r2, s31 @ clear 27 bit
mov r2, sp @ nothing stacked - regdump is at TOS
mov lr, r19 @ setup for a return to the user code
@ Now call the C code to package up the bounce to the support code
@ r0 holds the trigger instruction
@ r1 holds the FPSCR value
@ r2 pointer to register dump
b ucf64_exchandler
209:
@
@ Call the processor-specific abort handler:
@
@ r2 - aborted context pc
@ r3 - aborted context asr
@
@ The abort handler must return the aborted address in r0, and
@ the fault status register in r1.
@
movc r1, p0.c3,
movc r0, p0.c4,
@
@ INTRs on, then call the main handler
@
enable_irq r2
mov r2, sp
adr lr, ret_from_exception
b do_DataAbort
ENDPROC(__dabt_user)
.align 5
__intr_user:
user_entry
get_thread_info tsk
intr_handler
mov why,
b ret_to_user
ENDPROC(__intr_user)
.ltorg
.align 5
__extn_user:
user_entry
mov r0, sp
mov r1, asr
b bad_mode
ENDPROC(__extn_user)
.align 5
__pabt_user:
user_entry
mov r0, r2 @ pass address of aborted instruction.
mov r1,
enable_irq r1 @ Enable interrupts
mov r2, sp @ regs
b.l do_PrefetchAbort @ call abort handler
ENTRY(ret_from_exception)
get_thread_info tsk
mov why,
b ret_to_user
ENDPROC(__pabt_user)
ENDPROC(ret_from_exception)
ENTRY(__switch_to)
add ip, r1,
stm.w (r4 - r15), [ip]+
stm.w (r16 - r27, sp, lr), [ip]+
add ip, r1,
sfm.w (f0 - f7 ), [ip]+
sfm.w (f8 - f15), [ip]+
sfm.w (f16 - f23), [ip]+
sfm.w (f24 - f31), [ip]+
cff r4, s31
stw r4, [ip]
add ip, r2,
lfm.w (f0 - f7 ), [ip]+
lfm.w (f8 - f15), [ip]+
lfm.w (f16 - f23), [ip]+
lfm.w (f24 - f31), [ip]+
ldw r4, [ip]
ctf r4, s31
add ip, r2,
ldm.w (r4 - r15), [ip]+
ldm (r16 - r27, sp, pc), [ip]+ @ Load all regs saved previously
ENDPROC(__switch_to)
.align 5
ret_fast_syscall:
disable_irq r1 @ disable interrupts
ldw r1, [tsk+],
cand.a r1,
bne fast_work_pending
@ fast_restore_user_regs
restore_user_regs fast = 1, offset = S_OFF
fast_work_pending:
stw.w r0, [sp+],
work_pending:
cand.a r1,
bne work_resched
cand.a r1,
beq no_work_pending
mov r0, sp @ 'regs'
mov r2, why @ 'syscall'
cand.a r1,
cmovne why,
b.l do_notify_resume
b ret_slow_syscall @ Check work again
work_resched:
b.l schedule
ENTRY(ret_to_user)
ret_slow_syscall:
disable_irq r1 @ disable interrupts
get_thread_info tsk @ epip4d, one path error?!
ldw r1, [tsk+],
cand.a r1,
bne work_pending
no_work_pending:
@ slow_restore_user_regs
restore_user_regs fast = 0, offset = 0
ENDPROC(ret_to_user)
ENTRY(ret_from_fork)
b.l schedule_tail
get_thread_info tsk
ldw r1, [tsk+],
mov why,
cand.a r1,
beq ret_slow_syscall
mov r1, sp
mov r0,
b.l syscall_trace
b ret_slow_syscall
ENDPROC(ret_from_fork)
.align 5
ENTRY(vector_swi)
sub sp, sp,
stm (r0 - r15), [sp]+ @ Calling r0 - r15
add r8, sp,
stm (r16 - r28), [r8]+ @ Calling r16 - r28
add r8, sp,
stur (sp, lr), [r8-] @ Calling sp, lr
mov r8, bsr @ called from non-REAL mode
stw lr, [sp+],
stw r8, [sp+],
stw r0, [sp+],
zero_fp
sub ip, lr,
ldw.u scno, [ip] @ get SWI instruction
ldw ip, __cr_alignment
ldw ip, [ip]
movc p0.c1, ip,
enable_irq ip
get_thread_info tsk
ldw tbl, =sys_call_table @ load syscall table pointer
andn scno, scno,
andn scno, scno,
stm.w (r4, r5), [sp-] @ push fifth and sixth args
ldw ip, [tsk+],
cand.a ip,
bne __sys_trace
csub.a scno,
adr lr, ret_fast_syscall @ return address
bea 1f
ldw pc, [tbl+], scno <<
1:
add r1, sp,
2: mov why,
b sys_ni_syscall @ not private func
__sys_trace:
mov r2, scno
add r1, sp,
mov r0,
b.l syscall_trace
adr lr, __sys_trace_return @ return address
mov scno, r0 @ syscall number (possibly new)
add r1, sp,
csub.a scno,
bea 2b
ldm (r0 - r3), [r1]+ @ have to reload r0 - r3
ldw pc, [tbl+], scno <<
__sys_trace_return:
stw.w r0, [sp+],
mov r2, scno
mov r1, sp
mov r0,
b.l syscall_trace
b ret_slow_syscall
.align 5
.type __cr_alignment,
__cr_alignment:
.word cr_alignment
.ltorg
ENTRY(sys_execve)
add r3, sp,
b __sys_execve
ENDPROC(sys_execve)
ENTRY(sys_clone)
add ip, sp,
stw ip, [sp+],
b __sys_clone
ENDPROC(sys_clone)
ENTRY(sys_rt_sigreturn)
add r0, sp,
mov why,
b __sys_rt_sigreturn
ENDPROC(sys_rt_sigreturn)
ENTRY(sys_sigaltstack)
ldw r2, [sp+],
b do_sigaltstack
ENDPROC(sys_sigaltstack)
__INIT
.macro vector_stub, name, mode
.align 5
vector_\name:
@
@ Save r0, lr_<exception> (parent PC) and bsr_<exception>
@ (parent ASR)
@
stw r0, [sp]
stw lr, [sp+],
mov lr, bsr
stw lr, [sp+],
@
@ Prepare for PRIV mode. INTRs remain disabled.
@
mov r0, asr
xor r0, r0,
mov.a bsr, r0
@
@ the branch table must immediately follow this code
@
and lr, lr,
add lr, lr,
mov r0, sp
ldw lr, [pc+], lr <<
mov.a pc, lr @ branch to handler in PRIV mode
ENDPROC(vector_\name)
.align 2
@ handler addresses follow this label
.endm
.globl __stubs_start
__stubs_start:
vector_stub intr, INTR_MODE
.long __intr_user @ 0 (USER)
.long __invalid @ 1
.long __invalid @ 2
.long __intr_priv @ 3 (PRIV)
vector_stub dabt, ABRT_MODE
.long __dabt_user @ 0 (USER)
.long __invalid @ 1
.long __invalid @ 2 (INTR)
.long __dabt_priv @ 3 (PRIV)
vector_stub pabt, ABRT_MODE
.long __pabt_user @ 0 (USER)
.long __invalid @ 1
.long __invalid @ 2 (INTR)
.long __pabt_priv @ 3 (PRIV)
vector_stub extn, EXTN_MODE
.long __extn_user @ 0 (USER)
.long __invalid @ 1
.long __invalid @ 2 (INTR)
.long __extn_priv @ 3 (PRIV)
.align 5
.LCvswi:
.word vector_swi
.globl __stubs_end
__stubs_end:
.equ stubs_offset, __vectors_start + 0x200 - __stubs_start
.globl __vectors_start
__vectors_start:
jepriv SYS_ERROR0
b vector_extn + stubs_offset
ldw pc, .LCvswi + stubs_offset
b vector_pabt + stubs_offset
b vector_dabt + stubs_offset
jepriv SYS_ERROR0
b vector_intr + stubs_offset
jepriv SYS_ERROR0
.globl __vectors_end
__vectors_end:
.data
.globl cr_alignment
.globl cr_no_alignment
cr_alignment:
.space 4
cr_no_alignment:
.space 4