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