mte.S 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright (C) 2020 ARM Ltd.
  4. */
  5. #include <linux/linkage.h>
  6. #include <asm/asm-uaccess.h>
  7. #include <asm/assembler.h>
  8. #include <asm/mte.h>
  9. #include <asm/page.h>
  10. #include <asm/sysreg.h>
  11. .arch armv8.5-a+memtag
  12. /*
  13. * multitag_transfer_size - set \reg to the block size that is accessed by the
  14. * LDGM/STGM instructions.
  15. */
  16. .macro multitag_transfer_size, reg, tmp
  17. mrs_s \reg, SYS_GMID_EL1
  18. ubfx \reg, \reg, #GMID_EL1_BS_SHIFT, #GMID_EL1_BS_SIZE
  19. mov \tmp, #4
  20. lsl \reg, \tmp, \reg
  21. .endm
  22. /*
  23. * Clear the tags in a page
  24. * x0 - address of the page to be cleared
  25. */
  26. SYM_FUNC_START(mte_clear_page_tags)
  27. multitag_transfer_size x1, x2
  28. 1: stgm xzr, [x0]
  29. add x0, x0, x1
  30. tst x0, #(PAGE_SIZE - 1)
  31. b.ne 1b
  32. ret
  33. SYM_FUNC_END(mte_clear_page_tags)
  34. /*
  35. * Zero the page and tags at the same time
  36. *
  37. * Parameters:
  38. * x0 - address to the beginning of the page
  39. */
  40. SYM_FUNC_START(mte_zero_clear_page_tags)
  41. and x0, x0, #(1 << MTE_TAG_SHIFT) - 1 // clear the tag
  42. mrs x1, dczid_el0
  43. tbnz x1, #4, 2f // Branch if DC GZVA is prohibited
  44. and w1, w1, #0xf
  45. mov x2, #4
  46. lsl x1, x2, x1
  47. 1: dc gzva, x0
  48. add x0, x0, x1
  49. tst x0, #(PAGE_SIZE - 1)
  50. b.ne 1b
  51. ret
  52. 2: stz2g x0, [x0], #(MTE_GRANULE_SIZE * 2)
  53. tst x0, #(PAGE_SIZE - 1)
  54. b.ne 2b
  55. ret
  56. SYM_FUNC_END(mte_zero_clear_page_tags)
  57. /*
  58. * Copy the tags from the source page to the destination one
  59. * x0 - address of the destination page
  60. * x1 - address of the source page
  61. */
  62. SYM_FUNC_START(mte_copy_page_tags)
  63. mov x2, x0
  64. mov x3, x1
  65. multitag_transfer_size x5, x6
  66. 1: ldgm x4, [x3]
  67. stgm x4, [x2]
  68. add x2, x2, x5
  69. add x3, x3, x5
  70. tst x2, #(PAGE_SIZE - 1)
  71. b.ne 1b
  72. ret
  73. SYM_FUNC_END(mte_copy_page_tags)
  74. /*
  75. * Read tags from a user buffer (one tag per byte) and set the corresponding
  76. * tags at the given kernel address. Used by PTRACE_POKEMTETAGS.
  77. * x0 - kernel address (to)
  78. * x1 - user buffer (from)
  79. * x2 - number of tags/bytes (n)
  80. * Returns:
  81. * x0 - number of tags read/set
  82. */
  83. SYM_FUNC_START(mte_copy_tags_from_user)
  84. mov x3, x1
  85. cbz x2, 2f
  86. 1:
  87. USER(2f, ldtrb w4, [x1])
  88. lsl x4, x4, #MTE_TAG_SHIFT
  89. stg x4, [x0], #MTE_GRANULE_SIZE
  90. add x1, x1, #1
  91. subs x2, x2, #1
  92. b.ne 1b
  93. // exception handling and function return
  94. 2: sub x0, x1, x3 // update the number of tags set
  95. ret
  96. SYM_FUNC_END(mte_copy_tags_from_user)
  97. /*
  98. * Get the tags from a kernel address range and write the tag values to the
  99. * given user buffer (one tag per byte). Used by PTRACE_PEEKMTETAGS.
  100. * x0 - user buffer (to)
  101. * x1 - kernel address (from)
  102. * x2 - number of tags/bytes (n)
  103. * Returns:
  104. * x0 - number of tags read/set
  105. */
  106. SYM_FUNC_START(mte_copy_tags_to_user)
  107. mov x3, x0
  108. cbz x2, 2f
  109. 1:
  110. ldg x4, [x1]
  111. ubfx x4, x4, #MTE_TAG_SHIFT, #MTE_TAG_SIZE
  112. USER(2f, sttrb w4, [x0])
  113. add x0, x0, #1
  114. add x1, x1, #MTE_GRANULE_SIZE
  115. subs x2, x2, #1
  116. b.ne 1b
  117. // exception handling and function return
  118. 2: sub x0, x0, x3 // update the number of tags copied
  119. ret
  120. SYM_FUNC_END(mte_copy_tags_to_user)
  121. /*
  122. * Save the tags in a page
  123. * x0 - page address
  124. * x1 - tag storage, MTE_PAGE_TAG_STORAGE bytes
  125. */
  126. SYM_FUNC_START(mte_save_page_tags)
  127. multitag_transfer_size x7, x5
  128. 1:
  129. mov x2, #0
  130. 2:
  131. ldgm x5, [x0]
  132. orr x2, x2, x5
  133. add x0, x0, x7
  134. tst x0, #0xFF // 16 tag values fit in a register,
  135. b.ne 2b // which is 16*16=256 bytes
  136. str x2, [x1], #8
  137. tst x0, #(PAGE_SIZE - 1)
  138. b.ne 1b
  139. ret
  140. SYM_FUNC_END(mte_save_page_tags)
  141. /*
  142. * Restore the tags in a page
  143. * x0 - page address
  144. * x1 - tag storage, MTE_PAGE_TAG_STORAGE bytes
  145. */
  146. SYM_FUNC_START(mte_restore_page_tags)
  147. multitag_transfer_size x7, x5
  148. 1:
  149. ldr x2, [x1], #8
  150. 2:
  151. stgm x2, [x0]
  152. add x0, x0, x7
  153. tst x0, #0xFF
  154. b.ne 2b
  155. tst x0, #(PAGE_SIZE - 1)
  156. b.ne 1b
  157. ret
  158. SYM_FUNC_END(mte_restore_page_tags)