assembler.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * arch/arm/include/asm/assembler.h
  3. *
  4. * Copyright (C) 1996-2000 Russell King
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This file contains arm architecture specific defines
  11. * for the different processors.
  12. *
  13. * Do not include any C declarations in this file - it is included by
  14. * assembler source.
  15. */
  16. #ifndef __ASM_ASSEMBLER_H__
  17. #define __ASM_ASSEMBLER_H__
  18. #ifndef __ASSEMBLY__
  19. #error "Only include this from assembly code"
  20. #endif
  21. #include <asm/ptrace.h>
  22. #include <asm/domain.h>
  23. #define IOMEM(x) (x)
  24. /*
  25. * Endian independent macros for shifting bytes within registers.
  26. */
  27. #ifndef __ARMEB__
  28. #define pull lsr
  29. #define push lsl
  30. #define get_byte_0 lsl #0
  31. #define get_byte_1 lsr #8
  32. #define get_byte_2 lsr #16
  33. #define get_byte_3 lsr #24
  34. #define put_byte_0 lsl #0
  35. #define put_byte_1 lsl #8
  36. #define put_byte_2 lsl #16
  37. #define put_byte_3 lsl #24
  38. #else
  39. #define pull lsl
  40. #define push lsr
  41. #define get_byte_0 lsr #24
  42. #define get_byte_1 lsr #16
  43. #define get_byte_2 lsr #8
  44. #define get_byte_3 lsl #0
  45. #define put_byte_0 lsl #24
  46. #define put_byte_1 lsl #16
  47. #define put_byte_2 lsl #8
  48. #define put_byte_3 lsl #0
  49. #endif
  50. /*
  51. * Data preload for architectures that support it
  52. */
  53. #if __LINUX_ARM_ARCH__ >= 5
  54. #define PLD(code...) code
  55. #else
  56. #define PLD(code...)
  57. #endif
  58. /*
  59. * This can be used to enable code to cacheline align the destination
  60. * pointer when bulk writing to memory. Experiments on StrongARM and
  61. * XScale didn't show this a worthwhile thing to do when the cache is not
  62. * set to write-allocate (this would need further testing on XScale when WA
  63. * is used).
  64. *
  65. * On Feroceon there is much to gain however, regardless of cache mode.
  66. */
  67. #ifdef CONFIG_CPU_FEROCEON
  68. #define CALGN(code...) code
  69. #else
  70. #define CALGN(code...)
  71. #endif
  72. /*
  73. * Enable and disable interrupts
  74. */
  75. #if __LINUX_ARM_ARCH__ >= 6
  76. .macro disable_irq_notrace
  77. cpsid i
  78. .endm
  79. .macro enable_irq_notrace
  80. cpsie i
  81. .endm
  82. #else
  83. .macro disable_irq_notrace
  84. msr cpsr_c, #PSR_I_BIT | SVC_MODE
  85. .endm
  86. .macro enable_irq_notrace
  87. msr cpsr_c, #SVC_MODE
  88. .endm
  89. #endif
  90. .macro asm_trace_hardirqs_off
  91. #if defined(CONFIG_TRACE_IRQFLAGS)
  92. stmdb sp!, {r0-r3, ip, lr}
  93. bl trace_hardirqs_off
  94. ldmia sp!, {r0-r3, ip, lr}
  95. #endif
  96. .endm
  97. .macro asm_trace_hardirqs_on_cond, cond
  98. #if defined(CONFIG_TRACE_IRQFLAGS)
  99. /*
  100. * actually the registers should be pushed and pop'd conditionally, but
  101. * after bl the flags are certainly clobbered
  102. */
  103. stmdb sp!, {r0-r3, ip, lr}
  104. bl\cond trace_hardirqs_on
  105. ldmia sp!, {r0-r3, ip, lr}
  106. #endif
  107. .endm
  108. .macro asm_trace_hardirqs_on
  109. asm_trace_hardirqs_on_cond al
  110. .endm
  111. .macro disable_irq
  112. disable_irq_notrace
  113. asm_trace_hardirqs_off
  114. .endm
  115. .macro enable_irq
  116. asm_trace_hardirqs_on
  117. enable_irq_notrace
  118. .endm
  119. /*
  120. * Save the current IRQ state and disable IRQs. Note that this macro
  121. * assumes FIQs are enabled, and that the processor is in SVC mode.
  122. */
  123. .macro save_and_disable_irqs, oldcpsr
  124. mrs \oldcpsr, cpsr
  125. disable_irq
  126. .endm
  127. /*
  128. * Restore interrupt state previously stored in a register. We don't
  129. * guarantee that this will preserve the flags.
  130. */
  131. .macro restore_irqs_notrace, oldcpsr
  132. msr cpsr_c, \oldcpsr
  133. .endm
  134. .macro restore_irqs, oldcpsr
  135. tst \oldcpsr, #PSR_I_BIT
  136. asm_trace_hardirqs_on_cond eq
  137. restore_irqs_notrace \oldcpsr
  138. .endm
  139. #define USER(x...) \
  140. 9999: x; \
  141. .pushsection __ex_table,"a"; \
  142. .align 3; \
  143. .long 9999b,9001f; \
  144. .popsection
  145. #ifdef CONFIG_SMP
  146. #define ALT_SMP(instr...) \
  147. 9998: instr
  148. /*
  149. * Note: if you get assembler errors from ALT_UP() when building with
  150. * CONFIG_THUMB2_KERNEL, you almost certainly need to use
  151. * ALT_SMP( W(instr) ... )
  152. */
  153. #define ALT_UP(instr...) \
  154. .pushsection ".alt.smp.init", "a" ;\
  155. .long 9998b ;\
  156. 9997: instr ;\
  157. .if . - 9997b != 4 ;\
  158. .error "ALT_UP() content must assemble to exactly 4 bytes";\
  159. .endif ;\
  160. .popsection
  161. #define ALT_UP_B(label) \
  162. .equ up_b_offset, label - 9998b ;\
  163. .pushsection ".alt.smp.init", "a" ;\
  164. .long 9998b ;\
  165. W(b) . + up_b_offset ;\
  166. .popsection
  167. #else
  168. #define ALT_SMP(instr...)
  169. #define ALT_UP(instr...) instr
  170. #define ALT_UP_B(label) b label
  171. #endif
  172. /*
  173. * Instruction barrier
  174. */
  175. .macro instr_sync
  176. #if __LINUX_ARM_ARCH__ >= 7
  177. isb
  178. #elif __LINUX_ARM_ARCH__ == 6
  179. mcr p15, 0, r0, c7, c5, 4
  180. #endif
  181. .endm
  182. /*
  183. * SMP data memory barrier
  184. */
  185. .macro smp_dmb mode
  186. #ifdef CONFIG_SMP
  187. #if __LINUX_ARM_ARCH__ >= 7
  188. .ifeqs "\mode","arm"
  189. ALT_SMP(dmb)
  190. .else
  191. ALT_SMP(W(dmb))
  192. .endif
  193. #elif __LINUX_ARM_ARCH__ == 6
  194. ALT_SMP(mcr p15, 0, r0, c7, c10, 5) @ dmb
  195. #else
  196. #error Incompatible SMP platform
  197. #endif
  198. .ifeqs "\mode","arm"
  199. ALT_UP(nop)
  200. .else
  201. ALT_UP(W(nop))
  202. .endif
  203. #endif
  204. .endm
  205. #ifdef CONFIG_THUMB2_KERNEL
  206. .macro setmode, mode, reg
  207. mov \reg, #\mode
  208. msr cpsr_c, \reg
  209. .endm
  210. #else
  211. .macro setmode, mode, reg
  212. msr cpsr_c, #\mode
  213. .endm
  214. #endif
  215. /*
  216. * STRT/LDRT access macros with ARM and Thumb-2 variants
  217. */
  218. #ifdef CONFIG_THUMB2_KERNEL
  219. .macro usraccoff, instr, reg, ptr, inc, off, cond, abort, t=TUSER()
  220. 9999:
  221. .if \inc == 1
  222. \instr\cond\()b\()\t\().w \reg, [\ptr, #\off]
  223. .elseif \inc == 4
  224. \instr\cond\()\t\().w \reg, [\ptr, #\off]
  225. .else
  226. .error "Unsupported inc macro argument"
  227. .endif
  228. .pushsection __ex_table,"a"
  229. .align 3
  230. .long 9999b, \abort
  231. .popsection
  232. .endm
  233. .macro usracc, instr, reg, ptr, inc, cond, rept, abort
  234. @ explicit IT instruction needed because of the label
  235. @ introduced by the USER macro
  236. .ifnc \cond,al
  237. .if \rept == 1
  238. itt \cond
  239. .elseif \rept == 2
  240. ittt \cond
  241. .else
  242. .error "Unsupported rept macro argument"
  243. .endif
  244. .endif
  245. @ Slightly optimised to avoid incrementing the pointer twice
  246. usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
  247. .if \rept == 2
  248. usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort
  249. .endif
  250. add\cond \ptr, #\rept * \inc
  251. .endm
  252. #else /* !CONFIG_THUMB2_KERNEL */
  253. .macro usracc, instr, reg, ptr, inc, cond, rept, abort, t=TUSER()
  254. .rept \rept
  255. 9999:
  256. .if \inc == 1
  257. \instr\cond\()b\()\t \reg, [\ptr], #\inc
  258. .elseif \inc == 4
  259. \instr\cond\()\t \reg, [\ptr], #\inc
  260. .else
  261. .error "Unsupported inc macro argument"
  262. .endif
  263. .pushsection __ex_table,"a"
  264. .align 3
  265. .long 9999b, \abort
  266. .popsection
  267. .endr
  268. .endm
  269. #endif /* CONFIG_THUMB2_KERNEL */
  270. .macro strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
  271. usracc str, \reg, \ptr, \inc, \cond, \rept, \abort
  272. .endm
  273. .macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
  274. usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort
  275. .endm
  276. /* Utility macro for declaring string literals */
  277. .macro string name:req, string
  278. .type \name , #object
  279. \name:
  280. .asciz "\string"
  281. .size \name , . - \name
  282. .endm
  283. #endif /* __ASM_ASSEMBLER_H__ */