Skip to content

Commit

Permalink
Add support for EBPF_CLS_JMP32 JIT and interpret (#166)
Browse files Browse the repository at this point in the history
* Add support for EBPF_CLS_JMP32 x64 JIT and interpret

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Attempt JIT arm64 changes for EBPF_CLS_JMP32

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Fix Windows path to test files

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Add support for jmp32 with imm

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* All jmp32 ops pass on arm64

Signed-off-by: Alan Jowett <alanjo@microsoft.com>

* Rollback unintended changes

Signed-off-by: Alan Jowett <alanjo@microsoft.com>
  • Loading branch information
Alan-Jowett committed Oct 19, 2022
1 parent 9804aef commit ff9ba9b
Show file tree
Hide file tree
Showing 5 changed files with 359 additions and 56 deletions.
91 changes: 66 additions & 25 deletions vm/ebpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ struct ebpf_inst {

#define EBPF_CLS_MASK 0x07
#define EBPF_ALU_OP_MASK 0xf0
#define EBPF_JMP_OP_MASK 0xf0

#define EBPF_CLS_LD 0x00
#define EBPF_CLS_LDX 0x01
#define EBPF_CLS_ST 0x02
#define EBPF_CLS_STX 0x03
#define EBPF_CLS_ALU 0x04
#define EBPF_CLS_JMP 0x05
#define EBPF_CLS_JMP32 0x06
#define EBPF_CLS_ALU64 0x07

#define EBPF_SRC_IMM 0x00
Expand Down Expand Up @@ -120,30 +122,69 @@ struct ebpf_inst {
#define EBPF_OP_STXDW (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_DW)
#define EBPF_OP_LDDW (EBPF_CLS_LD|EBPF_MODE_IMM|EBPF_SIZE_DW)

#define EBPF_OP_JA (EBPF_CLS_JMP|0x00)
#define EBPF_OP_JEQ_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x10)
#define EBPF_OP_JEQ_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x10)
#define EBPF_OP_JGT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x20)
#define EBPF_OP_JGT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x20)
#define EBPF_OP_JGE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x30)
#define EBPF_OP_JGE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x30)
#define EBPF_OP_JSET_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x40)
#define EBPF_OP_JSET_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x40)
#define EBPF_OP_JNE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x50)
#define EBPF_OP_JNE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x50)
#define EBPF_OP_JSGT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x60)
#define EBPF_OP_JSGT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x60)
#define EBPF_OP_JSGE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0x70)
#define EBPF_OP_JSGE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0x70)
#define EBPF_OP_CALL (EBPF_CLS_JMP|0x80)
#define EBPF_OP_EXIT (EBPF_CLS_JMP|0x90)
#define EBPF_OP_JLT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0xa0)
#define EBPF_OP_JLT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0xa0)
#define EBPF_OP_JLE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0xb0)
#define EBPF_OP_JLE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0xb0)
#define EBPF_OP_JSLT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0xc0)
#define EBPF_OP_JSLT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0xc0)
#define EBPF_OP_JSLE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|0xd0)
#define EBPF_OP_JSLE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|0xd0)
#define EBPF_MODE_JA 0x00
#define EBPF_MODE_JEQ 0x10
#define EBPF_MODE_JGT 0x20
#define EBPF_MODE_JGE 0x30
#define EBPF_MODE_JSET 0x40
#define EBPF_MODE_JNE 0x50
#define EBPF_MODE_JSGT 0x60
#define EBPF_MODE_JSGE 0x70
#define EBPF_MODE_CALL 0x80
#define EBPF_MODE_EXIT 0x90
#define EBPF_MODE_JLT 0xa0
#define EBPF_MODE_JLE 0xb0
#define EBPF_MODE_JSLT 0xc0
#define EBPF_MODE_JSLE 0xd0

#define EBPF_OP_JA (EBPF_CLS_JMP|EBPF_MODE_JA)
#define EBPF_OP_JEQ_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JEQ)
#define EBPF_OP_JEQ_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JEQ)
#define EBPF_OP_JGT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JGT)
#define EBPF_OP_JGT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JGT)
#define EBPF_OP_JGE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JGE)
#define EBPF_OP_JGE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JGE)
#define EBPF_OP_JSET_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JSET)
#define EBPF_OP_JSET_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JSET)
#define EBPF_OP_JNE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JNE)
#define EBPF_OP_JNE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JNE)
#define EBPF_OP_JSGT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JSGT)
#define EBPF_OP_JSGT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JSGT)
#define EBPF_OP_JSGE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JSGE)
#define EBPF_OP_JSGE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JSGE)
#define EBPF_OP_CALL (EBPF_CLS_JMP|EBPF_MODE_CALL)
#define EBPF_OP_EXIT (EBPF_CLS_JMP|EBPF_MODE_EXIT)
#define EBPF_OP_JLT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JLT)
#define EBPF_OP_JLT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JLT)
#define EBPF_OP_JLE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JLE)
#define EBPF_OP_JLE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JLE)
#define EBPF_OP_JSLT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JSLT)
#define EBPF_OP_JSLT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JSLT)
#define EBPF_OP_JSLE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_MODE_JSLE)
#define EBPF_OP_JSLE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_MODE_JSLE)

#define EBPF_OP_JEQ32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JEQ)
#define EBPF_OP_JEQ32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JEQ)
#define EBPF_OP_JGT32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JGT)
#define EBPF_OP_JGT32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JGT)
#define EBPF_OP_JGE32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JGE)
#define EBPF_OP_JGE32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JGE)
#define EBPF_OP_JSET32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JSET)
#define EBPF_OP_JSET32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JSET)
#define EBPF_OP_JNE32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JNE)
#define EBPF_OP_JNE32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JNE)
#define EBPF_OP_JSGT32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JSGT)
#define EBPF_OP_JSGT32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JSGT)
#define EBPF_OP_JSGE32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JSGE)
#define EBPF_OP_JSGE32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JSGE)
#define EBPF_OP_JLT32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JLT)
#define EBPF_OP_JLT32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JLT)
#define EBPF_OP_JLE32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JLE)
#define EBPF_OP_JLE32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JLE)
#define EBPF_OP_JSLT32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JSLT)
#define EBPF_OP_JSLT32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JSLT)
#define EBPF_OP_JSLE32_IMM (EBPF_CLS_JMP32|EBPF_SRC_IMM|EBPF_MODE_JSLE)
#define EBPF_OP_JSLE32_REG (EBPF_CLS_JMP32|EBPF_SRC_REG|EBPF_MODE_JSLE)


#endif
76 changes: 50 additions & 26 deletions vm/ubpf_jit_arm64.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,9 +480,10 @@ is_imm_op(struct ebpf_inst const * inst)
bool is_exit = inst->opcode == EBPF_OP_EXIT;
bool is_ja = inst->opcode == EBPF_OP_JA;
bool is_alu = (class == EBPF_CLS_ALU || class == EBPF_CLS_ALU64) && !is_endian && !is_neg;
bool is_jmp = class == EBPF_CLS_JMP && !is_ja && !is_call && !is_exit;
bool is_jmp = (class == EBPF_CLS_JMP && !is_ja && !is_call && !is_exit);
bool is_jmp32 = class == EBPF_CLS_JMP32;
bool is_store = class == EBPF_CLS_ST;
return (is_imm && (is_alu || is_jmp)) || is_store;
return (is_imm && (is_alu || is_jmp || is_jmp32)) || is_store;
}

static bool
Expand Down Expand Up @@ -510,6 +511,16 @@ is_simple_imm(struct ebpf_inst const *inst)
case EBPF_OP_JLE_IMM:
case EBPF_OP_JSLT_IMM:
case EBPF_OP_JSLE_IMM:
case EBPF_OP_JEQ32_IMM:
case EBPF_OP_JGT32_IMM:
case EBPF_OP_JGE32_IMM:
case EBPF_OP_JNE32_IMM:
case EBPF_OP_JSGT32_IMM:
case EBPF_OP_JSGE32_IMM:
case EBPF_OP_JLT32_IMM:
case EBPF_OP_JLE32_IMM:
case EBPF_OP_JSLT32_IMM:
case EBPF_OP_JSLE32_IMM:
return inst->imm >= 0 && inst->imm < 0x1000;
case EBPF_OP_MOV_IMM:
case EBPF_OP_MOV64_IMM:
Expand All @@ -529,6 +540,7 @@ is_simple_imm(struct ebpf_inst const *inst)
case EBPF_OP_RSH64_IMM:
return false;
case EBPF_OP_JSET_IMM:
case EBPF_OP_JSET32_IMM:
return false;
case EBPF_OP_DIV_IMM:
case EBPF_OP_DIV64_IMM:
Expand All @@ -552,7 +564,7 @@ static uint8_t
to_reg_op(uint8_t opcode)
{
int class = opcode & EBPF_CLS_MASK;
if (class == EBPF_CLS_ALU64 || class == EBPF_CLS_ALU || class == EBPF_CLS_JMP) {
if (class == EBPF_CLS_ALU64 || class == EBPF_CLS_ALU || class == EBPF_CLS_JMP || class == EBPF_CLS_JMP32) {
return opcode | EBPF_SRC_REG;
}
else if (class == EBPF_CLS_ST) {
Expand Down Expand Up @@ -699,40 +711,30 @@ to_loadstore_opcode(int opcode)
static enum Condition
to_condition(int opcode)
{
switch (opcode)
uint8_t jmp_type = opcode & EBPF_JMP_OP_MASK;
switch (jmp_type)
{
case EBPF_OP_JEQ_IMM:
case EBPF_OP_JEQ_REG:
case EBPF_MODE_JEQ:
return COND_EQ;
case EBPF_OP_JGT_IMM:
case EBPF_OP_JGT_REG:
case EBPF_MODE_JGT:
return COND_HI;
case EBPF_OP_JGE_IMM:
case EBPF_OP_JGE_REG:
case EBPF_MODE_JGE:
return COND_HS;
case EBPF_OP_JLT_IMM:
case EBPF_OP_JLT_REG:
case EBPF_MODE_JLT:
return COND_LO;
case EBPF_OP_JLE_IMM:
case EBPF_OP_JLE_REG:
case EBPF_MODE_JLE:
return COND_LS;
case EBPF_OP_JSET_IMM:
case EBPF_OP_JSET_REG:
case EBPF_MODE_JSET:
return COND_NE;
case EBPF_OP_JNE_IMM:
case EBPF_OP_JNE_REG:
case EBPF_MODE_JNE:
return COND_NE;
case EBPF_OP_JSGT_IMM:
case EBPF_OP_JSGT_REG:
case EBPF_MODE_JSGT:
return COND_GT;
case EBPF_OP_JSGE_IMM:
case EBPF_OP_JSGE_REG:
case EBPF_MODE_JSGE:
return COND_GE;
case EBPF_OP_JSLT_IMM:
case EBPF_OP_JSLT_REG:
case EBPF_MODE_JSLT:
return COND_LT;
case EBPF_OP_JSLE_IMM:
case EBPF_OP_JSLE_REG:
case EBPF_MODE_JSLE:
return COND_LE;
default:
assert(false);
Expand Down Expand Up @@ -854,6 +856,16 @@ translate(struct ubpf_vm *vm, struct jit_state *state, char **errmsg)
case EBPF_OP_JSGE_IMM:
case EBPF_OP_JSLT_IMM:
case EBPF_OP_JSLE_IMM:
case EBPF_OP_JEQ32_IMM:
case EBPF_OP_JGT32_IMM:
case EBPF_OP_JGE32_IMM:
case EBPF_OP_JLT32_IMM:
case EBPF_OP_JLE32_IMM:
case EBPF_OP_JNE32_IMM:
case EBPF_OP_JSGT32_IMM:
case EBPF_OP_JSGE32_IMM:
case EBPF_OP_JSLT32_IMM:
case EBPF_OP_JSLE32_IMM:
emit_addsub_immediate(state, sixty_four, AS_SUBS, RZ, dst, inst.imm);
emit_conditionalbranch_immediate(state, to_condition(opcode), target_pc);
break;
Expand All @@ -867,10 +879,21 @@ translate(struct ubpf_vm *vm, struct jit_state *state, char **errmsg)
case EBPF_OP_JSGE_REG:
case EBPF_OP_JSLT_REG:
case EBPF_OP_JSLE_REG:
case EBPF_OP_JEQ32_REG:
case EBPF_OP_JGT32_REG:
case EBPF_OP_JGE32_REG:
case EBPF_OP_JLT32_REG:
case EBPF_OP_JLE32_REG:
case EBPF_OP_JNE32_REG:
case EBPF_OP_JSGT32_REG:
case EBPF_OP_JSGE32_REG:
case EBPF_OP_JSLT32_REG:
case EBPF_OP_JSLE32_REG:
emit_addsub_register(state, sixty_four, AS_SUBS, RZ, dst, src);
emit_conditionalbranch_immediate(state, to_condition(opcode), target_pc);
break;
case EBPF_OP_JSET_REG:
case EBPF_OP_JSET32_REG:
emit_logical_register(state, sixty_four, LOG_ANDS, RZ, dst, src);
emit_conditionalbranch_immediate(state, to_condition(opcode), target_pc);
break;
Expand Down Expand Up @@ -928,6 +951,7 @@ translate(struct ubpf_vm *vm, struct jit_state *state, char **errmsg)
case EBPF_OP_STB:
case EBPF_OP_STDW:
case EBPF_OP_JSET_IMM:
case EBPF_OP_JSET32_IMM:
case EBPF_OP_OR_IMM:
case EBPF_OP_AND_IMM:
case EBPF_OP_XOR_IMM:
Expand Down
88 changes: 88 additions & 0 deletions vm/ubpf_jit_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,94 @@ translate(struct ubpf_vm *vm, struct jit_state *state, char **errmsg)
emit_cmp(state, src, dst);
emit_jcc(state, 0x8e, target_pc);
break;
case EBPF_OP_JEQ32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x84, target_pc);
break;
case EBPF_OP_JEQ32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x84, target_pc);
break;
case EBPF_OP_JGT32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x87, target_pc);
break;
case EBPF_OP_JGT32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x87, target_pc);
break;
case EBPF_OP_JGE32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x83, target_pc);
break;
case EBPF_OP_JGE32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x83, target_pc);
break;
case EBPF_OP_JLT32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x82, target_pc);
break;
case EBPF_OP_JLT32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x82, target_pc);
break;
case EBPF_OP_JLE32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x86, target_pc);
break;
case EBPF_OP_JLE32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x86, target_pc);
break;
case EBPF_OP_JSET32_IMM:
emit_alu32_imm32(state, 0xf7, 0, dst, inst.imm);
emit_jcc(state, 0x85, target_pc);
break;
case EBPF_OP_JSET32_REG:
emit_alu32(state, 0x85, src, dst);
emit_jcc(state, 0x85, target_pc);
break;
case EBPF_OP_JNE32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x85, target_pc);
break;
case EBPF_OP_JNE32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x85, target_pc);
break;
case EBPF_OP_JSGT32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x8f, target_pc);
break;
case EBPF_OP_JSGT32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x8f, target_pc);
break;
case EBPF_OP_JSGE32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x8d, target_pc);
break;
case EBPF_OP_JSGE32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x8d, target_pc);
break;
case EBPF_OP_JSLT32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x8c, target_pc);
break;
case EBPF_OP_JSLT32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x8c, target_pc);
break;
case EBPF_OP_JSLE32_IMM:
emit_cmp32_imm32(state, dst, inst.imm);
emit_jcc(state, 0x8e, target_pc);
break;
case EBPF_OP_JSLE32_REG:
emit_cmp32(state, src, dst);
emit_jcc(state, 0x8e, target_pc);
break;
case EBPF_OP_CALL:
/* We reserve RCX for shifts */
emit_mov(state, RCX_ALT, RCX);
Expand Down
12 changes: 12 additions & 0 deletions vm/ubpf_jit_x86_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,24 @@ emit_cmp_imm32(struct jit_state *state, int dst, int32_t imm)
emit_alu64_imm32(state, 0x81, 7, dst, imm);
}

static inline void
emit_cmp32_imm32(struct jit_state *state, int dst, int32_t imm)
{
emit_alu32_imm32(state, 0x81, 7, dst, imm);
}

static inline void
emit_cmp(struct jit_state *state, int src, int dst)
{
emit_alu64(state, 0x39, src, dst);
}

static inline void
emit_cmp32(struct jit_state *state, int src, int dst)
{
emit_alu32(state, 0x39, src, dst);
}

static inline void
emit_jcc(struct jit_state *state, int code, int32_t target_pc)
{
Expand Down
Loading

0 comments on commit ff9ba9b

Please sign in to comment.