bpf_jit_asm.S 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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_jit32.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. PPC_LCMPI 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. PPC_LCMP r_scratch1, r_addr
  41. blt bpf_slow_path_word
  42. /* Nope, just hitting the header. cr0 here is eq or gt! */
  43. #ifdef __LITTLE_ENDIAN__
  44. lwbrx r_A, r_D, r_addr
  45. #else
  46. lwzx r_A, r_D, r_addr
  47. #endif
  48. blr /* Return success, cr0 != LT */
  49. .globl sk_load_half
  50. sk_load_half:
  51. PPC_LCMPI r_addr, 0
  52. blt bpf_slow_path_half_neg
  53. .globl sk_load_half_positive_offset
  54. sk_load_half_positive_offset:
  55. subi r_scratch1, r_HL, 2
  56. PPC_LCMP r_scratch1, r_addr
  57. blt bpf_slow_path_half
  58. #ifdef __LITTLE_ENDIAN__
  59. lhbrx r_A, r_D, r_addr
  60. #else
  61. lhzx r_A, r_D, r_addr
  62. #endif
  63. blr
  64. .globl sk_load_byte
  65. sk_load_byte:
  66. PPC_LCMPI r_addr, 0
  67. blt bpf_slow_path_byte_neg
  68. .globl sk_load_byte_positive_offset
  69. sk_load_byte_positive_offset:
  70. PPC_LCMP r_HL, r_addr
  71. ble bpf_slow_path_byte
  72. lbzx r_A, r_D, r_addr
  73. blr
  74. /*
  75. * BPF_LDX | BPF_B | BPF_MSH: ldxb 4*([offset]&0xf)
  76. * r_addr is the offset value
  77. */
  78. .globl sk_load_byte_msh
  79. sk_load_byte_msh:
  80. PPC_LCMPI r_addr, 0
  81. blt bpf_slow_path_byte_msh_neg
  82. .globl sk_load_byte_msh_positive_offset
  83. sk_load_byte_msh_positive_offset:
  84. PPC_LCMP r_HL, r_addr
  85. ble bpf_slow_path_byte_msh
  86. lbzx r_X, r_D, r_addr
  87. rlwinm r_X, r_X, 2, 32-4-2, 31-2
  88. blr
  89. /* Call out to skb_copy_bits:
  90. * We'll need to back up our volatile regs first; we have
  91. * local variable space at r1+(BPF_PPC_STACK_BASIC).
  92. * Allocate a new stack frame here to remain ABI-compliant in
  93. * stashing LR.
  94. */
  95. #define bpf_slow_path_common(SIZE) \
  96. mflr r0; \
  97. PPC_STL r0, PPC_LR_STKOFF(r1); \
  98. /* R3 goes in parameter space of caller's frame */ \
  99. PPC_STL r_skb, (BPF_PPC_STACKFRAME+BPF_PPC_STACK_R3_OFF)(r1); \
  100. PPC_STL r_A, (BPF_PPC_STACK_BASIC+(0*REG_SZ))(r1); \
  101. PPC_STL r_X, (BPF_PPC_STACK_BASIC+(1*REG_SZ))(r1); \
  102. addi r5, r1, BPF_PPC_STACK_BASIC+(2*REG_SZ); \
  103. PPC_STLU r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
  104. /* R3 = r_skb, as passed */ \
  105. mr r4, r_addr; \
  106. li r6, SIZE; \
  107. bl skb_copy_bits; \
  108. nop; \
  109. /* R3 = 0 on success */ \
  110. addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
  111. PPC_LL r0, PPC_LR_STKOFF(r1); \
  112. PPC_LL r_A, (BPF_PPC_STACK_BASIC+(0*REG_SZ))(r1); \
  113. PPC_LL r_X, (BPF_PPC_STACK_BASIC+(1*REG_SZ))(r1); \
  114. mtlr r0; \
  115. PPC_LCMPI r3, 0; \
  116. blt bpf_error; /* cr0 = LT */ \
  117. PPC_LL r_skb, (BPF_PPC_STACKFRAME+BPF_PPC_STACK_R3_OFF)(r1); \
  118. /* Great success! */
  119. bpf_slow_path_word:
  120. bpf_slow_path_common(4)
  121. /* Data value is on stack, and cr0 != LT */
  122. lwz r_A, BPF_PPC_STACK_BASIC+(2*REG_SZ)(r1)
  123. blr
  124. bpf_slow_path_half:
  125. bpf_slow_path_common(2)
  126. lhz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
  127. blr
  128. bpf_slow_path_byte:
  129. bpf_slow_path_common(1)
  130. lbz r_A, BPF_PPC_STACK_BASIC+(2*8)(r1)
  131. blr
  132. bpf_slow_path_byte_msh:
  133. bpf_slow_path_common(1)
  134. lbz r_X, BPF_PPC_STACK_BASIC+(2*8)(r1)
  135. rlwinm r_X, r_X, 2, 32-4-2, 31-2
  136. blr
  137. /* Call out to bpf_internal_load_pointer_neg_helper:
  138. * We'll need to back up our volatile regs first; we have
  139. * local variable space at r1+(BPF_PPC_STACK_BASIC).
  140. * Allocate a new stack frame here to remain ABI-compliant in
  141. * stashing LR.
  142. */
  143. #define sk_negative_common(SIZE) \
  144. mflr r0; \
  145. PPC_STL r0, PPC_LR_STKOFF(r1); \
  146. /* R3 goes in parameter space of caller's frame */ \
  147. PPC_STL r_skb, (BPF_PPC_STACKFRAME+BPF_PPC_STACK_R3_OFF)(r1); \
  148. PPC_STL r_A, (BPF_PPC_STACK_BASIC+(0*REG_SZ))(r1); \
  149. PPC_STL r_X, (BPF_PPC_STACK_BASIC+(1*REG_SZ))(r1); \
  150. PPC_STLU r1, -BPF_PPC_SLOWPATH_FRAME(r1); \
  151. /* R3 = r_skb, as passed */ \
  152. mr r4, r_addr; \
  153. li r5, SIZE; \
  154. bl bpf_internal_load_pointer_neg_helper; \
  155. nop; \
  156. /* R3 != 0 on success */ \
  157. addi r1, r1, BPF_PPC_SLOWPATH_FRAME; \
  158. PPC_LL r0, PPC_LR_STKOFF(r1); \
  159. PPC_LL r_A, (BPF_PPC_STACK_BASIC+(0*REG_SZ))(r1); \
  160. PPC_LL r_X, (BPF_PPC_STACK_BASIC+(1*REG_SZ))(r1); \
  161. mtlr r0; \
  162. PPC_LCMPLI r3, 0; \
  163. beq bpf_error_slow; /* cr0 = EQ */ \
  164. mr r_addr, r3; \
  165. PPC_LL r_skb, (BPF_PPC_STACKFRAME+BPF_PPC_STACK_R3_OFF)(r1); \
  166. /* Great success! */
  167. bpf_slow_path_word_neg:
  168. lis r_scratch1,-32 /* SKF_LL_OFF */
  169. PPC_LCMP r_addr, r_scratch1 /* addr < SKF_* */
  170. blt bpf_error /* cr0 = LT */
  171. .globl sk_load_word_negative_offset
  172. sk_load_word_negative_offset:
  173. sk_negative_common(4)
  174. lwz r_A, 0(r_addr)
  175. blr
  176. bpf_slow_path_half_neg:
  177. lis r_scratch1,-32 /* SKF_LL_OFF */
  178. PPC_LCMP r_addr, r_scratch1 /* addr < SKF_* */
  179. blt bpf_error /* cr0 = LT */
  180. .globl sk_load_half_negative_offset
  181. sk_load_half_negative_offset:
  182. sk_negative_common(2)
  183. lhz r_A, 0(r_addr)
  184. blr
  185. bpf_slow_path_byte_neg:
  186. lis r_scratch1,-32 /* SKF_LL_OFF */
  187. PPC_LCMP r_addr, r_scratch1 /* addr < SKF_* */
  188. blt bpf_error /* cr0 = LT */
  189. .globl sk_load_byte_negative_offset
  190. sk_load_byte_negative_offset:
  191. sk_negative_common(1)
  192. lbz r_A, 0(r_addr)
  193. blr
  194. bpf_slow_path_byte_msh_neg:
  195. lis r_scratch1,-32 /* SKF_LL_OFF */
  196. PPC_LCMP r_addr, r_scratch1 /* addr < SKF_* */
  197. blt bpf_error /* cr0 = LT */
  198. .globl sk_load_byte_msh_negative_offset
  199. sk_load_byte_msh_negative_offset:
  200. sk_negative_common(1)
  201. lbz r_X, 0(r_addr)
  202. rlwinm r_X, r_X, 2, 32-4-2, 31-2
  203. blr
  204. bpf_error_slow:
  205. /* fabricate a cr0 = lt */
  206. li r_scratch1, -1
  207. PPC_LCMPI r_scratch1, 0
  208. bpf_error:
  209. /* Entered with cr0 = lt */
  210. li r3, 0
  211. /* Generated code will 'blt epilogue', returning 0. */
  212. blr