phys2virt.S 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright (C) 1994-2002 Russell King
  4. * Copyright (c) 2003, 2020 ARM Limited
  5. * All Rights Reserved
  6. */
  7. #include <linux/init.h>
  8. #include <linux/linkage.h>
  9. #include <asm/assembler.h>
  10. #include <asm/page.h>
  11. #ifdef __ARMEB__
  12. #define LOW_OFFSET 0x4
  13. #define HIGH_OFFSET 0x0
  14. #else
  15. #define LOW_OFFSET 0x0
  16. #define HIGH_OFFSET 0x4
  17. #endif
  18. /*
  19. * __fixup_pv_table - patch the stub instructions with the delta between
  20. * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be
  21. * 2 MiB aligned.
  22. *
  23. * Called from head.S, which expects the following registers to be preserved:
  24. * r1 = machine no, r2 = atags or dtb,
  25. * r8 = phys_offset, r9 = cpuid, r10 = procinfo
  26. */
  27. __HEAD
  28. ENTRY(__fixup_pv_table)
  29. mov r0, r8, lsr #PAGE_SHIFT @ convert to PFN
  30. str_l r0, __pv_phys_pfn_offset, r3
  31. adr_l r0, __pv_offset
  32. subs r3, r8, #PAGE_OFFSET @ PHYS_OFFSET - PAGE_OFFSET
  33. mvn ip, #0
  34. strcc ip, [r0, #HIGH_OFFSET] @ save to __pv_offset high bits
  35. str r3, [r0, #LOW_OFFSET] @ save to __pv_offset low bits
  36. mov r0, r3, lsr #21 @ constant for add/sub instructions
  37. teq r3, r0, lsl #21 @ must be 2 MiB aligned
  38. bne 0f
  39. adr_l r4, __pv_table_begin
  40. adr_l r5, __pv_table_end
  41. b __fixup_a_pv_table
  42. 0: mov r0, r0 @ deadloop on error
  43. b 0b
  44. ENDPROC(__fixup_pv_table)
  45. .text
  46. __fixup_a_pv_table:
  47. adr_l r6, __pv_offset
  48. ldr r0, [r6, #HIGH_OFFSET] @ pv_offset high word
  49. ldr r6, [r6, #LOW_OFFSET] @ pv_offset low word
  50. cmn r0, #1
  51. #ifdef CONFIG_THUMB2_KERNEL
  52. @
  53. @ The Thumb-2 versions of the patchable sequences are
  54. @
  55. @ phys-to-virt: movw <reg>, #offset<31:21>
  56. @ lsl <reg>, #21
  57. @ sub <VA>, <PA>, <reg>
  58. @
  59. @ virt-to-phys (non-LPAE): movw <reg>, #offset<31:21>
  60. @ lsl <reg>, #21
  61. @ add <PA>, <VA>, <reg>
  62. @
  63. @ virt-to-phys (LPAE): movw <reg>, #offset<31:21>
  64. @ lsl <reg>, #21
  65. @ adds <PAlo>, <VA>, <reg>
  66. @ mov <PAhi>, #offset<39:32>
  67. @ adc <PAhi>, <PAhi>, #0
  68. @
  69. @ In the non-LPAE case, all patchable instructions are MOVW
  70. @ instructions, where we need to patch in the offset into the
  71. @ second halfword of the opcode (the 16-bit immediate is encoded
  72. @ as imm4:i:imm3:imm8)
  73. @
  74. @ 15 11 10 9 4 3 0 15 14 12 11 8 7 0
  75. @ +-----------+---+-------------+------++---+------+----+------+
  76. @ MOVW | 1 1 1 1 0 | i | 1 0 0 1 0 0 | imm4 || 0 | imm3 | Rd | imm8 |
  77. @ +-----------+---+-------------+------++---+------+----+------+
  78. @
  79. @ In the LPAE case, we also need to patch in the high word of the
  80. @ offset into the immediate field of the MOV instruction, or patch it
  81. @ to a MVN instruction if the offset is negative. In this case, we
  82. @ need to inspect the first halfword of the opcode, to check whether
  83. @ it is MOVW or MOV/MVN, and to perform the MOV to MVN patching if
  84. @ needed. The encoding of the immediate is rather complex for values
  85. @ of i:imm3 != 0b0000, but fortunately, we never need more than 8 lower
  86. @ order bits, which can be patched into imm8 directly (and i:imm3
  87. @ cleared)
  88. @
  89. @ 15 11 10 9 5 0 15 14 12 11 8 7 0
  90. @ +-----------+---+---------------------++---+------+----+------+
  91. @ MOV | 1 1 1 1 0 | i | 0 0 0 1 0 0 1 1 1 1 || 0 | imm3 | Rd | imm8 |
  92. @ MVN | 1 1 1 1 0 | i | 0 0 0 1 1 0 1 1 1 1 || 0 | imm3 | Rd | imm8 |
  93. @ +-----------+---+---------------------++---+------+----+------+
  94. @
  95. moveq r0, #0x200000 @ set bit 21, mov to mvn instruction
  96. lsrs r3, r6, #29 @ isolate top 3 bits of displacement
  97. ubfx r6, r6, #21, #8 @ put bits 28:21 into the MOVW imm8 field
  98. bfi r6, r3, #12, #3 @ put bits 31:29 into the MOVW imm3 field
  99. b .Lnext
  100. .Lloop: add r7, r4
  101. adds r4, #4 @ clears Z flag
  102. #ifdef CONFIG_ARM_LPAE
  103. ldrh ip, [r7]
  104. ARM_BE8(rev16 ip, ip)
  105. tst ip, #0x200 @ MOVW has bit 9 set, MVN has it clear
  106. bne 0f @ skip to MOVW handling (Z flag is clear)
  107. bic ip, #0x20 @ clear bit 5 (MVN -> MOV)
  108. orr ip, ip, r0, lsr #16 @ MOV -> MVN if offset < 0
  109. ARM_BE8(rev16 ip, ip)
  110. strh ip, [r7]
  111. @ Z flag is set
  112. 0:
  113. #endif
  114. ldrh ip, [r7, #2]
  115. ARM_BE8(rev16 ip, ip)
  116. and ip, #0xf00 @ clear everything except Rd field
  117. orreq ip, r0 @ Z flag set -> MOV/MVN -> patch in high bits
  118. orrne ip, r6 @ Z flag clear -> MOVW -> patch in low bits
  119. ARM_BE8(rev16 ip, ip)
  120. strh ip, [r7, #2]
  121. #else
  122. #ifdef CONFIG_CPU_ENDIAN_BE8
  123. @ in BE8, we load data in BE, but instructions still in LE
  124. #define PV_BIT24 0x00000001
  125. #define PV_IMM8_MASK 0xff000000
  126. #define PV_IMMR_MSB 0x00080000
  127. #else
  128. #define PV_BIT24 0x01000000
  129. #define PV_IMM8_MASK 0x000000ff
  130. #define PV_IMMR_MSB 0x00000800
  131. #endif
  132. @
  133. @ The ARM versions of the patchable sequences are
  134. @
  135. @ phys-to-virt: sub <VA>, <PA>, #offset<31:24>, lsl #24
  136. @ sub <VA>, <PA>, #offset<23:16>, lsl #16
  137. @
  138. @ virt-to-phys (non-LPAE): add <PA>, <VA>, #offset<31:24>, lsl #24
  139. @ add <PA>, <VA>, #offset<23:16>, lsl #16
  140. @
  141. @ virt-to-phys (LPAE): movw <reg>, #offset<31:20>
  142. @ adds <PAlo>, <VA>, <reg>, lsl #20
  143. @ mov <PAhi>, #offset<39:32>
  144. @ adc <PAhi>, <PAhi>, #0
  145. @
  146. @ In the non-LPAE case, all patchable instructions are ADD or SUB
  147. @ instructions, where we need to patch in the offset into the
  148. @ immediate field of the opcode, which is emitted with the correct
  149. @ rotation value. (The effective value of the immediate is imm12<7:0>
  150. @ rotated right by [2 * imm12<11:8>] bits)
  151. @
  152. @ 31 28 27 23 22 20 19 16 15 12 11 0
  153. @ +------+-----------------+------+------+-------+
  154. @ ADD | cond | 0 0 1 0 1 0 0 0 | Rn | Rd | imm12 |
  155. @ SUB | cond | 0 0 1 0 0 1 0 0 | Rn | Rd | imm12 |
  156. @ MOV | cond | 0 0 1 1 1 0 1 0 | Rn | Rd | imm12 |
  157. @ MVN | cond | 0 0 1 1 1 1 1 0 | Rn | Rd | imm12 |
  158. @ +------+-----------------+------+------+-------+
  159. @
  160. @ In the LPAE case, we use a MOVW instruction to carry the low offset
  161. @ word, and patch in the high word of the offset into the immediate
  162. @ field of the subsequent MOV instruction, or patch it to a MVN
  163. @ instruction if the offset is negative. We can distinguish MOVW
  164. @ instructions based on bits 23:22 of the opcode, and ADD/SUB can be
  165. @ distinguished from MOV/MVN (all using the encodings above) using
  166. @ bit 24.
  167. @
  168. @ 31 28 27 23 22 20 19 16 15 12 11 0
  169. @ +------+-----------------+------+------+-------+
  170. @ MOVW | cond | 0 0 1 1 0 0 0 0 | imm4 | Rd | imm12 |
  171. @ +------+-----------------+------+------+-------+
  172. @
  173. moveq r0, #0x400000 @ set bit 22, mov to mvn instruction
  174. mov r3, r6, lsr #16 @ put offset bits 31-16 into r3
  175. mov r6, r6, lsr #24 @ put offset bits 31-24 into r6
  176. and r3, r3, #0xf0 @ only keep offset bits 23-20 in r3
  177. b .Lnext
  178. .Lloop: ldr ip, [r7, r4]
  179. #ifdef CONFIG_ARM_LPAE
  180. tst ip, #PV_BIT24 @ ADD/SUB have bit 24 clear
  181. beq 1f
  182. ARM_BE8(rev ip, ip)
  183. tst ip, #0xc00000 @ MOVW has bits 23:22 clear
  184. bic ip, ip, #0x400000 @ clear bit 22
  185. bfc ip, #0, #12 @ clear imm12 field of MOV[W] instruction
  186. orreq ip, ip, r6, lsl #4 @ MOVW -> mask in offset bits 31-24
  187. orreq ip, ip, r3, lsr #4 @ MOVW -> mask in offset bits 23-20
  188. orrne ip, ip, r0 @ MOV -> mask in offset bits 7-0 (or bit 22)
  189. ARM_BE8(rev ip, ip)
  190. b 2f
  191. 1:
  192. #endif
  193. tst ip, #PV_IMMR_MSB @ rotation value >= 16 ?
  194. bic ip, ip, #PV_IMM8_MASK
  195. orreq ip, ip, r6 ARM_BE8(, lsl #24) @ mask in offset bits 31-24
  196. orrne ip, ip, r3 ARM_BE8(, lsl #24) @ mask in offset bits 23-20
  197. 2:
  198. str ip, [r7, r4]
  199. add r4, r4, #4
  200. #endif
  201. .Lnext:
  202. cmp r4, r5
  203. ldrcc r7, [r4] @ use branch for delay slot
  204. bcc .Lloop
  205. ret lr
  206. ENDPROC(__fixup_a_pv_table)
  207. ENTRY(fixup_pv_table)
  208. stmfd sp!, {r4 - r7, lr}
  209. mov r4, r0 @ r0 = table start
  210. add r5, r0, r1 @ r1 = table size
  211. bl __fixup_a_pv_table
  212. ldmfd sp!, {r4 - r7, pc}
  213. ENDPROC(fixup_pv_table)
  214. .data
  215. .align 2
  216. .globl __pv_phys_pfn_offset
  217. .type __pv_phys_pfn_offset, %object
  218. __pv_phys_pfn_offset:
  219. .word 0
  220. .size __pv_phys_pfn_offset, . -__pv_phys_pfn_offset
  221. .globl __pv_offset
  222. .type __pv_offset, %object
  223. __pv_offset:
  224. .quad 0
  225. .size __pv_offset, . -__pv_offset