Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

s390/bpf: Implement new atomic ops

Implement BPF_AND, BPF_OR and BPF_XOR as the existing BPF_ADD. Since
the corresponding machine instructions return the old value, BPF_FETCH
happens by itself, the only additional thing that is required is
zero-extension.

There is no single instruction that implements BPF_XCHG on s390, so use
a COMPARE AND SWAP loop.

BPF_CMPXCHG, on the other hand, can be implemented by a single COMPARE
AND SWAP. Zero-extension is automatically inserted by the verifier.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20210304233002.149096-1-iii@linux.ibm.com

authored by

Ilya Leoshkevich and committed by
Alexei Starovoitov
ba3b86b9 23f50b5a

+55 -9
+55 -9
arch/s390/net/bpf_jit_comp.c
··· 1209 1209 */ 1210 1210 case BPF_STX | BPF_ATOMIC | BPF_DW: 1211 1211 case BPF_STX | BPF_ATOMIC | BPF_W: 1212 - if (insn->imm != BPF_ADD) { 1212 + { 1213 + bool is32 = BPF_SIZE(insn->code) == BPF_W; 1214 + 1215 + switch (insn->imm) { 1216 + /* {op32|op64} {%w0|%src},%src,off(%dst) */ 1217 + #define EMIT_ATOMIC(op32, op64) do { \ 1218 + EMIT6_DISP_LH(0xeb000000, is32 ? (op32) : (op64), \ 1219 + (insn->imm & BPF_FETCH) ? src_reg : REG_W0, \ 1220 + src_reg, dst_reg, off); \ 1221 + if (is32 && (insn->imm & BPF_FETCH)) \ 1222 + EMIT_ZERO(src_reg); \ 1223 + } while (0) 1224 + case BPF_ADD: 1225 + case BPF_ADD | BPF_FETCH: 1226 + /* {laal|laalg} */ 1227 + EMIT_ATOMIC(0x00fa, 0x00ea); 1228 + break; 1229 + case BPF_AND: 1230 + case BPF_AND | BPF_FETCH: 1231 + /* {lan|lang} */ 1232 + EMIT_ATOMIC(0x00f4, 0x00e4); 1233 + break; 1234 + case BPF_OR: 1235 + case BPF_OR | BPF_FETCH: 1236 + /* {lao|laog} */ 1237 + EMIT_ATOMIC(0x00f6, 0x00e6); 1238 + break; 1239 + case BPF_XOR: 1240 + case BPF_XOR | BPF_FETCH: 1241 + /* {lax|laxg} */ 1242 + EMIT_ATOMIC(0x00f7, 0x00e7); 1243 + break; 1244 + #undef EMIT_ATOMIC 1245 + case BPF_XCHG: 1246 + /* {ly|lg} %w0,off(%dst) */ 1247 + EMIT6_DISP_LH(0xe3000000, 1248 + is32 ? 0x0058 : 0x0004, REG_W0, REG_0, 1249 + dst_reg, off); 1250 + /* 0: {csy|csg} %w0,%src,off(%dst) */ 1251 + EMIT6_DISP_LH(0xeb000000, is32 ? 0x0014 : 0x0030, 1252 + REG_W0, src_reg, dst_reg, off); 1253 + /* brc 4,0b */ 1254 + EMIT4_PCREL_RIC(0xa7040000, 4, jit->prg - 6); 1255 + /* {llgfr|lgr} %src,%w0 */ 1256 + EMIT4(is32 ? 0xb9160000 : 0xb9040000, src_reg, REG_W0); 1257 + if (is32 && insn_is_zext(&insn[1])) 1258 + insn_count = 2; 1259 + break; 1260 + case BPF_CMPXCHG: 1261 + /* 0: {csy|csg} %b0,%src,off(%dst) */ 1262 + EMIT6_DISP_LH(0xeb000000, is32 ? 0x0014 : 0x0030, 1263 + BPF_REG_0, src_reg, dst_reg, off); 1264 + break; 1265 + default: 1213 1266 pr_err("Unknown atomic operation %02x\n", insn->imm); 1214 1267 return -1; 1215 1268 } 1216 1269 1217 - /* *(u32/u64 *)(dst + off) += src 1218 - * 1219 - * BFW_W: laal %w0,%src,off(%dst) 1220 - * BPF_DW: laalg %w0,%src,off(%dst) 1221 - */ 1222 - EMIT6_DISP_LH(0xeb000000, 1223 - BPF_SIZE(insn->code) == BPF_W ? 0x00fa : 0x00ea, 1224 - REG_W0, src_reg, dst_reg, off); 1225 1270 jit->seen |= SEEN_MEM; 1226 1271 break; 1272 + } 1227 1273 /* 1228 1274 * BPF_LDX 1229 1275 */