bpf_jit_64.S 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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. nop; \
  102. /* R3 = 0 on success */ \
  103. addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
  104. ld r0, 16(r1); \
  105. ld r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
  106. ld r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
  107. mtlr r0; \
  108. cmpdi r3, 0; \
  109. blt bpf_error; /* cr0 = LT */ \
  110. ld r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
  111. /* Great success! */
  112. bpf_slow_path_word:
  113. bpf_slow_path_common(4)
  114. /* Data value is on stack, and cr0 != LT */
  115. lwz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
  116. blr
  117. bpf_slow_path_half:
  118. bpf_slow_path_common(2)
  119. lhz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
  120. blr
  121. bpf_slow_path_byte:
  122. bpf_slow_path_common(1)
  123. lbz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
  124. blr
  125. bpf_slow_path_byte_msh:
  126. bpf_slow_path_common(1)
  127. lbz r_X, BPF_PPC_STACK_BASIC+(2*8)(r1)
  128. rlwinm r_X, r_X, 2, 32-4-2, 31-2
  129. blr
  130. /* Call out to bpf_internal_load_pointer_neg_helper:
  131. * We'll need to back up our volatile regs first; we have
  132. * local variable space at r1+(BPF_PPC_STACK_BASIC).
  133. * Allocate a new stack frame here to remain ABI-compliant in
  134. * stashing LR.
  135. */
  136. #define sk_negative_common(SIZE) \
  137. mflr r0; \
  138. std r0, 16(r1); \
  139. /* R3 goes in parameter space of caller's frame */ \
  140. std r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
  141. std r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
  142. std r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
  143. stdu r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
  144. /* R3 = r_skb, as passed */ \
  145. mr r4, r_addr; \
  146. li r5, SIZE; \
  147. bl bpf_internal_load_pointer_neg_helper; \
  148. nop; \
  149. /* R3 != 0 on success */ \
  150. addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
  151. ld r0, 16(r1); \
  152. ld r_A, (BPF_PPC_STACK_BASIC+(0*8))(r1); \
  153. ld r_X, (BPF_PPC_STACK_BASIC+(1*8))(r1); \
  154. mtlr r0; \
  155. cmpldi r3, 0; \
  156. beq bpf_error_slow; /* cr0 = EQ */ \
  157. mr r_addr, r3; \
  158. ld r_skb, (BPF_PPC_STACKFRAME+48)(r1); \
  159. /* Great success! */
  160. bpf_slow_path_word_neg:
  161. lis r_scratch1,-32 /* SKF_LL_OFF */
  162. cmpd r_addr, r_scratch1 /* addr < SKF_* */
  163. blt bpf_error /* cr0 = LT */
  164. .globl sk_load_word_negative_offset
  165. sk_load_word_negative_offset:
  166. sk_negative_common(4)
  167. lwz r_A, 0(r_addr)
  168. blr
  169. bpf_slow_path_half_neg:
  170. lis r_scratch1,-32 /* SKF_LL_OFF */
  171. cmpd r_addr, r_scratch1 /* addr < SKF_* */
  172. blt bpf_error /* cr0 = LT */
  173. .globl sk_load_half_negative_offset
  174. sk_load_half_negative_offset:
  175. sk_negative_common(2)
  176. lhz r_A, 0(r_addr)
  177. blr
  178. bpf_slow_path_byte_neg:
  179. lis r_scratch1,-32 /* SKF_LL_OFF */
  180. cmpd r_addr, r_scratch1 /* addr < SKF_* */
  181. blt bpf_error /* cr0 = LT */
  182. .globl sk_load_byte_negative_offset
  183. sk_load_byte_negative_offset:
  184. sk_negative_common(1)
  185. lbz r_A, 0(r_addr)
  186. blr
  187. bpf_slow_path_byte_msh_neg:
  188. lis r_scratch1,-32 /* SKF_LL_OFF */
  189. cmpd r_addr, r_scratch1 /* addr < SKF_* */
  190. blt bpf_error /* cr0 = LT */
  191. .globl sk_load_byte_msh_negative_offset
  192. sk_load_byte_msh_negative_offset:
  193. sk_negative_common(1)
  194. lbz r_X, 0(r_addr)
  195. rlwinm r_X, r_X, 2, 32-4-2, 31-2
  196. blr
  197. bpf_error_slow:
  198. /* fabricate a cr0 = lt */
  199. li r_scratch1, -1
  200. cmpdi r_scratch1, 0
  201. bpf_error:
  202. /* Entered with cr0 = lt */
  203. li r3, 0
  204. /* Generated code will 'blt epilogue', returning 0. */
  205. blr