Skip to content

Commit ce4ebfd

Browse files
Jakub Kicinskiborkmann
authored andcommitted
nfp: bpf: add helpers for updating immediate instructions
Immediate loads are used to load the return address of a helper. We need to be able to update those loads for relocations. Immediate loads can be slightly more complex and spread over two instructions in general, but here we only care about simple loads of small (< 65k) constants, so complex cases are not handled. Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 9d080d5 commit ce4ebfd

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

drivers/net/ethernet/netronome/nfp/nfp_asm.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ const struct cmd_tgt_act cmd_tgt_act[__CMD_TGT_MAP_SIZE] = {
5050
[CMD_TGT_READ_SWAP_LE] = { 0x03, 0x40 },
5151
};
5252

53+
static bool unreg_is_imm(u16 reg)
54+
{
55+
return (reg & UR_REG_IMM) == UR_REG_IMM;
56+
}
57+
5358
u16 br_get_offset(u64 instr)
5459
{
5560
u16 addr_lo, addr_hi;
@@ -80,6 +85,59 @@ void br_add_offset(u64 *instr, u16 offset)
8085
br_set_offset(instr, addr + offset);
8186
}
8287

88+
static bool immed_can_modify(u64 instr)
89+
{
90+
if (FIELD_GET(OP_IMMED_INV, instr) ||
91+
FIELD_GET(OP_IMMED_SHIFT, instr) ||
92+
FIELD_GET(OP_IMMED_WIDTH, instr) != IMMED_WIDTH_ALL) {
93+
pr_err("Can't decode/encode immed!\n");
94+
return false;
95+
}
96+
return true;
97+
}
98+
99+
u16 immed_get_value(u64 instr)
100+
{
101+
u16 reg;
102+
103+
if (!immed_can_modify(instr))
104+
return 0;
105+
106+
reg = FIELD_GET(OP_IMMED_A_SRC, instr);
107+
if (!unreg_is_imm(reg))
108+
reg = FIELD_GET(OP_IMMED_B_SRC, instr);
109+
110+
return (reg & 0xff) | FIELD_GET(OP_IMMED_IMM, instr);
111+
}
112+
113+
void immed_set_value(u64 *instr, u16 immed)
114+
{
115+
if (!immed_can_modify(*instr))
116+
return;
117+
118+
if (unreg_is_imm(FIELD_GET(OP_IMMED_A_SRC, *instr))) {
119+
*instr &= ~FIELD_PREP(OP_IMMED_A_SRC, 0xff);
120+
*instr |= FIELD_PREP(OP_IMMED_A_SRC, immed & 0xff);
121+
} else {
122+
*instr &= ~FIELD_PREP(OP_IMMED_B_SRC, 0xff);
123+
*instr |= FIELD_PREP(OP_IMMED_B_SRC, immed & 0xff);
124+
}
125+
126+
*instr &= ~OP_IMMED_IMM;
127+
*instr |= FIELD_PREP(OP_IMMED_IMM, immed >> 8);
128+
}
129+
130+
void immed_add_value(u64 *instr, u16 offset)
131+
{
132+
u16 val;
133+
134+
if (!immed_can_modify(*instr))
135+
return;
136+
137+
val = immed_get_value(*instr);
138+
immed_set_value(instr, val + offset);
139+
}
140+
83141
static u16 nfp_swreg_to_unreg(swreg reg, bool is_dst)
84142
{
85143
bool lm_id, lm_dec = false;

drivers/net/ethernet/netronome/nfp/nfp_asm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ enum immed_shift {
138138
IMMED_SHIFT_2B = 2,
139139
};
140140

141+
u16 immed_get_value(u64 instr);
142+
void immed_set_value(u64 *instr, u16 immed);
143+
void immed_add_value(u64 *instr, u16 offset);
144+
141145
#define OP_SHF_BASE 0x08000000000ULL
142146
#define OP_SHF_A_SRC 0x000000000ffULL
143147
#define OP_SHF_SC 0x00000000300ULL

0 commit comments

Comments
 (0)