net: filter: Fix some more small issues in sparc JIT.
Fix mixed space and tabs. Put bpf_jit_load_*[] externs into bpf_jit.h "while(0)" --> "while (0)" "COND (X)" --> "COND(X)" Document branch offset calculations, and bpf_error's return sequence. Document the reason we need to emit three nops between the %y register write and the divide instruction. Remove erroneous trailing semicolons from emit_read_y() and emit_write_y(). Based upon feedback from Sam Ravnborg. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7b56f76edf
commit
584c5e2ad3
3 changed files with 84 additions and 44 deletions
|
@ -38,6 +38,21 @@
|
||||||
#define r_TMP G1
|
#define r_TMP G1
|
||||||
#define r_TMP2 G2
|
#define r_TMP2 G2
|
||||||
#define r_OFF G3
|
#define r_OFF G3
|
||||||
|
|
||||||
|
/* assembly code in arch/sparc/net/bpf_jit_asm.S */
|
||||||
|
extern u32 bpf_jit_load_word[];
|
||||||
|
extern u32 bpf_jit_load_half[];
|
||||||
|
extern u32 bpf_jit_load_byte[];
|
||||||
|
extern u32 bpf_jit_load_byte_msh[];
|
||||||
|
extern u32 bpf_jit_load_word_positive_offset[];
|
||||||
|
extern u32 bpf_jit_load_half_positive_offset[];
|
||||||
|
extern u32 bpf_jit_load_byte_positive_offset[];
|
||||||
|
extern u32 bpf_jit_load_byte_msh_positive_offset[];
|
||||||
|
extern u32 bpf_jit_load_word_negative_offset[];
|
||||||
|
extern u32 bpf_jit_load_half_negative_offset[];
|
||||||
|
extern u32 bpf_jit_load_byte_negative_offset[];
|
||||||
|
extern u32 bpf_jit_load_byte_msh_negative_offset[];
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define r_SKB %o0
|
#define r_SKB %o0
|
||||||
#define r_A %o1
|
#define r_A %o1
|
||||||
|
|
|
@ -195,5 +195,11 @@ bpf_jit_load_byte_msh_negative_offset:
|
||||||
sll r_OFF, 2, r_X
|
sll r_OFF, 2, r_X
|
||||||
|
|
||||||
bpf_error:
|
bpf_error:
|
||||||
|
/* Make the JIT program return zero. The JIT epilogue
|
||||||
|
* stores away the original %o7 into r_saved_O7. The
|
||||||
|
* normal leaf function return is to use "retl" which
|
||||||
|
* would evalute to "jmpl %o7 + 8, %g0" but we want to
|
||||||
|
* use the saved value thus the sequence you see here.
|
||||||
|
*/
|
||||||
jmpl r_saved_O7 + 8, %g0
|
jmpl r_saved_O7 + 8, %g0
|
||||||
clr %o0
|
clr %o0
|
||||||
|
|
|
@ -11,20 +11,6 @@
|
||||||
|
|
||||||
int bpf_jit_enable __read_mostly;
|
int bpf_jit_enable __read_mostly;
|
||||||
|
|
||||||
/* assembly code in arch/sparc/net/bpf_jit_asm.S */
|
|
||||||
extern u32 bpf_jit_load_word[];
|
|
||||||
extern u32 bpf_jit_load_half[];
|
|
||||||
extern u32 bpf_jit_load_byte[];
|
|
||||||
extern u32 bpf_jit_load_byte_msh[];
|
|
||||||
extern u32 bpf_jit_load_word_positive_offset[];
|
|
||||||
extern u32 bpf_jit_load_half_positive_offset[];
|
|
||||||
extern u32 bpf_jit_load_byte_positive_offset[];
|
|
||||||
extern u32 bpf_jit_load_byte_msh_positive_offset[];
|
|
||||||
extern u32 bpf_jit_load_word_negative_offset[];
|
|
||||||
extern u32 bpf_jit_load_half_negative_offset[];
|
|
||||||
extern u32 bpf_jit_load_byte_negative_offset[];
|
|
||||||
extern u32 bpf_jit_load_byte_msh_negative_offset[];
|
|
||||||
|
|
||||||
static inline bool is_simm13(unsigned int value)
|
static inline bool is_simm13(unsigned int value)
|
||||||
{
|
{
|
||||||
return value + 0x1000 < 0x2000;
|
return value + 0x1000 < 0x2000;
|
||||||
|
@ -65,22 +51,22 @@ static void bpf_flush_icache(void *start_, void *end_)
|
||||||
#define F2(X, Y) (OP(X) | OP2(Y))
|
#define F2(X, Y) (OP(X) | OP2(Y))
|
||||||
#define F3(X, Y) (OP(X) | OP3(Y))
|
#define F3(X, Y) (OP(X) | OP3(Y))
|
||||||
|
|
||||||
#define CONDN COND (0x0)
|
#define CONDN COND(0x0)
|
||||||
#define CONDE COND (0x1)
|
#define CONDE COND(0x1)
|
||||||
#define CONDLE COND (0x2)
|
#define CONDLE COND(0x2)
|
||||||
#define CONDL COND (0x3)
|
#define CONDL COND(0x3)
|
||||||
#define CONDLEU COND (0x4)
|
#define CONDLEU COND(0x4)
|
||||||
#define CONDCS COND (0x5)
|
#define CONDCS COND(0x5)
|
||||||
#define CONDNEG COND (0x6)
|
#define CONDNEG COND(0x6)
|
||||||
#define CONDVC COND (0x7)
|
#define CONDVC COND(0x7)
|
||||||
#define CONDA COND (0x8)
|
#define CONDA COND(0x8)
|
||||||
#define CONDNE COND (0x9)
|
#define CONDNE COND(0x9)
|
||||||
#define CONDG COND (0xa)
|
#define CONDG COND(0xa)
|
||||||
#define CONDGE COND (0xb)
|
#define CONDGE COND(0xb)
|
||||||
#define CONDGU COND (0xc)
|
#define CONDGU COND(0xc)
|
||||||
#define CONDCC COND (0xd)
|
#define CONDCC COND(0xd)
|
||||||
#define CONDPOS COND (0xe)
|
#define CONDPOS COND(0xe)
|
||||||
#define CONDVS COND (0xf)
|
#define CONDVS COND(0xf)
|
||||||
|
|
||||||
#define CONDGEU CONDCC
|
#define CONDGEU CONDCC
|
||||||
#define CONDLU CONDCS
|
#define CONDLU CONDCS
|
||||||
|
@ -172,7 +158,7 @@ do { /* sethi %hi(K), REG */ \
|
||||||
|
|
||||||
/* Emit
|
/* Emit
|
||||||
*
|
*
|
||||||
* OP r_A, r_X, r_A
|
* OP r_A, r_X, r_A
|
||||||
*/
|
*/
|
||||||
#define emit_alu_X(OPCODE) \
|
#define emit_alu_X(OPCODE) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -195,7 +181,7 @@ do { \
|
||||||
* is zero.
|
* is zero.
|
||||||
*/
|
*/
|
||||||
#define emit_alu_K(OPCODE, K) \
|
#define emit_alu_K(OPCODE, K) \
|
||||||
do { \
|
do { \
|
||||||
if (K) { \
|
if (K) { \
|
||||||
unsigned int _insn = OPCODE; \
|
unsigned int _insn = OPCODE; \
|
||||||
_insn |= RS1(r_A) | RD(r_A); \
|
_insn |= RS1(r_A) | RD(r_A); \
|
||||||
|
@ -204,7 +190,7 @@ do { \
|
||||||
} else { \
|
} else { \
|
||||||
emit_set_const(K, r_TMP); \
|
emit_set_const(K, r_TMP); \
|
||||||
*prog++ = _insn | RS2(r_TMP); \
|
*prog++ = _insn | RS2(r_TMP); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -222,37 +208,37 @@ do { \
|
||||||
do { unsigned int _off = offsetof(STRUCT, FIELD); \
|
do { unsigned int _off = offsetof(STRUCT, FIELD); \
|
||||||
BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(void *)); \
|
BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(void *)); \
|
||||||
*prog++ = LDPTRI | RS1(BASE) | S13(_off) | RD(DEST); \
|
*prog++ = LDPTRI | RS1(BASE) | S13(_off) | RD(DEST); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define emit_load32(BASE, STRUCT, FIELD, DEST) \
|
#define emit_load32(BASE, STRUCT, FIELD, DEST) \
|
||||||
do { unsigned int _off = offsetof(STRUCT, FIELD); \
|
do { unsigned int _off = offsetof(STRUCT, FIELD); \
|
||||||
BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u32)); \
|
BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u32)); \
|
||||||
*prog++ = LD32I | RS1(BASE) | S13(_off) | RD(DEST); \
|
*prog++ = LD32I | RS1(BASE) | S13(_off) | RD(DEST); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define emit_load16(BASE, STRUCT, FIELD, DEST) \
|
#define emit_load16(BASE, STRUCT, FIELD, DEST) \
|
||||||
do { unsigned int _off = offsetof(STRUCT, FIELD); \
|
do { unsigned int _off = offsetof(STRUCT, FIELD); \
|
||||||
BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u16)); \
|
BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u16)); \
|
||||||
*prog++ = LD16I | RS1(BASE) | S13(_off) | RD(DEST); \
|
*prog++ = LD16I | RS1(BASE) | S13(_off) | RD(DEST); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define __emit_load8(BASE, STRUCT, FIELD, DEST) \
|
#define __emit_load8(BASE, STRUCT, FIELD, DEST) \
|
||||||
do { unsigned int _off = offsetof(STRUCT, FIELD); \
|
do { unsigned int _off = offsetof(STRUCT, FIELD); \
|
||||||
*prog++ = LD8I | RS1(BASE) | S13(_off) | RD(DEST); \
|
*prog++ = LD8I | RS1(BASE) | S13(_off) | RD(DEST); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define emit_load8(BASE, STRUCT, FIELD, DEST) \
|
#define emit_load8(BASE, STRUCT, FIELD, DEST) \
|
||||||
do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \
|
do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \
|
||||||
__emit_load8(BASE, STRUCT, FIELD, DEST); \
|
__emit_load8(BASE, STRUCT, FIELD, DEST); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define emit_ldmem(OFF, DEST) \
|
#define emit_ldmem(OFF, DEST) \
|
||||||
do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(DEST); \
|
do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(DEST); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define emit_stmem(OFF, SRC) \
|
#define emit_stmem(OFF, SRC) \
|
||||||
do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(SRC); \
|
do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(SRC); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define cpu_off offsetof(struct thread_info, cpu)
|
#define cpu_off offsetof(struct thread_info, cpu)
|
||||||
|
|
||||||
|
@ -292,16 +278,16 @@ do { void *_here = image + addrs[i] - 8; \
|
||||||
#define emit_branch(BR_OPC, DEST) \
|
#define emit_branch(BR_OPC, DEST) \
|
||||||
do { unsigned int _here = addrs[i] - 8; \
|
do { unsigned int _here = addrs[i] - 8; \
|
||||||
*prog++ = BR_OPC | WDISP22((DEST) - _here); \
|
*prog++ = BR_OPC | WDISP22((DEST) - _here); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define emit_branch_off(BR_OPC, OFF) \
|
#define emit_branch_off(BR_OPC, OFF) \
|
||||||
do { *prog++ = BR_OPC | WDISP22(OFF); \
|
do { *prog++ = BR_OPC | WDISP22(OFF); \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#define emit_jump(DEST) emit_branch(BA, DEST)
|
#define emit_jump(DEST) emit_branch(BA, DEST)
|
||||||
|
|
||||||
#define emit_read_y(REG) *prog++ = RD_Y | RD(REG);
|
#define emit_read_y(REG) *prog++ = RD_Y | RD(REG)
|
||||||
#define emit_write_y(REG) *prog++ = WR_Y | IMMED | RS1(REG) | S13(0);
|
#define emit_write_y(REG) *prog++ = WR_Y | IMMED | RS1(REG) | S13(0)
|
||||||
|
|
||||||
#define emit_cmp(R1, R2) \
|
#define emit_cmp(R1, R2) \
|
||||||
*prog++ = (SUBCC | RS1(R1) | RS2(R2) | RD(G0))
|
*prog++ = (SUBCC | RS1(R1) | RS2(R2) | RD(G0))
|
||||||
|
@ -333,6 +319,35 @@ do { *prog++ = BR_OPC | WDISP22(OFF); \
|
||||||
#define emit_release_stack(SZ) \
|
#define emit_release_stack(SZ) \
|
||||||
*prog++ = (ADD | IMMED | RS1(SP) | S13(SZ) | RD(SP))
|
*prog++ = (ADD | IMMED | RS1(SP) | S13(SZ) | RD(SP))
|
||||||
|
|
||||||
|
/* A note about branch offset calculations. The addrs[] array,
|
||||||
|
* indexed by BPF instruction, records the address after all the
|
||||||
|
* sparc instructions emitted for that BPF instruction.
|
||||||
|
*
|
||||||
|
* The most common case is to emit a branch at the end of such
|
||||||
|
* a code sequence. So this would be two instructions, the
|
||||||
|
* branch and it's delay slot.
|
||||||
|
*
|
||||||
|
* Therefore by default the branch emitters calculate the branch
|
||||||
|
* offset field as:
|
||||||
|
*
|
||||||
|
* destination - (addrs[i] - 8)
|
||||||
|
*
|
||||||
|
* This "addrs[i] - 8" is the address of the branch itself or
|
||||||
|
* what "." would be in assembler notation. The "8" part is
|
||||||
|
* how we take into consideration the branch and it's delay
|
||||||
|
* slot mentioned above.
|
||||||
|
*
|
||||||
|
* Sometimes we need to emit a branch earlier in the code
|
||||||
|
* sequence. And in these situations we adjust "destination"
|
||||||
|
* to accomodate this difference. For example, if we needed
|
||||||
|
* to emit a branch (and it's delay slot) right before the
|
||||||
|
* final instruction emitted for a BPF opcode, we'd use
|
||||||
|
* "destination + 4" instead of just plain "destination" above.
|
||||||
|
*
|
||||||
|
* This is why you see all of these funny emit_branch() and
|
||||||
|
* emit_jump() calls with adjusted offsets.
|
||||||
|
*/
|
||||||
|
|
||||||
void bpf_jit_compile(struct sk_filter *fp)
|
void bpf_jit_compile(struct sk_filter *fp)
|
||||||
{
|
{
|
||||||
unsigned int cleanup_addr, proglen, oldproglen = 0;
|
unsigned int cleanup_addr, proglen, oldproglen = 0;
|
||||||
|
@ -493,6 +508,10 @@ void bpf_jit_compile(struct sk_filter *fp)
|
||||||
}
|
}
|
||||||
emit_write_y(G0);
|
emit_write_y(G0);
|
||||||
#ifdef CONFIG_SPARC32
|
#ifdef CONFIG_SPARC32
|
||||||
|
/* The Sparc v8 architecture requires
|
||||||
|
* three instructions between a %y
|
||||||
|
* register write and the first use.
|
||||||
|
*/
|
||||||
emit_nop();
|
emit_nop();
|
||||||
emit_nop();
|
emit_nop();
|
||||||
emit_nop();
|
emit_nop();
|
||||||
|
|
Loading…
Reference in a new issue