bpf_jit_64.S 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /* bpf_jit.S: Packet/header access helper functions
  2. * for PPC64 BPF compiler.
  3. *
  4. * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; version 2
  9. * of the License.
  10. */
  11. #include <asm/ppc_asm.h>
  12. #include "bpf_jit.h"
  13. /*
  14. * All of these routines are called directly from generated code,
  15. * whose register usage is:
  16. *
  17. * r3 skb
  18. * r4,r5 A,X
  19. * r6 *** address parameter to helper ***
  20. * r7-r10 scratch
  21. * r14 skb->data
  22. * r15 skb headlen
  23. * r16-31 M[]
  24. */
  25. /*
  26. * To consider: These helpers are so small it could be better to just
  27. * generate them inline. Inline code can do the simple headlen check
  28. * then branch directly to slow_path_XXX if required. (In fact, could
  29. * load a spare GPR with the address of slow_path_generic and pass size
  30. * as an argument, making the call site a mtlr, li and bllr.)
  31. */
  32. .globl sk_load_word
  33. sk_load_word:
  34. cmpdi r_addr, 0
  35. blt bpf_slow_path_word_neg
  36. .globl sk_load_word_positive_offset
  37. sk_load_word_positive_offset:
  38. /* Are we accessing past headlen? */
  39. subi r_scratch1, r_HL, 4
  40. cmpd r_scratch1, r_addr
  41. blt bpf_slow_path_word
  42. /* Nope, just hitting the header. cr0 here is eq or gt! */
  43. lwzx r_A, r_D, r_addr
  44. /* When big endian we don't need to byteswap. */
  45. blr /* Return success, cr0 != LT */
  46. .globl sk_load_half
  47. sk_load_half:
  48. cmpdi r_addr, 0
  49. blt bpf_slow_path_half_neg
  50. .globl sk_load_half_positive_offset
  51. sk_load_half_positive_offset:
  52. subi r_scratch1, r_HL, 2
  53. cmpd r_scratch1, r_addr
  54. blt bpf_slow_path_half
  55. lhzx r_A, r_D, r_addr
  56. blr
  57. .globl sk_load_byte
  58. sk_load_byte:
  59. cmpdi r_addr, 0
  60. blt bpf_slow_path_byte_neg
  61. .globl sk_load_byte_positive_offset
  62. sk_load_byte_positive_offset:
  63. cmpd r_HL, r_addr
  64. ble bpf_slow_path_byte
  65. lbzx r_A, r_D, r_addr
  66. blr
  67. /*
  68. * BPF_S_LDX_B_MSH: ldxb 4*([offset]&0xf)
  69. * r_addr is the offset value
  70. */
  71. .globl sk_load_byte_msh
  72. sk_load_byte_msh:
  73. cmpdi r_addr, 0
  74. blt bpf_slow_path_byte_msh_neg
  75. .globl sk_load_byte_msh_positive_offset
  76. sk_load_byte_msh_positive_offset:
  77. cmpd r_HL, r_addr
  78. ble bpf_slow_path_byte_msh
  79. lbzx r_X, r_D, r_addr
  80. rlwinm r_X, r_X, 2, 32-4-2, 31-2
  81. blr
  82. /* Call out to skb_copy_bits:
  83. * We'll need to back up our volatile regs first; we have
  84. * local variable space at r1+(BPF_PPC_STACK_BASIC).
  85. * Allocate a new stack frame here to remain ABI-compliant in
  86. * stashing LR.
  87. */
  88. #define bpf_slow_path_common(SIZE) \
  89. mflr r0; \
  90. std r0, 16(r1); \
  91. /* R3 goes in parameter space of caller's frame */ \
  92. std r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
  93. std r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
  94. std r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
  95. addi r5, r1, BPF_PPC_STACK_BASIC+(2*8); \
  96. stdu r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
  97. /* R3 = r_skb, as passed */ \
  98. mr r4, r_addr; \
  99. li r6, SIZE; \
  100. bl skb_copy_bits; \
  101. /* R3 = 0 on success */ \
  102. addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
  103. ld r0, 16(r1); \
  104. ld r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
  105. ld r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
  106. mtlr r0; \
  107. cmpdi r3, 0; \
  108. blt bpf_error; /* cr0 = LT */ \
  109. ld r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
  110. /* Great success! */
  111. bpf_slow_path_word:
  112. bpf_slow_path_common(4)
  113. /* Data value is on stack, and cr0 != LT */
  114. lwz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
  115. blr
  116. bpf_slow_path_half:
  117. bpf_slow_path_common(2)
  118. lhz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
  119. blr
  120. bpf_slow_path_byte:
  121. bpf_slow_path_common(1)
  122. lbz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
  123. blr
  124. bpf_slow_path_byte_msh:
  125. bpf_slow_path_common(1)
  126. lbz r_X, BPF_PPC_STACK_BASIC+(2*8)(r1)
  127. rlwinm r_X, r_X, 2, 32-4-2, 31-2
  128. blr
  129. /* Call out to bpf_internal_load_pointer_neg_helper:
  130. * We'll need to back up our volatile regs first; we have
  131. * local variable space at r1+(BPF_PPC_STACK_BASIC).
  132. * Allocate a new stack frame here to remain ABI-compliant in
  133. * stashing LR.
  134. */
  135. #define sk_negative_common(SIZE) \
  136. mflr r0; \
  137. std r0, 16(r1); \
  138. /* R3 goes in parameter space of caller's frame */ \
  139. std r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
  140. std r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
  141. std r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
  142. stdu r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
  143. /* R3 = r_skb, as passed */ \
  144. mr r4, r_addr; \
  145. li r5, SIZE; \
  146. bl bpf_internal_load_pointer_neg_helper; \
  147. /* R3 != 0 on success */ \
  148. addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
  149. ld r0, 16(r1); \
  150. ld r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
  151. ld r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
  152. mtlr r0; \
  153. cmpldi r3, 0; \
  154. beq bpf_error_slow; /* cr0 = EQ */ \
  155. mr r_addr, r3; \
  156. ld r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
  157. /* Great success! */
  158. bpf_slow_path_word_neg:
  159. lis r_scratch1,-32 /* SKF_LL_OFF */
  160. cmpd r_addr, r_scratch1 /* addr < SKF_* */
  161. blt bpf_error /* cr0 = LT */
  162. .globl sk_load_word_negative_offset
  163. sk_load_word_negative_offset:
  164. sk_negative_common(4)
  165. lwz r_A, 0(r_addr)
  166. blr
  167. bpf_slow_path_half_neg:
  168. lis r_scratch1,-32 /* SKF_LL_OFF */
  169. cmpd r_addr, r_scratch1 /* addr < SKF_* */
  170. blt bpf_error /* cr0 = LT */
  171. .globl sk_load_half_negative_offset
  172. sk_load_half_negative_offset:
  173. sk_negative_common(2)
  174. lhz r_A, 0(r_addr)
  175. blr
  176. bpf_slow_path_byte_neg:
  177. lis r_scratch1,-32 /* SKF_LL_OFF */
  178. cmpd r_addr, r_scratch1 /* addr < SKF_* */
  179. blt bpf_error /* cr0 = LT */
  180. .globl sk_load_byte_negative_offset
  181. sk_load_byte_negative_offset:
  182. sk_negative_common(1)
  183. lbz r_A, 0(r_addr)
  184. blr
  185. bpf_slow_path_byte_msh_neg:
  186. lis r_scratch1,-32 /* SKF_LL_OFF */
  187. cmpd r_addr, r_scratch1 /* addr < SKF_* */
  188. blt bpf_error /* cr0 = LT */
  189. .globl sk_load_byte_msh_negative_offset
  190. sk_load_byte_msh_negative_offset:
  191. sk_negative_common(1)
  192. lbz r_X, 0(r_addr)
  193. rlwinm r_X, r_X, 2, 32-4-2, 31-2
  194. blr
  195. bpf_error_slow:
  196. /* fabricate a cr0 = lt */
  197. li r_scratch1, -1
  198. cmpdi r_scratch1, 0
  199. bpf_error:
  200. /* Entered with cr0 = lt */
  201. li r3, 0
  202. /* Generated code will 'blt epilogue', returning 0. */
  203. blr