diff options
Diffstat (limited to 'arch/sparc/net/bpf_jit_comp.c')
| -rw-r--r-- | arch/sparc/net/bpf_jit_comp.c | 107 |
1 files changed, 63 insertions, 44 deletions
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c index ebc89809f585..4ce0296575eb 100644 --- a/arch/sparc/net/bpf_jit_comp.c +++ b/arch/sparc/net/bpf_jit_comp.c | |||
| @@ -11,20 +11,6 @@ | |||
| 11 | 11 | ||
| 12 | int bpf_jit_enable __read_mostly; | 12 | int bpf_jit_enable __read_mostly; |
| 13 | 13 | ||
| 14 | /* assembly code in arch/sparc/net/bpf_jit_asm.S */ | ||
| 15 | extern u32 bpf_jit_load_word[]; | ||
| 16 | extern u32 bpf_jit_load_half[]; | ||
| 17 | extern u32 bpf_jit_load_byte[]; | ||
| 18 | extern u32 bpf_jit_load_byte_msh[]; | ||
| 19 | extern u32 bpf_jit_load_word_positive_offset[]; | ||
| 20 | extern u32 bpf_jit_load_half_positive_offset[]; | ||
| 21 | extern u32 bpf_jit_load_byte_positive_offset[]; | ||
| 22 | extern u32 bpf_jit_load_byte_msh_positive_offset[]; | ||
| 23 | extern u32 bpf_jit_load_word_negative_offset[]; | ||
| 24 | extern u32 bpf_jit_load_half_negative_offset[]; | ||
| 25 | extern u32 bpf_jit_load_byte_negative_offset[]; | ||
| 26 | extern u32 bpf_jit_load_byte_msh_negative_offset[]; | ||
| 27 | |||
| 28 | static inline bool is_simm13(unsigned int value) | 14 | static inline bool is_simm13(unsigned int value) |
| 29 | { | 15 | { |
| 30 | return value + 0x1000 < 0x2000; | 16 | return value + 0x1000 < 0x2000; |
| @@ -65,22 +51,22 @@ static void bpf_flush_icache(void *start_, void *end_) | |||
| 65 | #define F2(X, Y) (OP(X) | OP2(Y)) | 51 | #define F2(X, Y) (OP(X) | OP2(Y)) |
| 66 | #define F3(X, Y) (OP(X) | OP3(Y)) | 52 | #define F3(X, Y) (OP(X) | OP3(Y)) |
| 67 | 53 | ||
| 68 | #define CONDN COND (0x0) | 54 | #define CONDN COND(0x0) |
| 69 | #define CONDE COND (0x1) | 55 | #define CONDE COND(0x1) |
| 70 | #define CONDLE COND (0x2) | 56 | #define CONDLE COND(0x2) |
| 71 | #define CONDL COND (0x3) | 57 | #define CONDL COND(0x3) |
| 72 | #define CONDLEU COND (0x4) | 58 | #define CONDLEU COND(0x4) |
| 73 | #define CONDCS COND (0x5) | 59 | #define CONDCS COND(0x5) |
| 74 | #define CONDNEG COND (0x6) | 60 | #define CONDNEG COND(0x6) |
| 75 | #define CONDVC COND (0x7) | 61 | #define CONDVC COND(0x7) |
| 76 | #define CONDA COND (0x8) | 62 | #define CONDA COND(0x8) |
| 77 | #define CONDNE COND (0x9) | 63 | #define CONDNE COND(0x9) |
| 78 | #define CONDG COND (0xa) | 64 | #define CONDG COND(0xa) |
| 79 | #define CONDGE COND (0xb) | 65 | #define CONDGE COND(0xb) |
| 80 | #define CONDGU COND (0xc) | 66 | #define CONDGU COND(0xc) |
| 81 | #define CONDCC COND (0xd) | 67 | #define CONDCC COND(0xd) |
| 82 | #define CONDPOS COND (0xe) | 68 | #define CONDPOS COND(0xe) |
| 83 | #define CONDVS COND (0xf) | 69 | #define CONDVS COND(0xf) |
| 84 | 70 | ||
| 85 | #define CONDGEU CONDCC | 71 | #define CONDGEU CONDCC |
| 86 | #define CONDLU CONDCS | 72 | #define CONDLU CONDCS |
| @@ -172,7 +158,7 @@ do { /* sethi %hi(K), REG */ \ | |||
| 172 | 158 | ||
| 173 | /* Emit | 159 | /* Emit |
| 174 | * | 160 | * |
| 175 | * OP r_A, r_X, r_A | 161 | * OP r_A, r_X, r_A |
| 176 | */ | 162 | */ |
| 177 | #define emit_alu_X(OPCODE) \ | 163 | #define emit_alu_X(OPCODE) \ |
| 178 | do { \ | 164 | do { \ |
| @@ -195,7 +181,7 @@ do { \ | |||
| 195 | * is zero. | 181 | * is zero. |
| 196 | */ | 182 | */ |
| 197 | #define emit_alu_K(OPCODE, K) \ | 183 | #define emit_alu_K(OPCODE, K) \ |
| 198 | do { \ | 184 | do { \ |
| 199 | if (K) { \ | 185 | if (K) { \ |
| 200 | unsigned int _insn = OPCODE; \ | 186 | unsigned int _insn = OPCODE; \ |
| 201 | _insn |= RS1(r_A) | RD(r_A); \ | 187 | _insn |= RS1(r_A) | RD(r_A); \ |
| @@ -204,7 +190,7 @@ do { \ | |||
| 204 | } else { \ | 190 | } else { \ |
| 205 | emit_set_const(K, r_TMP); \ | 191 | emit_set_const(K, r_TMP); \ |
| 206 | *prog++ = _insn | RS2(r_TMP); \ | 192 | *prog++ = _insn | RS2(r_TMP); \ |
| 207 | } \ | 193 | } \ |
| 208 | } \ | 194 | } \ |
| 209 | } while (0) | 195 | } while (0) |
| 210 | 196 | ||
| @@ -222,37 +208,37 @@ do { \ | |||
| 222 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ | 208 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ |
| 223 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(void *)); \ | 209 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(void *)); \ |
| 224 | *prog++ = LDPTRI | RS1(BASE) | S13(_off) | RD(DEST); \ | 210 | *prog++ = LDPTRI | RS1(BASE) | S13(_off) | RD(DEST); \ |
| 225 | } while(0) | 211 | } while (0) |
| 226 | 212 | ||
| 227 | #define emit_load32(BASE, STRUCT, FIELD, DEST) \ | 213 | #define emit_load32(BASE, STRUCT, FIELD, DEST) \ |
| 228 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ | 214 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ |
| 229 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u32)); \ | 215 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u32)); \ |
| 230 | *prog++ = LD32I | RS1(BASE) | S13(_off) | RD(DEST); \ | 216 | *prog++ = LD32I | RS1(BASE) | S13(_off) | RD(DEST); \ |
| 231 | } while(0) | 217 | } while (0) |
| 232 | 218 | ||
| 233 | #define emit_load16(BASE, STRUCT, FIELD, DEST) \ | 219 | #define emit_load16(BASE, STRUCT, FIELD, DEST) \ |
| 234 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ | 220 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ |
| 235 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u16)); \ | 221 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u16)); \ |
| 236 | *prog++ = LD16I | RS1(BASE) | S13(_off) | RD(DEST); \ | 222 | *prog++ = LD16I | RS1(BASE) | S13(_off) | RD(DEST); \ |
| 237 | } while(0) | 223 | } while (0) |
| 238 | 224 | ||
| 239 | #define __emit_load8(BASE, STRUCT, FIELD, DEST) \ | 225 | #define __emit_load8(BASE, STRUCT, FIELD, DEST) \ |
| 240 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ | 226 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ |
| 241 | *prog++ = LD8I | RS1(BASE) | S13(_off) | RD(DEST); \ | 227 | *prog++ = LD8I | RS1(BASE) | S13(_off) | RD(DEST); \ |
| 242 | } while(0) | 228 | } while (0) |
| 243 | 229 | ||
| 244 | #define emit_load8(BASE, STRUCT, FIELD, DEST) \ | 230 | #define emit_load8(BASE, STRUCT, FIELD, DEST) \ |
| 245 | do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \ | 231 | do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \ |
| 246 | __emit_load8(BASE, STRUCT, FIELD, DEST); \ | 232 | __emit_load8(BASE, STRUCT, FIELD, DEST); \ |
| 247 | } while(0) | 233 | } while (0) |
| 248 | 234 | ||
| 249 | #define emit_ldmem(OFF, DEST) \ | 235 | #define emit_ldmem(OFF, DEST) \ |
| 250 | do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(DEST); \ | 236 | do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(DEST); \ |
| 251 | } while(0) | 237 | } while (0) |
| 252 | 238 | ||
| 253 | #define emit_stmem(OFF, SRC) \ | 239 | #define emit_stmem(OFF, SRC) \ |
| 254 | do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(SRC); \ | 240 | do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(SRC); \ |
| 255 | } while(0) | 241 | } while (0) |
| 256 | 242 | ||
| 257 | #define cpu_off offsetof(struct thread_info, cpu) | 243 | #define cpu_off offsetof(struct thread_info, cpu) |
| 258 | 244 | ||
| @@ -292,16 +278,16 @@ do { void *_here = image + addrs[i] - 8; \ | |||
| 292 | #define emit_branch(BR_OPC, DEST) \ | 278 | #define emit_branch(BR_OPC, DEST) \ |
| 293 | do { unsigned int _here = addrs[i] - 8; \ | 279 | do { unsigned int _here = addrs[i] - 8; \ |
| 294 | *prog++ = BR_OPC | WDISP22((DEST) - _here); \ | 280 | *prog++ = BR_OPC | WDISP22((DEST) - _here); \ |
| 295 | } while(0) | 281 | } while (0) |
| 296 | 282 | ||
| 297 | #define emit_branch_off(BR_OPC, OFF) \ | 283 | #define emit_branch_off(BR_OPC, OFF) \ |
| 298 | do { *prog++ = BR_OPC | WDISP22(OFF); \ | 284 | do { *prog++ = BR_OPC | WDISP22(OFF); \ |
| 299 | } while(0) | 285 | } while (0) |
| 300 | 286 | ||
| 301 | #define emit_jump(DEST) emit_branch(BA, DEST) | 287 | #define emit_jump(DEST) emit_branch(BA, DEST) |
| 302 | 288 | ||
| 303 | #define emit_read_y(REG) *prog++ = RD_Y | RD(REG); | 289 | #define emit_read_y(REG) *prog++ = RD_Y | RD(REG) |
| 304 | #define emit_write_y(REG) *prog++ = WR_Y | IMMED | RS1(REG) | S13(0); | 290 | #define emit_write_y(REG) *prog++ = WR_Y | IMMED | RS1(REG) | S13(0) |
| 305 | 291 | ||
| 306 | #define emit_cmp(R1, R2) \ | 292 | #define emit_cmp(R1, R2) \ |
| 307 | *prog++ = (SUBCC | RS1(R1) | RS2(R2) | RD(G0)) | 293 | *prog++ = (SUBCC | RS1(R1) | RS2(R2) | RD(G0)) |
| @@ -333,6 +319,35 @@ do { *prog++ = BR_OPC | WDISP22(OFF); \ | |||
| 333 | #define emit_release_stack(SZ) \ | 319 | #define emit_release_stack(SZ) \ |
| 334 | *prog++ = (ADD | IMMED | RS1(SP) | S13(SZ) | RD(SP)) | 320 | *prog++ = (ADD | IMMED | RS1(SP) | S13(SZ) | RD(SP)) |
| 335 | 321 | ||
| 322 | /* A note about branch offset calculations. The addrs[] array, | ||
| 323 | * indexed by BPF instruction, records the address after all the | ||
| 324 | * sparc instructions emitted for that BPF instruction. | ||
| 325 | * | ||
| 326 | * The most common case is to emit a branch at the end of such | ||
| 327 | * a code sequence. So this would be two instructions, the | ||
| 328 | * branch and it's delay slot. | ||
| 329 | * | ||
| 330 | * Therefore by default the branch emitters calculate the branch | ||
| 331 | * offset field as: | ||
| 332 | * | ||
| 333 | * destination - (addrs[i] - 8) | ||
| 334 | * | ||
| 335 | * This "addrs[i] - 8" is the address of the branch itself or | ||
| 336 | * what "." would be in assembler notation. The "8" part is | ||
| 337 | * how we take into consideration the branch and it's delay | ||
| 338 | * slot mentioned above. | ||
| 339 | * | ||
| 340 | * Sometimes we need to emit a branch earlier in the code | ||
| 341 | * sequence. And in these situations we adjust "destination" | ||
| 342 | * to accomodate this difference. For example, if we needed | ||
| 343 | * to emit a branch (and it's delay slot) right before the | ||
| 344 | * final instruction emitted for a BPF opcode, we'd use | ||
| 345 | * "destination + 4" instead of just plain "destination" above. | ||
| 346 | * | ||
| 347 | * This is why you see all of these funny emit_branch() and | ||
| 348 | * emit_jump() calls with adjusted offsets. | ||
| 349 | */ | ||
| 350 | |||
| 336 | void bpf_jit_compile(struct sk_filter *fp) | 351 | void bpf_jit_compile(struct sk_filter *fp) |
| 337 | { | 352 | { |
| 338 | unsigned int cleanup_addr, proglen, oldproglen = 0; | 353 | unsigned int cleanup_addr, proglen, oldproglen = 0; |
| @@ -493,6 +508,10 @@ void bpf_jit_compile(struct sk_filter *fp) | |||
| 493 | } | 508 | } |
| 494 | emit_write_y(G0); | 509 | emit_write_y(G0); |
| 495 | #ifdef CONFIG_SPARC32 | 510 | #ifdef CONFIG_SPARC32 |
| 511 | /* The Sparc v8 architecture requires | ||
| 512 | * three instructions between a %y | ||
| 513 | * register write and the first use. | ||
| 514 | */ | ||
| 496 | emit_nop(); | 515 | emit_nop(); |
| 497 | emit_nop(); | 516 | emit_nop(); |
| 498 | emit_nop(); | 517 | emit_nop(); |
