entry.S 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /*
  2. * linux/arch/m32r/kernel/entry.S
  3. *
  4. * Copyright (c) 2001, 2002 Hirokazu Takata, Hitoshi Yamamoto, H. Kondo
  5. * Copyright (c) 2003 Hitoshi Yamamoto
  6. * Copyright (c) 2004 Hirokazu Takata <takata at linux-m32r.org>
  7. *
  8. * Taken from i386 version.
  9. * Copyright (C) 1991, 1992 Linus Torvalds
  10. */
  11. /*
  12. * entry.S contains the system-call and fault low-level handling routines.
  13. * This also contains the timer-interrupt handler, as well as all interrupts
  14. * and faults that can result in a task-switch.
  15. *
  16. * NOTE: This code handles signal-recognition, which happens every time
  17. * after a timer-interrupt and after each system call.
  18. *
  19. * Stack layout in 'ret_from_system_call':
  20. * ptrace needs to have all regs on the stack.
  21. * if the order here is changed, it needs to be
  22. * updated in fork.c:copy_thread, signal.c:do_signal,
  23. * ptrace.c and ptrace.h
  24. *
  25. * M32R/M32Rx/M32R2
  26. * @(sp) - r4
  27. * @(0x04,sp) - r5
  28. * @(0x08,sp) - r6
  29. * @(0x0c,sp) - *pt_regs
  30. * @(0x10,sp) - r0
  31. * @(0x14,sp) - r1
  32. * @(0x18,sp) - r2
  33. * @(0x1c,sp) - r3
  34. * @(0x20,sp) - r7
  35. * @(0x24,sp) - r8
  36. * @(0x28,sp) - r9
  37. * @(0x2c,sp) - r10
  38. * @(0x30,sp) - r11
  39. * @(0x34,sp) - r12
  40. * @(0x38,sp) - syscall_nr
  41. * @(0x3c,sp) - acc0h
  42. * @(0x40,sp) - acc0l
  43. * @(0x44,sp) - acc1h ; ISA_DSP_LEVEL2 only
  44. * @(0x48,sp) - acc1l ; ISA_DSP_LEVEL2 only
  45. * @(0x4c,sp) - psw
  46. * @(0x50,sp) - bpc
  47. * @(0x54,sp) - bbpsw
  48. * @(0x58,sp) - bbpc
  49. * @(0x5c,sp) - spu (cr3)
  50. * @(0x60,sp) - fp (r13)
  51. * @(0x64,sp) - lr (r14)
  52. * @(0x68,sp) - spi (cr2)
  53. * @(0x6c,sp) - orig_r0
  54. */
  55. #include <linux/linkage.h>
  56. #include <asm/irq.h>
  57. #include <asm/unistd.h>
  58. #include <asm/assembler.h>
  59. #include <asm/thread_info.h>
  60. #include <asm/errno.h>
  61. #include <asm/segment.h>
  62. #include <asm/smp.h>
  63. #include <asm/page.h>
  64. #include <asm/m32r.h>
  65. #include <asm/mmu_context.h>
  66. #if !defined(CONFIG_MMU)
  67. #define sys_madvise sys_ni_syscall
  68. #define sys_readahead sys_ni_syscall
  69. #define sys_mprotect sys_ni_syscall
  70. #define sys_msync sys_ni_syscall
  71. #define sys_mlock sys_ni_syscall
  72. #define sys_munlock sys_ni_syscall
  73. #define sys_mlockall sys_ni_syscall
  74. #define sys_munlockall sys_ni_syscall
  75. #define sys_mremap sys_ni_syscall
  76. #define sys_mincore sys_ni_syscall
  77. #define sys_remap_file_pages sys_ni_syscall
  78. #endif /* CONFIG_MMU */
  79. #define R4(reg) @reg
  80. #define R5(reg) @(0x04,reg)
  81. #define R6(reg) @(0x08,reg)
  82. #define PTREGS(reg) @(0x0C,reg)
  83. #define R0(reg) @(0x10,reg)
  84. #define R1(reg) @(0x14,reg)
  85. #define R2(reg) @(0x18,reg)
  86. #define R3(reg) @(0x1C,reg)
  87. #define R7(reg) @(0x20,reg)
  88. #define R8(reg) @(0x24,reg)
  89. #define R9(reg) @(0x28,reg)
  90. #define R10(reg) @(0x2C,reg)
  91. #define R11(reg) @(0x30,reg)
  92. #define R12(reg) @(0x34,reg)
  93. #define SYSCALL_NR(reg) @(0x38,reg)
  94. #define ACC0H(reg) @(0x3C,reg)
  95. #define ACC0L(reg) @(0x40,reg)
  96. #define ACC1H(reg) @(0x44,reg)
  97. #define ACC1L(reg) @(0x48,reg)
  98. #define PSW(reg) @(0x4C,reg)
  99. #define BPC(reg) @(0x50,reg)
  100. #define BBPSW(reg) @(0x54,reg)
  101. #define BBPC(reg) @(0x58,reg)
  102. #define SPU(reg) @(0x5C,reg)
  103. #define FP(reg) @(0x60,reg) /* FP = R13 */
  104. #define LR(reg) @(0x64,reg)
  105. #define SP(reg) @(0x68,reg)
  106. #define ORIG_R0(reg) @(0x6C,reg)
  107. #define nr_syscalls ((syscall_table_size)/4)
  108. #ifdef CONFIG_PREEMPT
  109. #define preempt_stop(x) DISABLE_INTERRUPTS(x)
  110. #else
  111. #define preempt_stop(x)
  112. #define resume_kernel restore_all
  113. #endif
  114. /* how to get the thread information struct from ASM */
  115. #define GET_THREAD_INFO(reg) GET_THREAD_INFO reg
  116. .macro GET_THREAD_INFO reg
  117. ldi \reg, #-THREAD_SIZE
  118. and \reg, sp
  119. .endm
  120. ENTRY(ret_from_kernel_thread)
  121. pop r0
  122. bl schedule_tail
  123. GET_THREAD_INFO(r8)
  124. ld r0, R0(r8)
  125. ld r1, R1(r8)
  126. jl r1
  127. bra syscall_exit
  128. ENTRY(ret_from_fork)
  129. pop r0
  130. bl schedule_tail
  131. GET_THREAD_INFO(r8)
  132. bra syscall_exit
  133. /*
  134. * Return to user mode is not as complex as all this looks,
  135. * but we want the default path for a system call return to
  136. * go as quickly as possible which is why some of this is
  137. * less clear than it otherwise should be.
  138. */
  139. ; userspace resumption stub bypassing syscall exit tracing
  140. ALIGN
  141. ret_from_exception:
  142. preempt_stop(r4)
  143. ret_from_intr:
  144. ld r4, PSW(sp)
  145. #ifdef CONFIG_ISA_M32R2
  146. and3 r4, r4, #0x8800 ; check BSM and BPM bits
  147. #else
  148. and3 r4, r4, #0x8000 ; check BSM bit
  149. #endif
  150. beqz r4, resume_kernel
  151. resume_userspace:
  152. DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
  153. ; setting need_resched or sigpending
  154. ; between sampling and the iret
  155. GET_THREAD_INFO(r8)
  156. ld r9, @(TI_FLAGS, r8)
  157. and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done on
  158. ; int/exception return?
  159. bnez r4, work_pending
  160. bra restore_all
  161. #ifdef CONFIG_PREEMPT
  162. ENTRY(resume_kernel)
  163. GET_THREAD_INFO(r8)
  164. ld r9, @(TI_PRE_COUNT, r8) ; non-zero preempt_count ?
  165. bnez r9, restore_all
  166. need_resched:
  167. ld r9, @(TI_FLAGS, r8) ; need_resched set ?
  168. and3 r4, r9, #_TIF_NEED_RESCHED
  169. beqz r4, restore_all
  170. ld r4, PSW(sp) ; interrupts off (exception path) ?
  171. and3 r4, r4, #0x4000
  172. beqz r4, restore_all
  173. LDIMM (r4, PREEMPT_ACTIVE)
  174. st r4, @(TI_PRE_COUNT, r8)
  175. ENABLE_INTERRUPTS(r4)
  176. bl schedule
  177. ldi r4, #0
  178. st r4, @(TI_PRE_COUNT, r8)
  179. DISABLE_INTERRUPTS(r4)
  180. bra need_resched
  181. #endif
  182. ; system call handler stub
  183. ENTRY(system_call)
  184. SWITCH_TO_KERNEL_STACK
  185. SAVE_ALL
  186. ENABLE_INTERRUPTS(r4) ; Enable interrupt
  187. st sp, PTREGS(sp) ; implicit pt_regs parameter
  188. cmpui r7, #NR_syscalls
  189. bnc syscall_badsys
  190. st r7, SYSCALL_NR(sp) ; syscall_nr
  191. ; system call tracing in operation
  192. GET_THREAD_INFO(r8)
  193. ld r9, @(TI_FLAGS, r8)
  194. and3 r4, r9, #_TIF_SYSCALL_TRACE
  195. bnez r4, syscall_trace_entry
  196. syscall_call:
  197. slli r7, #2 ; table jump for the system call
  198. LDIMM (r4, sys_call_table)
  199. add r7, r4
  200. ld r7, @r7
  201. jl r7 ; execute system call
  202. st r0, R0(sp) ; save the return value
  203. syscall_exit:
  204. DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
  205. ; setting need_resched or sigpending
  206. ; between sampling and the iret
  207. ld r9, @(TI_FLAGS, r8)
  208. and3 r4, r9, #_TIF_ALLWORK_MASK ; current->work
  209. bnez r4, syscall_exit_work
  210. restore_all:
  211. RESTORE_ALL
  212. # perform work that needs to be done immediately before resumption
  213. # r9 : flags
  214. ALIGN
  215. work_pending:
  216. and3 r4, r9, #_TIF_NEED_RESCHED
  217. beqz r4, work_notifysig
  218. work_resched:
  219. bl schedule
  220. DISABLE_INTERRUPTS(r4) ; make sure we don't miss an interrupt
  221. ; setting need_resched or sigpending
  222. ; between sampling and the iret
  223. ld r9, @(TI_FLAGS, r8)
  224. and3 r4, r9, #_TIF_WORK_MASK ; is there any work to be done other
  225. ; than syscall tracing?
  226. beqz r4, restore_all
  227. and3 r4, r4, #_TIF_NEED_RESCHED
  228. bnez r4, work_resched
  229. work_notifysig: ; deal with pending signals and
  230. ; notify-resume requests
  231. mv r0, sp ; arg1 : struct pt_regs *regs
  232. mv r1, r9 ; arg2 : __u32 thread_info_flags
  233. bl do_notify_resume
  234. bra resume_userspace
  235. ; perform syscall exit tracing
  236. ALIGN
  237. syscall_trace_entry:
  238. ldi r4, #-ENOSYS
  239. st r4, R0(sp)
  240. bl do_syscall_trace
  241. ld r0, ORIG_R0(sp)
  242. ld r1, R1(sp)
  243. ld r2, R2(sp)
  244. ld r3, R3(sp)
  245. ld r4, R4(sp)
  246. ld r5, R5(sp)
  247. ld r6, R6(sp)
  248. ld r7, SYSCALL_NR(sp)
  249. cmpui r7, #NR_syscalls
  250. bc syscall_call
  251. bra syscall_exit
  252. ; perform syscall exit tracing
  253. ALIGN
  254. syscall_exit_work:
  255. ld r9, @(TI_FLAGS, r8)
  256. and3 r4, r9, #_TIF_SYSCALL_TRACE
  257. beqz r4, work_pending
  258. ENABLE_INTERRUPTS(r4) ; could let do_syscall_trace() call
  259. ; schedule() instead
  260. bl do_syscall_trace
  261. bra resume_userspace
  262. ALIGN
  263. syscall_fault:
  264. SAVE_ALL
  265. GET_THREAD_INFO(r8)
  266. ldi r4, #-EFAULT
  267. st r4, R0(sp)
  268. bra resume_userspace
  269. ALIGN
  270. syscall_badsys:
  271. ldi r4, #-ENOSYS
  272. st r4, R0(sp)
  273. bra resume_userspace
  274. .global eit_vector
  275. .equ ei_vec_table, eit_vector + 0x0200
  276. /*
  277. * EI handler routine
  278. */
  279. ENTRY(ei_handler)
  280. #if defined(CONFIG_CHIP_M32700)
  281. ; WORKAROUND: force to clear SM bit and use the kernel stack (SPI).
  282. SWITCH_TO_KERNEL_STACK
  283. #endif
  284. SAVE_ALL
  285. mv r1, sp ; arg1(regs)
  286. ; get ICU status
  287. seth r0, #shigh(M32R_ICU_ISTS_ADDR)
  288. ld r0, @(low(M32R_ICU_ISTS_ADDR),r0)
  289. push r0
  290. #if defined(CONFIG_SMP)
  291. /*
  292. * If IRQ == 0 --> Nothing to do, Not write IMASK
  293. * If IRQ == IPI --> Do IPI handler, Not write IMASK
  294. * If IRQ != 0, IPI --> Do do_IRQ(), Write IMASK
  295. */
  296. slli r0, #4
  297. srli r0, #24 ; r0(irq_num<<2)
  298. ;; IRQ exist check
  299. #if defined(CONFIG_CHIP_M32700)
  300. /* WORKAROUND: IMASK bug M32700-TS1, TS2 chip. */
  301. bnez r0, 0f
  302. ld24 r14, #0x00070000
  303. seth r0, #shigh(M32R_ICU_IMASK_ADDR)
  304. st r14, @(low(M32R_ICU_IMASK_ADDR),r0)
  305. bra 1f
  306. .fillinsn
  307. 0:
  308. #endif /* CONFIG_CHIP_M32700 */
  309. beqz r0, 1f ; if (!irq_num) goto exit
  310. ;; IPI check
  311. cmpi r0, #(M32R_IRQ_IPI0<<2) ; ISN < IPI0 check
  312. bc 2f
  313. cmpi r0, #((M32R_IRQ_IPI7+1)<<2) ; ISN > IPI7 check
  314. bnc 2f
  315. LDIMM (r2, ei_vec_table)
  316. add r2, r0
  317. ld r2, @r2
  318. beqz r2, 1f ; if (no IPI handler) goto exit
  319. mv r0, r1 ; arg0(regs)
  320. jl r2
  321. .fillinsn
  322. 1:
  323. addi sp, #4
  324. bra restore_all
  325. .fillinsn
  326. 2:
  327. srli r0, #2
  328. #else /* not CONFIG_SMP */
  329. srli r0, #22 ; r0(irq)
  330. #endif /* not CONFIG_SMP */
  331. #if defined(CONFIG_PLAT_HAS_INT1ICU)
  332. add3 r2, r0, #-(M32R_IRQ_INT1) ; INT1# interrupt
  333. bnez r2, 3f
  334. seth r0, #shigh(M32R_INT1ICU_ISTS)
  335. lduh r0, @(low(M32R_INT1ICU_ISTS),r0) ; bit10-6 : ISN
  336. slli r0, #21
  337. srli r0, #27 ; ISN
  338. addi r0, #(M32R_INT1ICU_IRQ_BASE)
  339. bra check_end
  340. .fillinsn
  341. 3:
  342. #endif /* CONFIG_PLAT_HAS_INT1ICU */
  343. #if defined(CONFIG_PLAT_HAS_INT0ICU)
  344. add3 r2, r0, #-(M32R_IRQ_INT0) ; INT0# interrupt
  345. bnez r2, 4f
  346. seth r0, #shigh(M32R_INT0ICU_ISTS)
  347. lduh r0, @(low(M32R_INT0ICU_ISTS),r0) ; bit10-6 : ISN
  348. slli r0, #21
  349. srli r0, #27 ; ISN
  350. add3 r0, r0, #(M32R_INT0ICU_IRQ_BASE)
  351. bra check_end
  352. .fillinsn
  353. 4:
  354. #endif /* CONFIG_PLAT_HAS_INT0ICU */
  355. #if defined(CONFIG_PLAT_HAS_INT2ICU)
  356. add3 r2, r0, #-(M32R_IRQ_INT2) ; INT2# interrupt
  357. bnez r2, 5f
  358. seth r0, #shigh(M32R_INT2ICU_ISTS)
  359. lduh r0, @(low(M32R_INT2ICU_ISTS),r0) ; bit10-6 : ISN
  360. slli r0, #21
  361. srli r0, #27 ; ISN
  362. add3 r0, r0, #(M32R_INT2ICU_IRQ_BASE)
  363. ; bra check_end
  364. .fillinsn
  365. 5:
  366. #endif /* CONFIG_PLAT_HAS_INT2ICU */
  367. check_end:
  368. bl do_IRQ
  369. pop r14
  370. seth r0, #shigh(M32R_ICU_IMASK_ADDR)
  371. st r14, @(low(M32R_ICU_IMASK_ADDR),r0)
  372. bra ret_from_intr
  373. /*
  374. * Default EIT handler
  375. */
  376. ALIGN
  377. int_msg:
  378. .asciz "Unknown interrupt\n"
  379. .byte 0
  380. ENTRY(default_eit_handler)
  381. push r0
  382. mvfc r0, psw
  383. push r1
  384. push r2
  385. push r3
  386. push r0
  387. LDIMM (r0, __KERNEL_DS)
  388. mv r0, r1
  389. mv r0, r2
  390. LDIMM (r0, int_msg)
  391. bl printk
  392. pop r0
  393. pop r3
  394. pop r2
  395. pop r1
  396. mvtc r0, psw
  397. pop r0
  398. infinit:
  399. bra infinit
  400. #ifdef CONFIG_MMU
  401. /*
  402. * Access Exception handler
  403. */
  404. ENTRY(ace_handler)
  405. SWITCH_TO_KERNEL_STACK
  406. SAVE_ALL
  407. seth r2, #shigh(MMU_REG_BASE) /* Check status register */
  408. ld r4, @(low(MESTS_offset),r2)
  409. st r4, @(low(MESTS_offset),r2)
  410. srl3 r1, r4, #4
  411. #ifdef CONFIG_CHIP_M32700
  412. and3 r1, r1, #0x0000ffff
  413. ; WORKAROUND: ignore TME bit for the M32700(TS1).
  414. #endif /* CONFIG_CHIP_M32700 */
  415. beqz r1, inst
  416. oprand:
  417. ld r2, @(low(MDEVA_offset),r2) ; set address
  418. srli r1, #1
  419. bra 1f
  420. inst:
  421. and3 r1, r4, #2
  422. srli r1, #1
  423. or3 r1, r1, #8
  424. mvfc r2, bpc ; set address
  425. .fillinsn
  426. 1:
  427. mvfc r3, psw
  428. mv r0, sp
  429. and3 r3, r3, 0x800
  430. srli r3, #9
  431. or r1, r3
  432. /*
  433. * do_page_fault():
  434. * r0 : struct pt_regs *regs
  435. * r1 : unsigned long error-code
  436. * r2 : unsigned long address
  437. * error-code:
  438. * +------+------+------+------+
  439. * | bit3 | bit2 | bit1 | bit0 |
  440. * +------+------+------+------+
  441. * bit 3 == 0:means data, 1:means instruction
  442. * bit 2 == 0:means kernel, 1:means user-mode
  443. * bit 1 == 0:means read, 1:means write
  444. * bit 0 == 0:means no page found 1:means protection fault
  445. *
  446. */
  447. bl do_page_fault
  448. bra ret_from_intr
  449. #endif /* CONFIG_MMU */
  450. ENTRY(alignment_check)
  451. /* void alignment_check(int error_code) */
  452. SWITCH_TO_KERNEL_STACK
  453. SAVE_ALL
  454. ldi r1, #0x30 ; error_code
  455. mv r0, sp ; pt_regs
  456. bl do_alignment_check
  457. error_code:
  458. bra ret_from_exception
  459. ENTRY(rie_handler)
  460. /* void rie_handler(int error_code) */
  461. SWITCH_TO_KERNEL_STACK
  462. SAVE_ALL
  463. ldi r1, #0x20 ; error_code
  464. mv r0, sp ; pt_regs
  465. bl do_rie_handler
  466. bra error_code
  467. ENTRY(pie_handler)
  468. /* void pie_handler(int error_code) */
  469. SWITCH_TO_KERNEL_STACK
  470. SAVE_ALL
  471. ldi r1, #0 ; error_code ; FIXME
  472. mv r0, sp ; pt_regs
  473. bl do_pie_handler
  474. bra error_code
  475. ENTRY(debug_trap)
  476. /* void debug_trap(void) */
  477. .global withdraw_debug_trap
  478. SWITCH_TO_KERNEL_STACK
  479. SAVE_ALL
  480. mv r0, sp ; pt_regs
  481. bl withdraw_debug_trap
  482. ldi r1, #0 ; error_code
  483. mv r0, sp ; pt_regs
  484. bl do_debug_trap
  485. bra error_code
  486. ENTRY(ill_trap)
  487. /* void ill_trap(void) */
  488. SWITCH_TO_KERNEL_STACK
  489. SAVE_ALL
  490. ldi r1, #0 ; error_code ; FIXME
  491. mv r0, sp ; pt_regs
  492. bl do_ill_trap
  493. bra error_code
  494. ENTRY(cache_flushing_handler)
  495. /* void _flush_cache_all(void); */
  496. .global _flush_cache_all
  497. SWITCH_TO_KERNEL_STACK
  498. push r0
  499. push r1
  500. push r2
  501. push r3
  502. push r4
  503. push r5
  504. push r6
  505. push r7
  506. push lr
  507. bl _flush_cache_all
  508. pop lr
  509. pop r7
  510. pop r6
  511. pop r5
  512. pop r4
  513. pop r3
  514. pop r2
  515. pop r1
  516. pop r0
  517. rte
  518. .section .rodata,"a"
  519. #include "syscall_table.S"
  520. syscall_table_size=(.-sys_call_table)