aboutsummaryrefslogtreecommitdiff
path: root/arch/arc/kernel/entry.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc/kernel/entry.S')
-rw-r--r--arch/arc/kernel/entry.S274
1 files changed, 104 insertions, 170 deletions
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index ef6800ba2f0..83a046a7cd0 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -141,8 +141,8 @@ VECTOR EV_Extension ; 0x130, Extn Intruction Excp (0x26)
VECTOR reserved ; Reserved Exceptions
.endr
-#include <linux/linkage.h> /* ARC_{EXTRY,EXIT} */
-#include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,TRAP...} */
+#include <linux/linkage.h> /* {EXTRY,EXIT} */
+#include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,SYS...} */
#include <asm/errno.h>
#include <asm/arcregs.h>
#include <asm/irqflags.h>
@@ -156,7 +156,7 @@ ARCFP_DATA int1_saved_reg
int1_saved_reg:
.zero 4
-/* Each Interrupt level needs it's own scratch */
+/* Each Interrupt level needs its own scratch */
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
ARCFP_DATA int2_saved_reg
@@ -184,7 +184,7 @@ reserved: ; processor restart
; ---------------------------------------------
; Level 2 ISR: Can interrupt a Level 1 ISR
; ---------------------------------------------
-ARC_ENTRY handle_interrupt_level2
+ENTRY(handle_interrupt_level2)
; TODO-vineetg for SMP this wont work
; free up r9 as scratchpad
@@ -225,14 +225,14 @@ ARC_ENTRY handle_interrupt_level2
b ret_from_exception
-ARC_EXIT handle_interrupt_level2
+END(handle_interrupt_level2)
#endif
; ---------------------------------------------
; Level 1 ISR
; ---------------------------------------------
-ARC_ENTRY handle_interrupt_level1
+ENTRY(handle_interrupt_level1)
/* free up r9 as scratchpad */
#ifdef CONFIG_SMP
@@ -250,6 +250,14 @@ ARC_ENTRY handle_interrupt_level1
lr r0, [icause1]
and r0, r0, 0x1f
+#ifdef CONFIG_TRACE_IRQFLAGS
+ ; icause1 needs to be read early, before calling tracing, which
+ ; can clobber scratch regs, hence use of stack to stash it
+ push r0
+ TRACE_ASM_IRQ_DISABLE
+ pop r0
+#endif
+
bl.d @arch_do_IRQ
mov r1, sp
@@ -257,7 +265,7 @@ ARC_ENTRY handle_interrupt_level1
sr r8, [AUX_IRQ_LV12] ; clear bit in Sticky Status Reg
b ret_from_exception
-ARC_EXIT handle_interrupt_level1
+END(handle_interrupt_level1)
;################### Non TLB Exception Handling #############################
@@ -265,63 +273,52 @@ ARC_EXIT handle_interrupt_level1
; Instruction Error Exception Handler
; ---------------------------------------------
-ARC_ENTRY instr_service
-
- EXCPN_PROLOG_FREEUP_REG r9
-
- lr r9, [erstatus]
-
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ENTRY(instr_service)
- lr r0, [ecr]
- lr r1, [efa]
+ EXCEPTION_PROLOGUE
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
FAKE_RET_FROM_EXCPN r9
bl do_insterror_or_kprobe
b ret_from_exception
-ARC_EXIT instr_service
+END(instr_service)
; ---------------------------------------------
; Memory Error Exception Handler
; ---------------------------------------------
-ARC_ENTRY mem_service
+ENTRY(mem_service)
- EXCPN_PROLOG_FREEUP_REG r9
+ EXCEPTION_PROLOGUE
- lr r9, [erstatus]
+ lr r0, [efa]
+ mov r1, sp
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ FAKE_RET_FROM_EXCPN r9
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
bl do_memory_error
b ret_from_exception
-ARC_EXIT mem_service
+END(mem_service)
; ---------------------------------------------
; Machine Check Exception Handler
; ---------------------------------------------
-ARC_ENTRY EV_MachineCheck
+ENTRY(EV_MachineCheck)
- EXCPN_PROLOG_FREEUP_REG r9
- lr r9, [erstatus]
+ EXCEPTION_PROLOGUE
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ lr r2, [ecr]
+ lr r0, [efa]
+ mov r1, sp
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
+ lsr r3, r2, 8
+ bmsk r3, r3, 7
+ brne r3, ECR_C_MCHK_DUP_TLB, 1f
- brne r0, 0x200100, 1f
bl do_tlb_overlap_fault
b ret_from_exception
@@ -334,29 +331,23 @@ ARC_ENTRY EV_MachineCheck
j do_machine_check_fault
-ARC_EXIT EV_MachineCheck
+END(EV_MachineCheck)
; ---------------------------------------------
; Protection Violation Exception Handler
; ---------------------------------------------
-ARC_ENTRY EV_TLBProtV
-
- EXCPN_PROLOG_FREEUP_REG r9
+ENTRY(EV_TLBProtV)
- ;Which mode (user/kernel) was the system in when Exception occured
- lr r9, [erstatus]
-
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ EXCEPTION_PROLOGUE
;---------(3) Save some more regs-----------------
; vineetg: Mar 6th: Random Seg Fault issue #1
; ecr and efa were not saved in case an Intr sneaks in
; after fake rtie
- ;
- lr r3, [ecr]
- lr r4, [efa]
+
+ lr r2, [ecr]
+ lr r0, [efa] ; Faulting Data address
; --------(4) Return from CPU Exception Mode ---------
; Fake a rtie, but rtie to next label
@@ -365,85 +356,68 @@ ARC_ENTRY EV_TLBProtV
FAKE_RET_FROM_EXCPN r9
+ mov r1, sp
+
;------ (5) Type of Protection Violation? ----------
;
; ProtV Hardware Exception is triggered for Access Faults of 2 types
- ; -Access Violaton (WRITE to READ ONLY Page) - for linux COW
- ; -Unaligned Access (READ/WRITE on odd boundary)
+ ; -Access Violaton : 00_23_(00|01|02|03)_00
+ ; x r w r+w
+ ; -Unaligned Access : 00_23_04_00
;
- cmp r3, 0x230400 ; Misaligned data access ?
- beq 4f
+ bbit1 r2, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
;========= (6a) Access Violation Processing ========
- cmp r3, 0x230100
- mov r1, 0x0 ; if LD exception ? write = 0
- mov.ne r1, 0x1 ; else write = 1
-
- mov r2, r4 ; faulting address
- mov r0, sp ; pt_regs
bl do_page_fault
b ret_from_exception
;========== (6b) Non aligned access ============
4:
- mov r0, r3 ; cause code
- mov r1, r4 ; faulting address
- mov r2, sp ; pt_regs
-#ifdef CONFIG_ARC_MISALIGN_ACCESS
SAVE_CALLEE_SAVED_USER
- mov r3, sp ; callee_regs
-#endif
+ mov r2, sp ; callee_regs
bl do_misaligned_access
-#ifdef CONFIG_ARC_MISALIGN_ACCESS
- DISCARD_CALLEE_SAVED_USER
-#endif
+ ; TBD: optimize - do this only if a callee reg was involved
+ ; either a dst of emulated LD/ST or src with address-writeback
+ RESTORE_CALLEE_SAVED_USER
b ret_from_exception
-ARC_EXIT EV_TLBProtV
+END(EV_TLBProtV)
; ---------------------------------------------
; Privilege Violation Exception Handler
; ---------------------------------------------
-ARC_ENTRY EV_PrivilegeV
-
- EXCPN_PROLOG_FREEUP_REG r9
+ENTRY(EV_PrivilegeV)
- lr r9, [erstatus]
+ EXCEPTION_PROLOGUE
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
-
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
FAKE_RET_FROM_EXCPN r9
bl do_privilege_fault
b ret_from_exception
-ARC_EXIT EV_PrivilegeV
+END(EV_PrivilegeV)
; ---------------------------------------------
; Extension Instruction Exception Handler
; ---------------------------------------------
-ARC_ENTRY EV_Extension
+ENTRY(EV_Extension)
- EXCPN_PROLOG_FREEUP_REG r9
- lr r9, [erstatus]
+ EXCEPTION_PROLOGUE
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_SYS
+ lr r0, [efa]
+ mov r1, sp
+
+ FAKE_RET_FROM_EXCPN r9
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
bl do_extension_fault
b ret_from_exception
-ARC_EXIT EV_Extension
+END(EV_Extension)
;######################### System Call Tracing #########################
@@ -452,7 +426,7 @@ tracesys:
; using ERET won't work since next-PC has already committed
lr r12, [efa]
GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11
- st r12, [r11, THREAD_FAULT_ADDR]
+ st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address
; PRE Sys Call Ptrace hook
mov r0, sp ; pt_regs needed
@@ -496,13 +470,10 @@ tracesys_exit:
trap_with_param:
; stop_pc info by gdb needs this info
- stw orig_r8_IS_BRKPT, [sp, PT_orig_r8]
-
- mov r0, r12
- lr r1, [efa]
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
- ; Now that we have read EFA, its safe to do "fake" rtie
+ ; Now that we have read EFA, it is safe to do "fake" rtie
; and get out of CPU exception mode
FAKE_RET_FROM_EXCPN r11
@@ -533,20 +504,13 @@ trap_with_param:
; (2) Break Points
;------------------------------------------------------------------
-ARC_ENTRY EV_Trap
+ENTRY(EV_Trap)
- ; Need at least 1 reg to code the early exception prolog
- EXCPN_PROLOG_FREEUP_REG r9
-
- ;Which mode (user/kernel) was the system in when intr occured
- lr r9, [erstatus]
-
- SWITCH_TO_KERNEL_STK
- SAVE_ALL_TRAP
+ EXCEPTION_PROLOGUE
;------- (4) What caused the Trap --------------
lr r12, [ecr]
- and.f 0, r12, ECR_PARAM_MASK
+ bmsk.f 0, r12, 7
bnz trap_with_param
; ======= (5a) Trap is due to System Call ========
@@ -570,9 +534,9 @@ ARC_ENTRY EV_Trap
jl [r9] ; Entry into Sys Call Handler
; fall through to ret_from_system_call
-ARC_EXIT EV_Trap
+END(EV_Trap)
-ARC_ENTRY ret_from_system_call
+ENTRY(ret_from_system_call)
st r0, [sp, PT_r0] ; sys call return value in pt_regs
@@ -582,16 +546,12 @@ ARC_ENTRY ret_from_system_call
;
; If ret to user mode do we need to handle signals, schedule() et al.
-ARC_ENTRY ret_from_exception
+ENTRY(ret_from_exception)
; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32
ld r8, [sp, PT_status32] ; returning to User/Kernel Mode
-#ifdef CONFIG_PREEMPT
bbit0 r8, STATUS_U_BIT, resume_kernel_mode
-#else
- bbit0 r8, STATUS_U_BIT, restore_regs
-#endif
; Before returning to User mode check-for-and-complete any pending work
; such as rescheduling/signal-delivery etc.
@@ -618,6 +578,7 @@ resume_user_mode_begin:
; --- (Slow Path #2) pending signal ---
mov r0, sp ; pt_regs for arg to do_signal()/do_notify_resume()
+ GET_CURR_THR_INFO_FLAGS r9
bbit0 r9, TIF_SIGPENDING, .Lchk_notify_resume
; Normal Trap/IRQ entry only saves Scratch (caller-saved) regs
@@ -651,10 +612,15 @@ resume_user_mode_begin:
b resume_user_mode_begin ; unconditionally back to U mode ret chks
; for single exit point from this block
-#ifdef CONFIG_PREEMPT
-
resume_kernel_mode:
+ ; 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
+ IRQ_DISABLE r9
+
+#ifdef CONFIG_PREEMPT
+
; Can't preempt if preemption disabled
GET_CURR_THR_INFO_FROM_SP r10
ld r8, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -664,8 +630,6 @@ resume_kernel_mode:
ld r9, [r10, THREAD_INFO_FLAGS]
bbit0 r9, TIF_NEED_RESCHED, restore_regs
- IRQ_DISABLE r9
-
; Invoke PREEMPTION
bl preempt_schedule_irq
@@ -678,23 +642,13 @@ resume_kernel_mode:
;
; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap)
; IRQ shd definitely not happen between now and rtie
+; All 2 entry points to here already disable interrupts
restore_regs :
- ; Disable Interrupts while restoring reg-file back
- ; XXX can this be optimised out
- IRQ_DISABLE_SAVE r9, r10 ;@r10 has prisitine (pre-disable) copy
-
-#ifdef CONFIG_ARC_CURR_IN_REG
- ; Restore User R25
- ; Earlier this used to be only for returning to user mode
- ; However with 2 levels of IRQ this can also happen even if
- ; in kernel mode
- ld r9, [sp, PT_sp]
- brhs r9, VMALLOC_START, 8f
- RESTORE_USER_R25
-8:
-#endif
+ TRACE_ASM_IRQ_ENABLE
+
+ lr r10, [status32]
; Restore REG File. In case multiple Events outstanding,
; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
@@ -712,28 +666,33 @@ not_exception:
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
+ ; Level 2 interrupt return Path - from hardware standpoint
bbit0 r10, STATUS_A2_BIT, not_level2_interrupt
;------------------------------------------------------------------
- ; if L2 IRQ interrupted a L1 ISR, we'd disbaled preemption earlier
- ; so that sched doesnt move to new task, causing L1 to be delayed
- ; undeterministically. Now that we've achieved that, lets reset
+ ; However the context returning might not have taken L2 intr itself
+ ; e.g. Task'A' user-code -> L2 intr -> schedule -> 'B' user-code ret
+ ; Special considerations needed for the context which took L2 intr
+
+ ld r9, [sp, PT_event] ; Ensure this is L2 intr context
+ brne r9, event_IRQ2, 149f
+
+ ;------------------------------------------------------------------
+ ; if L2 IRQ interrupted an L1 ISR, we'd disabled preemption earlier
+ ; so that sched doesn't move to new task, causing L1 to be delayed
+ ; undeterministically. Now that we've achieved that, let's reset
; things to what they were, before returning from L2 context
;----------------------------------------------------------------
- ldw r9, [sp, PT_orig_r8] ; get orig_r8 to make sure it is
- brne r9, orig_r8_IS_IRQ2, 149f ; infact a L2 ISR ret path
-
ld r9, [sp, PT_status32] ; get statu32_l2 (saved in pt_regs)
bbit0 r9, STATUS_A1_BIT, 149f ; L1 not active when L2 IRQ, so normal
- ; A1 is set in status32_l2
; decrement thread_info->preempt_count (re-enable preemption)
GET_CURR_THR_INFO_FROM_SP r10
ld r9, [r10, THREAD_INFO_PREEMPT_COUNT]
; paranoid check, given A1 was active when A2 happened, preempt count
- ; must not be 0 beccause we would have incremented it.
+ ; must not be 0 because we would have incremented it.
; If this does happen we simply HALT as it means a BUG !!!
cmp r9, 0
bnz 2f
@@ -769,15 +728,15 @@ not_level1_interrupt:
debug_marker_syscall:
rtie
-ARC_EXIT ret_from_exception
+END(ret_from_exception)
-ARC_ENTRY ret_from_fork
+ENTRY(ret_from_fork)
; when the forked child comes here from the __switch_to function
; r0 has the last task pointer.
; put last task in scheduler queue
bl @schedule_tail
- ; If kernel thread, jump to it's entry-point
+ ; If kernel thread, jump to its entry-point
ld r9, [sp, PT_status32]
brne r9, 0, 1f
@@ -788,36 +747,11 @@ ARC_ENTRY ret_from_fork
; special case of kernel_thread entry point returning back due to
; kernel_execve() - pretend return from syscall to ret to userland
b ret_from_exception
-ARC_EXIT ret_from_fork
+END(ret_from_fork)
;################### Special Sys Call Wrappers ##########################
-; TBD: call do_fork directly from here
-ARC_ENTRY sys_fork_wrapper
- SAVE_CALLEE_SAVED_USER
- bl @sys_fork
- DISCARD_CALLEE_SAVED_USER
-
- GET_CURR_THR_INFO_FLAGS r10
- btst r10, TIF_SYSCALL_TRACE
- bnz tracesys_exit
-
- b ret_from_system_call
-ARC_EXIT sys_fork_wrapper
-
-ARC_ENTRY sys_vfork_wrapper
- SAVE_CALLEE_SAVED_USER
- bl @sys_vfork
- DISCARD_CALLEE_SAVED_USER
-
- GET_CURR_THR_INFO_FLAGS r10
- btst r10, TIF_SYSCALL_TRACE
- bnz tracesys_exit
-
- b ret_from_system_call
-ARC_EXIT sys_vfork_wrapper
-
-ARC_ENTRY sys_clone_wrapper
+ENTRY(sys_clone_wrapper)
SAVE_CALLEE_SAVED_USER
bl @sys_clone
DISCARD_CALLEE_SAVED_USER
@@ -827,7 +761,7 @@ ARC_ENTRY sys_clone_wrapper
bnz tracesys_exit
b ret_from_system_call
-ARC_EXIT sys_clone_wrapper
+END(sys_clone_wrapper)
#ifdef CONFIG_ARC_DW2_UNWIND
; Workaround for bug 94179 (STAR ):