2013-01-18 15:12:18 +05:30
/ *
2015-02-21 15:09:32 +05:30
* Common L o w L e v e l I n t e r r u p t s / T r a p s / E x c e p t i o n s ( n o n - T L B ) H a n d l i n g f o r A R C
* ( included f r o m e n t r y - < i s a > . S
2013-01-18 15:12:18 +05:30
*
2015-02-21 15:09:32 +05:30
* Copyright ( C ) 2 0 1 4 - 1 5 S y n o p s y s , I n c . ( w w w . s y n o p s y s . c o m )
2013-01-18 15:12:18 +05:30
* Copyright ( C ) 2 0 0 4 , 2 0 0 7 - 2 0 1 0 , 2 0 1 1 - 2 0 1 2 S y n o p s y s , I n c . ( w w w . s y n o p s y s . c o m )
*
* This p r o g r a m i s f r e e s o f t w a r e ; you can redistribute it and/or modify
* it u n d e r t h e t e r m s o f t h e G N U G e n e r a l P u b l i c L i c e n s e v e r s i o n 2 a s
* published b y t h e F r e e S o f t w a r e F o u n d a t i o n .
* /
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Function A B I
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* Arguments r0 - r7
* Caller S a v e d R e g i s t e r s r0 - r12
* Callee S a v e d R e g i s t e r s r13 - r25
* Global P o i n t e r ( g p ) r26
* Frame P o i n t e r ( f p ) r27
* Stack P o i n t e r ( s p ) r28
* Branch l i n k r e g i s t e r ( b l i n k ) r31
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* /
2015-03-10 19:13:07 +05:30
;################### Special Sys Call Wrappers ##########################
ENTRY( s y s _ c l o n e _ w r a p p e r )
SAVE_ C A L L E E _ S A V E D _ U S E R
bl @sys_clone
DISCARD_ C A L L E E _ S A V E D _ U S E R
GET_ C U R R _ T H R _ I N F O _ F L A G S r10
btst r10 , T I F _ S Y S C A L L _ T R A C E
bnz t r a c e s y s _ e x i t
2016-09-16 17:13:29 -07:00
b . L r e t _ f r o m _ s y s t e m _ c a l l
2015-03-10 19:13:07 +05:30
END( s y s _ c l o n e _ w r a p p e r )
ENTRY( r e t _ f r o m _ f o r k )
; when the forked child comes here from the __switch_to function
; r0 has the last task pointer.
; put last task in scheduler queue
2015-08-12 17:23:32 +03:00
jl @schedule_tail
2015-03-10 19:13:07 +05:30
ld r9 , [ s p , P T _ s t a t u s32 ]
brne r9 , 0 , 1 f
jl. d [ r14 ] ; kernel thread entry point
mov r0 , r13 ; (see PF_KTHREAD block in copy_thread)
1 :
; Return to user space
; 1. Any forked task (Reach here via BRne above)
; 2. First ever init task (Reach here via return from JL above)
; This is the historic "kernel_execve" use-case, to return to init
; user mode, in a round about way since that is always done from
; a kernel thread which is executed via JL above but always returns
; out whenever kernel_execve (now inline do_fork()) is involved
b r e t _ f r o m _ e x c e p t i o n
END( r e t _ f r o m _ f o r k )
2013-01-18 15:12:18 +05:30
;################### Non TLB Exception Handling #############################
; ---------------------------------------------
; Instruction Error Exception Handler
; ---------------------------------------------
2014-02-07 13:47:43 +05:30
ENTRY( i n s t r _ s e r v i c e )
2013-01-18 15:12:18 +05:30
2013-07-09 15:07:13 +05:30
EXCEPTION_ P R O L O G U E
2013-01-18 15:12:18 +05:30
2013-06-12 15:13:40 +05:30
lr r0 , [ e f a ]
mov r1 , s p
2013-01-18 15:12:18 +05:30
2015-02-27 16:43:08 +05:30
FAKE_ R E T _ F R O M _ E X C P N
2013-01-18 15:12:18 +05:30
bl d o _ i n s t e r r o r _ o r _ k p r o b e
b r e t _ f r o m _ e x c e p t i o n
2014-02-07 13:47:43 +05:30
END( i n s t r _ s e r v i c e )
2013-01-18 15:12:18 +05:30
; ---------------------------------------------
; Machine Check Exception Handler
; ---------------------------------------------
2014-02-07 13:47:43 +05:30
ENTRY( E V _ M a c h i n e C h e c k )
2013-01-18 15:12:18 +05:30
2013-07-09 15:07:13 +05:30
EXCEPTION_ P R O L O G U E
2013-01-18 15:12:18 +05:30
2013-06-12 15:13:40 +05:30
lr r2 , [ e c r ]
lr r0 , [ e f a ]
mov r1 , s p
2013-01-18 15:12:18 +05:30
2017-09-01 17:00:23 +01:00
; hardware auto-disables MMU, re-enable it to allow kernel vaddr
; access for say stack unwinding of modules for crash dumps
lr r3 , [ A R C _ R E G _ P I D ]
or r3 , r3 , M M U _ E N A B L E
sr r3 , [ A R C _ R E G _ P I D ]
2013-06-12 15:13:40 +05:30
lsr r3 , r2 , 8
2013-05-28 15:24:30 +05:30
bmsk r3 , r3 , 7
brne r3 , E C R _ C _ M C H K _ D U P _ T L B , 1 f
2013-01-18 15:12:18 +05:30
bl d o _ t l b _ o v e r l a p _ f a u l t
b r e t _ f r o m _ e x c e p t i o n
1 :
; DEAD END: can't do much, display Regs and HALT
SAVE_ C A L L E E _ S A V E D _ U S E R
GET_ C U R R _ T A S K _ F I E L D _ P T R T A S K _ T H R E A D , r10
st s p , [ r10 , T H R E A D _ C A L L E E _ R E G ]
j d o _ m a c h i n e _ c h e c k _ f a u l t
2014-02-07 13:47:43 +05:30
END( E V _ M a c h i n e C h e c k )
2013-01-18 15:12:18 +05:30
; ---------------------------------------------
; Privilege Violation Exception Handler
; ---------------------------------------------
2014-02-07 13:47:43 +05:30
ENTRY( E V _ P r i v i l e g e V )
2013-01-18 15:12:18 +05:30
2013-07-09 15:07:13 +05:30
EXCEPTION_ P R O L O G U E
2013-01-18 15:12:18 +05:30
2013-06-12 15:13:40 +05:30
lr r0 , [ e f a ]
mov r1 , s p
2013-01-18 15:12:18 +05:30
2015-02-27 16:43:08 +05:30
FAKE_ R E T _ F R O M _ E X C P N
2013-01-18 15:12:18 +05:30
bl d o _ p r i v i l e g e _ f a u l t
b r e t _ f r o m _ e x c e p t i o n
2014-02-07 13:47:43 +05:30
END( E V _ P r i v i l e g e V )
2013-01-18 15:12:18 +05:30
; ---------------------------------------------
; Extension Instruction Exception Handler
; ---------------------------------------------
2014-02-07 13:47:43 +05:30
ENTRY( E V _ E x t e n s i o n )
2013-01-18 15:12:18 +05:30
2013-07-09 15:07:13 +05:30
EXCEPTION_ P R O L O G U E
2013-01-18 15:12:18 +05:30
2013-06-12 15:13:40 +05:30
lr r0 , [ e f a ]
mov r1 , s p
2013-07-09 15:07:13 +05:30
2015-02-27 16:43:08 +05:30
FAKE_ R E T _ F R O M _ E X C P N
2013-07-09 15:07:13 +05:30
2013-01-18 15:12:18 +05:30
bl d o _ e x t e n s i o n _ f a u l t
b r e t _ f r o m _ e x c e p t i o n
2014-02-07 13:47:43 +05:30
END( E V _ E x t e n s i o n )
2013-01-18 15:12:18 +05:30
2015-02-27 16:45:08 +05:30
;################ Trap Handling (Syscall, Breakpoint) ##################
2013-01-18 15:12:22 +05:30
2015-02-27 16:45:08 +05:30
; ---------------------------------------------
; syscall Tracing
; ---------------------------------------------
2013-01-18 15:12:22 +05:30
tracesys :
; save EFA in case tracer wants the PC of traced task
; using ERET won't work since next-PC has already committed
lr r12 , [ e f a ]
GET_ C U R R _ T A S K _ F I E L D _ P T R T A S K _ T H R E A D , r11
2013-03-20 16:53:14 +05:30
st r12 , [ r11 , T H R E A D _ F A U L T _ A D D R ] ; thread.fault_address
2013-01-18 15:12:22 +05:30
; PRE Sys Call Ptrace hook
mov r0 , s p ; pt_regs needed
bl @syscall_trace_entry
; Tracing code now returns the syscall num (orig or modif)
mov r8 , r0
; Do the Sys Call as we normally would.
; Validate the Sys Call number
cmp r8 , N R _ s y s c a l l s
mov. h i r0 , - E N O S Y S
bhi t r a c e s y s _ e x i t
; Restore the sys-call args. Mere invocation of the hook abv could have
; clobbered them (since they are in scratch regs). The tracer could also
; have deliberately changed the syscall args: r0-r7
ld r0 , [ s p , P T _ r0 ]
ld r1 , [ s p , P T _ r1 ]
ld r2 , [ s p , P T _ r2 ]
ld r3 , [ s p , P T _ r3 ]
ld r4 , [ s p , P T _ r4 ]
ld r5 , [ s p , P T _ r5 ]
ld r6 , [ s p , P T _ r6 ]
ld r7 , [ s p , P T _ r7 ]
ld. a s r9 , [ s y s _ c a l l _ t a b l e , r8 ]
jl [ r9 ] ; Entry into Sys Call Handler
tracesys_exit :
st r0 , [ s p , P T _ r0 ] ; sys call return value in pt_regs
;POST Sys Call Ptrace Hook
bl @syscall_trace_exit
b r e t _ f r o m _ e x c e p t i o n ; NOT ret_from_system_call at is saves r0 which
; we'd done before calling post hook above
2015-02-27 16:45:08 +05:30
; ---------------------------------------------
; Breakpoint TRAP
; ---------------------------------------------
2013-01-18 15:12:18 +05:30
trap_with_param :
2013-02-11 20:01:24 +05:30
; stop_pc info by gdb needs this info
2013-06-12 15:13:40 +05:30
lr r0 , [ e f a ]
mov r1 , s p
2013-01-18 15:12:18 +05:30
2014-04-20 13:33:48 +01:00
; Now that we have read EFA, it is safe to do "fake" rtie
2013-01-18 15:12:18 +05:30
; and get out of CPU exception mode
2015-02-27 16:43:08 +05:30
FAKE_ R E T _ F R O M _ E X C P N
2013-01-18 15:12:18 +05:30
; Save callee regs in case gdb wants to have a look
; SP will grow up by size of CALLEE Reg-File
; NOTE: clobbers r12
SAVE_ C A L L E E _ S A V E D _ U S E R
; save location of saved Callee Regs @ thread_struct->pc
GET_ C U R R _ T A S K _ F I E L D _ P T R T A S K _ T H R E A D , r10
st s p , [ r10 , T H R E A D _ C A L L E E _ R E G ]
; Call the trap handler
bl d o _ n o n _ s w i _ t r a p
; unwind stack to discard Callee saved Regs
DISCARD_ C A L L E E _ S A V E D _ U S E R
b r e t _ f r o m _ e x c e p t i o n
2015-02-27 16:45:08 +05:30
; ---------------------------------------------
; syscall TRAP
; ABI: (r0-r7) upto 8 args, (r8) syscall number
; ---------------------------------------------
2013-01-18 15:12:18 +05:30
2014-02-07 13:47:43 +05:30
ENTRY( E V _ T r a p )
2013-01-18 15:12:18 +05:30
2013-07-09 15:07:13 +05:30
EXCEPTION_ P R O L O G U E
2013-01-18 15:12:18 +05:30
2015-02-27 16:45:08 +05:30
;============ TRAP 1 :breakpoints
2015-03-13 11:50:23 +05:30
; Check ECR for trap with arg (PROLOGUE ensures r9 has ECR)
bmsk. f 0 , r9 , 7
2013-01-18 15:12:18 +05:30
bnz t r a p _ w i t h _ p a r a m
2015-02-27 16:45:08 +05:30
;============ TRAP (no param): syscall top level
2013-01-18 15:12:18 +05:30
2015-02-27 16:45:08 +05:30
; First return from Exception to pure K mode (Exception/IRQs renabled)
2015-02-27 16:43:08 +05:30
FAKE_ R E T _ F R O M _ E X C P N
2013-01-18 15:12:18 +05:30
2015-02-27 16:45:08 +05:30
; If syscall tracing ongoing, invoke pre-post-hooks
2013-01-18 15:12:22 +05:30
GET_ C U R R _ T H R _ I N F O _ F L A G S r10
btst r10 , T I F _ S Y S C A L L _ T R A C E
bnz t r a c e s y s ; this never comes back
2015-02-27 16:45:08 +05:30
;============ Normal syscall case
; syscall num shd not exceed the total system calls avail
2013-01-18 15:12:18 +05:30
cmp r8 , N R _ s y s c a l l s
mov. h i r0 , - E N O S Y S
2016-09-16 17:13:29 -07:00
bhi . L r e t _ f r o m _ s y s t e m _ c a l l
2013-01-18 15:12:18 +05:30
; Offset into the syscall_table and call handler
ld. a s r9 ,[ s y s _ c a l l _ t a b l e , r8 ]
jl [ r9 ] ; Entry into Sys Call Handler
2016-09-16 17:13:29 -07:00
.Lret_from_system_call :
2013-01-18 15:12:18 +05:30
st r0 , [ s p , P T _ r0 ] ; sys call return value in pt_regs
2016-09-16 17:13:29 -07:00
; fall through to ret_from_exception
END( E V _ T r a p )
2013-01-18 15:12:18 +05:30
;############# Return from Intr/Excp/Trap (Linux Specifics) ##############
;
; If ret to user mode do we need to handle signals, schedule() et al.
2014-02-07 13:47:43 +05:30
ENTRY( r e t _ f r o m _ e x c e p t i o n )
2013-01-18 15:12:18 +05:30
; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32
ld r8 , [ s p , P T _ s t a t u s32 ] ; returning to User/Kernel Mode
bbit0 r8 , S T A T U S _ U _ B I T , r e s u m e _ k e r n e l _ m o d e
; Before returning to User mode check-for-and-complete any pending work
; such as rescheduling/signal-delivery etc.
resume_user_mode_begin :
; Disable IRQs to ensures that chk for pending work itself is atomic
; (and we don't end up missing a NEED_RESCHED/SIGPENDING due to an
; interim IRQ).
IRQ_ D I S A B L E r10
; Fast Path return to user mode if no pending work
GET_ C U R R _ T H R _ I N F O _ F L A G S r9
and. f 0 , r9 , _ T I F _ W O R K _ M A S K
2014-10-13 19:49:00 +05:30
bz . L r e s t o r e _ r e g s
2013-01-18 15:12:18 +05:30
; --- (Slow Path #1) task preemption ---
bbit0 r9 , T I F _ N E E D _ R E S C H E D , . L c h k _ p e n d _ s i g n a l s
mov b l i n k , r e s u m e _ u s e r _ m o d e _ b e g i n ; tail-call to U mode ret chks
2015-08-12 17:23:32 +03:00
j @schedule ; BTST+Bnz causes relo error in link
2013-01-18 15:12:18 +05:30
.Lchk_pend_signals :
IRQ_ E N A B L E r10
; --- (Slow Path #2) pending signal ---
mov r0 , s p ; pt_regs for arg to do_signal()/do_notify_resume()
2013-09-06 14:18:17 +05:30
GET_ C U R R _ T H R _ I N F O _ F L A G S r9
2013-01-18 15:12:18 +05:30
bbit0 r9 , T I F _ S I G P E N D I N G , . L c h k _ n o t i f y _ r e s u m e
2013-01-18 15:12:19 +05:30
; Normal Trap/IRQ entry only saves Scratch (caller-saved) regs
; in pt_reg since the "C" ABI (kernel code) will automatically
; save/restore callee-saved regs.
;
; However, here we need to explicitly save callee regs because
2013-01-18 15:12:18 +05:30
; (i) If this signal causes coredump - full regfile needed
; (ii) If signal is SIGTRAP/SIGSTOP, task is being traced thus
; tracer might call PEEKUSR(CALLEE reg)
;
; NOTE: SP will grow up by size of CALLEE Reg-File
SAVE_ C A L L E E _ S A V E D _ U S E R ; clobbers r12
; save location of saved Callee Regs @ thread_struct->callee
GET_ C U R R _ T A S K _ F I E L D _ P T R T A S K _ T H R E A D , r10
st s p , [ r10 , T H R E A D _ C A L L E E _ R E G ]
bl @do_signal
2013-01-18 15:12:19 +05:30
; Ideally we want to discard the Callee reg above, however if this was
; a tracing signal, tracer could have done a POKEUSR(CALLEE reg)
RESTORE_ C A L L E E _ S A V E D _ U S E R
2013-01-18 15:12:18 +05:30
b r e s u m e _ u s e r _ m o d e _ b e g i n ; loop back to start of U mode ret
; --- (Slow Path #3) notify_resume ---
.Lchk_notify_resume :
btst r9 , T I F _ N O T I F Y _ R E S U M E
blnz @do_notify_resume
b r e s u m e _ u s e r _ m o d e _ b e g i n ; unconditionally back to U mode ret chks
; for single exit point from this block
resume_kernel_mode :
2014-04-30 15:26:45 +05:30
; Disable Interrupts from this point on
; CONFIG_PREEMPT: This is a must for preempt_schedule_irq()
; !CONFIG_PREEMPT: To ensure restore_regs is intr safe
2013-07-09 17:06:40 +05:30
IRQ_ D I S A B L E r9
2014-04-30 15:26:45 +05:30
# ifdef C O N F I G _ P R E E M P T
2013-01-18 15:12:18 +05:30
; Can't preempt if preemption disabled
GET_ C U R R _ T H R _ I N F O _ F R O M _ S P r10
ld r8 , [ r10 , T H R E A D _ I N F O _ P R E E M P T _ C O U N T ]
2014-10-13 19:49:00 +05:30
brne r8 , 0 , . L r e s t o r e _ r e g s
2013-01-18 15:12:18 +05:30
; check if this task's NEED_RESCHED flag set
ld r9 , [ r10 , T H R E A D _ I N F O _ F L A G S ]
2014-10-13 19:49:00 +05:30
bbit0 r9 , T I F _ N E E D _ R E S C H E D , . L r e s t o r e _ r e g s
2013-01-18 15:12:18 +05:30
; Invoke PREEMPTION
2015-08-12 17:23:32 +03:00
jl p r e e m p t _ s c h e d u l e _ i r q
2013-01-18 15:12:18 +05:30
; preempt_schedule_irq() always returns with IRQ disabled
# endif
2015-02-21 15:09:32 +05:30
b . L r e s t o r e _ r e g s
2013-01-18 15:12:18 +05:30
2015-03-10 19:13:07 +05:30
# # # # # DONT A D D C O D E H E R E - . L r e s t o r e _ r e g s a c t u a l l y f o l l o w s i n e n t r y - < i s a > . S
2015-02-21 15:09:32 +05:30