18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * BPF Jit compiler for s390. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Minimum build requirements: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * - HAVE_MARCH_Z196_FEATURES: laal, laalg 88c2ecf20Sopenharmony_ci * - HAVE_MARCH_Z10_FEATURES: msfi, cgrj, clgrj 98c2ecf20Sopenharmony_ci * - HAVE_MARCH_Z9_109_FEATURES: alfi, llilf, clfi, oilf, nilf 108c2ecf20Sopenharmony_ci * - PACK_STACK 118c2ecf20Sopenharmony_ci * - 64BIT 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2012,2015 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 168c2ecf20Sopenharmony_ci * Michael Holzheu <holzheu@linux.vnet.ibm.com> 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define KMSG_COMPONENT "bpf_jit" 208c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/filter.h> 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/bpf.h> 268c2ecf20Sopenharmony_ci#include <linux/mm.h> 278c2ecf20Sopenharmony_ci#include <linux/kernel.h> 288c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 298c2ecf20Sopenharmony_ci#include <asm/dis.h> 308c2ecf20Sopenharmony_ci#include <asm/facility.h> 318c2ecf20Sopenharmony_ci#include <asm/nospec-branch.h> 328c2ecf20Sopenharmony_ci#include <asm/set_memory.h> 338c2ecf20Sopenharmony_ci#include "bpf_jit.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct bpf_jit { 368c2ecf20Sopenharmony_ci u32 seen; /* Flags to remember seen eBPF instructions */ 378c2ecf20Sopenharmony_ci u32 seen_reg[16]; /* Array to remember which registers are used */ 388c2ecf20Sopenharmony_ci u32 *addrs; /* Array with relative instruction addresses */ 398c2ecf20Sopenharmony_ci u8 *prg_buf; /* Start of program */ 408c2ecf20Sopenharmony_ci int size; /* Size of program and literal pool */ 418c2ecf20Sopenharmony_ci int size_prg; /* Size of program */ 428c2ecf20Sopenharmony_ci int prg; /* Current position in program */ 438c2ecf20Sopenharmony_ci int lit32_start; /* Start of 32-bit literal pool */ 448c2ecf20Sopenharmony_ci int lit32; /* Current position in 32-bit literal pool */ 458c2ecf20Sopenharmony_ci int lit64_start; /* Start of 64-bit literal pool */ 468c2ecf20Sopenharmony_ci int lit64; /* Current position in 64-bit literal pool */ 478c2ecf20Sopenharmony_ci int base_ip; /* Base address for literal pool */ 488c2ecf20Sopenharmony_ci int exit_ip; /* Address of exit */ 498c2ecf20Sopenharmony_ci int r1_thunk_ip; /* Address of expoline thunk for 'br %r1' */ 508c2ecf20Sopenharmony_ci int r14_thunk_ip; /* Address of expoline thunk for 'br %r14' */ 518c2ecf20Sopenharmony_ci int tail_call_start; /* Tail call start offset */ 528c2ecf20Sopenharmony_ci int excnt; /* Number of exception table entries */ 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define SEEN_MEM BIT(0) /* use mem[] for temporary storage */ 568c2ecf20Sopenharmony_ci#define SEEN_LITERAL BIT(1) /* code uses literals */ 578c2ecf20Sopenharmony_ci#define SEEN_FUNC BIT(2) /* calls C functions */ 588c2ecf20Sopenharmony_ci#define SEEN_TAIL_CALL BIT(3) /* code uses tail calls */ 598c2ecf20Sopenharmony_ci#define SEEN_STACK (SEEN_FUNC | SEEN_MEM) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * s390 registers 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci#define REG_W0 (MAX_BPF_JIT_REG + 0) /* Work register 1 (even) */ 658c2ecf20Sopenharmony_ci#define REG_W1 (MAX_BPF_JIT_REG + 1) /* Work register 2 (odd) */ 668c2ecf20Sopenharmony_ci#define REG_L (MAX_BPF_JIT_REG + 2) /* Literal pool register */ 678c2ecf20Sopenharmony_ci#define REG_15 (MAX_BPF_JIT_REG + 3) /* Register 15 */ 688c2ecf20Sopenharmony_ci#define REG_0 REG_W0 /* Register 0 */ 698c2ecf20Sopenharmony_ci#define REG_1 REG_W1 /* Register 1 */ 708c2ecf20Sopenharmony_ci#define REG_2 BPF_REG_1 /* Register 2 */ 718c2ecf20Sopenharmony_ci#define REG_14 BPF_REG_0 /* Register 14 */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * Mapping of BPF registers to s390 registers 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic const int reg2hex[] = { 778c2ecf20Sopenharmony_ci /* Return code */ 788c2ecf20Sopenharmony_ci [BPF_REG_0] = 14, 798c2ecf20Sopenharmony_ci /* Function parameters */ 808c2ecf20Sopenharmony_ci [BPF_REG_1] = 2, 818c2ecf20Sopenharmony_ci [BPF_REG_2] = 3, 828c2ecf20Sopenharmony_ci [BPF_REG_3] = 4, 838c2ecf20Sopenharmony_ci [BPF_REG_4] = 5, 848c2ecf20Sopenharmony_ci [BPF_REG_5] = 6, 858c2ecf20Sopenharmony_ci /* Call saved registers */ 868c2ecf20Sopenharmony_ci [BPF_REG_6] = 7, 878c2ecf20Sopenharmony_ci [BPF_REG_7] = 8, 888c2ecf20Sopenharmony_ci [BPF_REG_8] = 9, 898c2ecf20Sopenharmony_ci [BPF_REG_9] = 10, 908c2ecf20Sopenharmony_ci /* BPF stack pointer */ 918c2ecf20Sopenharmony_ci [BPF_REG_FP] = 13, 928c2ecf20Sopenharmony_ci /* Register for blinding */ 938c2ecf20Sopenharmony_ci [BPF_REG_AX] = 12, 948c2ecf20Sopenharmony_ci /* Work registers for s390x backend */ 958c2ecf20Sopenharmony_ci [REG_W0] = 0, 968c2ecf20Sopenharmony_ci [REG_W1] = 1, 978c2ecf20Sopenharmony_ci [REG_L] = 11, 988c2ecf20Sopenharmony_ci [REG_15] = 15, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic inline u32 reg(u32 dst_reg, u32 src_reg) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci return reg2hex[dst_reg] << 4 | reg2hex[src_reg]; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic inline u32 reg_high(u32 reg) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return reg2hex[reg] << 4; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic inline void reg_set_seen(struct bpf_jit *jit, u32 b1) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci u32 r1 = reg2hex[b1]; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (r1 >= 6 && r1 <= 15 && !jit->seen_reg[r1]) 1168c2ecf20Sopenharmony_ci jit->seen_reg[r1] = 1; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#define REG_SET_SEEN(b1) \ 1208c2ecf20Sopenharmony_ci({ \ 1218c2ecf20Sopenharmony_ci reg_set_seen(jit, b1); \ 1228c2ecf20Sopenharmony_ci}) 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define REG_SEEN(b1) jit->seen_reg[reg2hex[(b1)]] 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* 1278c2ecf20Sopenharmony_ci * EMIT macros for code generation 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define _EMIT2(op) \ 1318c2ecf20Sopenharmony_ci({ \ 1328c2ecf20Sopenharmony_ci if (jit->prg_buf) \ 1338c2ecf20Sopenharmony_ci *(u16 *) (jit->prg_buf + jit->prg) = (op); \ 1348c2ecf20Sopenharmony_ci jit->prg += 2; \ 1358c2ecf20Sopenharmony_ci}) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#define EMIT2(op, b1, b2) \ 1388c2ecf20Sopenharmony_ci({ \ 1398c2ecf20Sopenharmony_ci _EMIT2((op) | reg(b1, b2)); \ 1408c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 1418c2ecf20Sopenharmony_ci REG_SET_SEEN(b2); \ 1428c2ecf20Sopenharmony_ci}) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define _EMIT4(op) \ 1458c2ecf20Sopenharmony_ci({ \ 1468c2ecf20Sopenharmony_ci if (jit->prg_buf) \ 1478c2ecf20Sopenharmony_ci *(u32 *) (jit->prg_buf + jit->prg) = (op); \ 1488c2ecf20Sopenharmony_ci jit->prg += 4; \ 1498c2ecf20Sopenharmony_ci}) 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define EMIT4(op, b1, b2) \ 1528c2ecf20Sopenharmony_ci({ \ 1538c2ecf20Sopenharmony_ci _EMIT4((op) | reg(b1, b2)); \ 1548c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 1558c2ecf20Sopenharmony_ci REG_SET_SEEN(b2); \ 1568c2ecf20Sopenharmony_ci}) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#define EMIT4_RRF(op, b1, b2, b3) \ 1598c2ecf20Sopenharmony_ci({ \ 1608c2ecf20Sopenharmony_ci _EMIT4((op) | reg_high(b3) << 8 | reg(b1, b2)); \ 1618c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 1628c2ecf20Sopenharmony_ci REG_SET_SEEN(b2); \ 1638c2ecf20Sopenharmony_ci REG_SET_SEEN(b3); \ 1648c2ecf20Sopenharmony_ci}) 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define _EMIT4_DISP(op, disp) \ 1678c2ecf20Sopenharmony_ci({ \ 1688c2ecf20Sopenharmony_ci unsigned int __disp = (disp) & 0xfff; \ 1698c2ecf20Sopenharmony_ci _EMIT4((op) | __disp); \ 1708c2ecf20Sopenharmony_ci}) 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#define EMIT4_DISP(op, b1, b2, disp) \ 1738c2ecf20Sopenharmony_ci({ \ 1748c2ecf20Sopenharmony_ci _EMIT4_DISP((op) | reg_high(b1) << 16 | \ 1758c2ecf20Sopenharmony_ci reg_high(b2) << 8, (disp)); \ 1768c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 1778c2ecf20Sopenharmony_ci REG_SET_SEEN(b2); \ 1788c2ecf20Sopenharmony_ci}) 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#define EMIT4_IMM(op, b1, imm) \ 1818c2ecf20Sopenharmony_ci({ \ 1828c2ecf20Sopenharmony_ci unsigned int __imm = (imm) & 0xffff; \ 1838c2ecf20Sopenharmony_ci _EMIT4((op) | reg_high(b1) << 16 | __imm); \ 1848c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 1858c2ecf20Sopenharmony_ci}) 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci#define EMIT4_PCREL(op, pcrel) \ 1888c2ecf20Sopenharmony_ci({ \ 1898c2ecf20Sopenharmony_ci long __pcrel = ((pcrel) >> 1) & 0xffff; \ 1908c2ecf20Sopenharmony_ci _EMIT4((op) | __pcrel); \ 1918c2ecf20Sopenharmony_ci}) 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci#define EMIT4_PCREL_RIC(op, mask, target) \ 1948c2ecf20Sopenharmony_ci({ \ 1958c2ecf20Sopenharmony_ci int __rel = ((target) - jit->prg) / 2; \ 1968c2ecf20Sopenharmony_ci _EMIT4((op) | (mask) << 20 | (__rel & 0xffff)); \ 1978c2ecf20Sopenharmony_ci}) 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#define _EMIT6(op1, op2) \ 2008c2ecf20Sopenharmony_ci({ \ 2018c2ecf20Sopenharmony_ci if (jit->prg_buf) { \ 2028c2ecf20Sopenharmony_ci *(u32 *) (jit->prg_buf + jit->prg) = (op1); \ 2038c2ecf20Sopenharmony_ci *(u16 *) (jit->prg_buf + jit->prg + 4) = (op2); \ 2048c2ecf20Sopenharmony_ci } \ 2058c2ecf20Sopenharmony_ci jit->prg += 6; \ 2068c2ecf20Sopenharmony_ci}) 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci#define _EMIT6_DISP(op1, op2, disp) \ 2098c2ecf20Sopenharmony_ci({ \ 2108c2ecf20Sopenharmony_ci unsigned int __disp = (disp) & 0xfff; \ 2118c2ecf20Sopenharmony_ci _EMIT6((op1) | __disp, op2); \ 2128c2ecf20Sopenharmony_ci}) 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci#define _EMIT6_DISP_LH(op1, op2, disp) \ 2158c2ecf20Sopenharmony_ci({ \ 2168c2ecf20Sopenharmony_ci u32 _disp = (u32) (disp); \ 2178c2ecf20Sopenharmony_ci unsigned int __disp_h = _disp & 0xff000; \ 2188c2ecf20Sopenharmony_ci unsigned int __disp_l = _disp & 0x00fff; \ 2198c2ecf20Sopenharmony_ci _EMIT6((op1) | __disp_l, (op2) | __disp_h >> 4); \ 2208c2ecf20Sopenharmony_ci}) 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#define EMIT6_DISP_LH(op1, op2, b1, b2, b3, disp) \ 2238c2ecf20Sopenharmony_ci({ \ 2248c2ecf20Sopenharmony_ci _EMIT6_DISP_LH((op1) | reg(b1, b2) << 16 | \ 2258c2ecf20Sopenharmony_ci reg_high(b3) << 8, op2, disp); \ 2268c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 2278c2ecf20Sopenharmony_ci REG_SET_SEEN(b2); \ 2288c2ecf20Sopenharmony_ci REG_SET_SEEN(b3); \ 2298c2ecf20Sopenharmony_ci}) 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci#define EMIT6_PCREL_RIEB(op1, op2, b1, b2, mask, target) \ 2328c2ecf20Sopenharmony_ci({ \ 2338c2ecf20Sopenharmony_ci unsigned int rel = (int)((target) - jit->prg) / 2; \ 2348c2ecf20Sopenharmony_ci _EMIT6((op1) | reg(b1, b2) << 16 | (rel & 0xffff), \ 2358c2ecf20Sopenharmony_ci (op2) | (mask) << 12); \ 2368c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 2378c2ecf20Sopenharmony_ci REG_SET_SEEN(b2); \ 2388c2ecf20Sopenharmony_ci}) 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define EMIT6_PCREL_RIEC(op1, op2, b1, imm, mask, target) \ 2418c2ecf20Sopenharmony_ci({ \ 2428c2ecf20Sopenharmony_ci unsigned int rel = (int)((target) - jit->prg) / 2; \ 2438c2ecf20Sopenharmony_ci _EMIT6((op1) | (reg_high(b1) | (mask)) << 16 | \ 2448c2ecf20Sopenharmony_ci (rel & 0xffff), (op2) | ((imm) & 0xff) << 8); \ 2458c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 2468c2ecf20Sopenharmony_ci BUILD_BUG_ON(((unsigned long) (imm)) > 0xff); \ 2478c2ecf20Sopenharmony_ci}) 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci#define EMIT6_PCREL(op1, op2, b1, b2, i, off, mask) \ 2508c2ecf20Sopenharmony_ci({ \ 2518c2ecf20Sopenharmony_ci int rel = (addrs[(i) + (off) + 1] - jit->prg) / 2; \ 2528c2ecf20Sopenharmony_ci _EMIT6((op1) | reg(b1, b2) << 16 | (rel & 0xffff), (op2) | (mask));\ 2538c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 2548c2ecf20Sopenharmony_ci REG_SET_SEEN(b2); \ 2558c2ecf20Sopenharmony_ci}) 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define EMIT6_PCREL_RILB(op, b, target) \ 2588c2ecf20Sopenharmony_ci({ \ 2598c2ecf20Sopenharmony_ci unsigned int rel = (int)((target) - jit->prg) / 2; \ 2608c2ecf20Sopenharmony_ci _EMIT6((op) | reg_high(b) << 16 | rel >> 16, rel & 0xffff);\ 2618c2ecf20Sopenharmony_ci REG_SET_SEEN(b); \ 2628c2ecf20Sopenharmony_ci}) 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci#define EMIT6_PCREL_RIL(op, target) \ 2658c2ecf20Sopenharmony_ci({ \ 2668c2ecf20Sopenharmony_ci unsigned int rel = (int)((target) - jit->prg) / 2; \ 2678c2ecf20Sopenharmony_ci _EMIT6((op) | rel >> 16, rel & 0xffff); \ 2688c2ecf20Sopenharmony_ci}) 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci#define EMIT6_PCREL_RILC(op, mask, target) \ 2718c2ecf20Sopenharmony_ci({ \ 2728c2ecf20Sopenharmony_ci EMIT6_PCREL_RIL((op) | (mask) << 20, (target)); \ 2738c2ecf20Sopenharmony_ci}) 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci#define _EMIT6_IMM(op, imm) \ 2768c2ecf20Sopenharmony_ci({ \ 2778c2ecf20Sopenharmony_ci unsigned int __imm = (imm); \ 2788c2ecf20Sopenharmony_ci _EMIT6((op) | (__imm >> 16), __imm & 0xffff); \ 2798c2ecf20Sopenharmony_ci}) 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci#define EMIT6_IMM(op, b1, imm) \ 2828c2ecf20Sopenharmony_ci({ \ 2838c2ecf20Sopenharmony_ci _EMIT6_IMM((op) | reg_high(b1) << 16, imm); \ 2848c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 2858c2ecf20Sopenharmony_ci}) 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci#define _EMIT_CONST_U32(val) \ 2888c2ecf20Sopenharmony_ci({ \ 2898c2ecf20Sopenharmony_ci unsigned int ret; \ 2908c2ecf20Sopenharmony_ci ret = jit->lit32; \ 2918c2ecf20Sopenharmony_ci if (jit->prg_buf) \ 2928c2ecf20Sopenharmony_ci *(u32 *)(jit->prg_buf + jit->lit32) = (u32)(val);\ 2938c2ecf20Sopenharmony_ci jit->lit32 += 4; \ 2948c2ecf20Sopenharmony_ci ret; \ 2958c2ecf20Sopenharmony_ci}) 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci#define EMIT_CONST_U32(val) \ 2988c2ecf20Sopenharmony_ci({ \ 2998c2ecf20Sopenharmony_ci jit->seen |= SEEN_LITERAL; \ 3008c2ecf20Sopenharmony_ci _EMIT_CONST_U32(val) - jit->base_ip; \ 3018c2ecf20Sopenharmony_ci}) 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci#define _EMIT_CONST_U64(val) \ 3048c2ecf20Sopenharmony_ci({ \ 3058c2ecf20Sopenharmony_ci unsigned int ret; \ 3068c2ecf20Sopenharmony_ci ret = jit->lit64; \ 3078c2ecf20Sopenharmony_ci if (jit->prg_buf) \ 3088c2ecf20Sopenharmony_ci *(u64 *)(jit->prg_buf + jit->lit64) = (u64)(val);\ 3098c2ecf20Sopenharmony_ci jit->lit64 += 8; \ 3108c2ecf20Sopenharmony_ci ret; \ 3118c2ecf20Sopenharmony_ci}) 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci#define EMIT_CONST_U64(val) \ 3148c2ecf20Sopenharmony_ci({ \ 3158c2ecf20Sopenharmony_ci jit->seen |= SEEN_LITERAL; \ 3168c2ecf20Sopenharmony_ci _EMIT_CONST_U64(val) - jit->base_ip; \ 3178c2ecf20Sopenharmony_ci}) 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci#define EMIT_ZERO(b1) \ 3208c2ecf20Sopenharmony_ci({ \ 3218c2ecf20Sopenharmony_ci if (!fp->aux->verifier_zext) { \ 3228c2ecf20Sopenharmony_ci /* llgfr %dst,%dst (zero extend to 64 bit) */ \ 3238c2ecf20Sopenharmony_ci EMIT4(0xb9160000, b1, b1); \ 3248c2ecf20Sopenharmony_ci REG_SET_SEEN(b1); \ 3258c2ecf20Sopenharmony_ci } \ 3268c2ecf20Sopenharmony_ci}) 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/* 3298c2ecf20Sopenharmony_ci * Return whether this is the first pass. The first pass is special, since we 3308c2ecf20Sopenharmony_ci * don't know any sizes yet, and thus must be conservative. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_cistatic bool is_first_pass(struct bpf_jit *jit) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci return jit->size == 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* 3388c2ecf20Sopenharmony_ci * Return whether this is the code generation pass. The code generation pass is 3398c2ecf20Sopenharmony_ci * special, since we should change as little as possible. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_cistatic bool is_codegen_pass(struct bpf_jit *jit) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci return jit->prg_buf; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/* 3478c2ecf20Sopenharmony_ci * Return whether "rel" can be encoded as a short PC-relative offset 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_cistatic bool is_valid_rel(int rel) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci return rel >= -65536 && rel <= 65534; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/* 3558c2ecf20Sopenharmony_ci * Return whether "off" can be reached using a short PC-relative offset 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_cistatic bool can_use_rel(struct bpf_jit *jit, int off) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci return is_valid_rel(off - jit->prg); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/* 3638c2ecf20Sopenharmony_ci * Return whether given displacement can be encoded using 3648c2ecf20Sopenharmony_ci * Long-Displacement Facility 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_cistatic bool is_valid_ldisp(int disp) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci return disp >= -524288 && disp <= 524287; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/* 3728c2ecf20Sopenharmony_ci * Return whether the next 32-bit literal pool entry can be referenced using 3738c2ecf20Sopenharmony_ci * Long-Displacement Facility 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_cistatic bool can_use_ldisp_for_lit32(struct bpf_jit *jit) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci return is_valid_ldisp(jit->lit32 - jit->base_ip); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/* 3818c2ecf20Sopenharmony_ci * Return whether the next 64-bit literal pool entry can be referenced using 3828c2ecf20Sopenharmony_ci * Long-Displacement Facility 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_cistatic bool can_use_ldisp_for_lit64(struct bpf_jit *jit) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci return is_valid_ldisp(jit->lit64 - jit->base_ip); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/* 3908c2ecf20Sopenharmony_ci * Fill whole space with illegal instructions 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_cistatic void jit_fill_hole(void *area, unsigned int size) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci memset(area, 0, size); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/* 3988c2ecf20Sopenharmony_ci * Save registers from "rs" (register start) to "re" (register end) on stack 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_cistatic void save_regs(struct bpf_jit *jit, u32 rs, u32 re) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci u32 off = STK_OFF_R6 + (rs - 6) * 8; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (rs == re) 4058c2ecf20Sopenharmony_ci /* stg %rs,off(%r15) */ 4068c2ecf20Sopenharmony_ci _EMIT6(0xe300f000 | rs << 20 | off, 0x0024); 4078c2ecf20Sopenharmony_ci else 4088c2ecf20Sopenharmony_ci /* stmg %rs,%re,off(%r15) */ 4098c2ecf20Sopenharmony_ci _EMIT6_DISP(0xeb00f000 | rs << 20 | re << 16, 0x0024, off); 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci/* 4138c2ecf20Sopenharmony_ci * Restore registers from "rs" (register start) to "re" (register end) on stack 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_cistatic void restore_regs(struct bpf_jit *jit, u32 rs, u32 re, u32 stack_depth) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci u32 off = STK_OFF_R6 + (rs - 6) * 8; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (jit->seen & SEEN_STACK) 4208c2ecf20Sopenharmony_ci off += STK_OFF + stack_depth; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (rs == re) 4238c2ecf20Sopenharmony_ci /* lg %rs,off(%r15) */ 4248c2ecf20Sopenharmony_ci _EMIT6(0xe300f000 | rs << 20 | off, 0x0004); 4258c2ecf20Sopenharmony_ci else 4268c2ecf20Sopenharmony_ci /* lmg %rs,%re,off(%r15) */ 4278c2ecf20Sopenharmony_ci _EMIT6_DISP(0xeb00f000 | rs << 20 | re << 16, 0x0004, off); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci/* 4318c2ecf20Sopenharmony_ci * Return first seen register (from start) 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_cistatic int get_start(struct bpf_jit *jit, int start) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci int i; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci for (i = start; i <= 15; i++) { 4388c2ecf20Sopenharmony_ci if (jit->seen_reg[i]) 4398c2ecf20Sopenharmony_ci return i; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/* 4458c2ecf20Sopenharmony_ci * Return last seen register (from start) (gap >= 2) 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_cistatic int get_end(struct bpf_jit *jit, int start) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci int i; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci for (i = start; i < 15; i++) { 4528c2ecf20Sopenharmony_ci if (!jit->seen_reg[i] && !jit->seen_reg[i + 1]) 4538c2ecf20Sopenharmony_ci return i - 1; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci return jit->seen_reg[15] ? 15 : 14; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci#define REGS_SAVE 1 4598c2ecf20Sopenharmony_ci#define REGS_RESTORE 0 4608c2ecf20Sopenharmony_ci/* 4618c2ecf20Sopenharmony_ci * Save and restore clobbered registers (6-15) on stack. 4628c2ecf20Sopenharmony_ci * We save/restore registers in chunks with gap >= 2 registers. 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_cistatic void save_restore_regs(struct bpf_jit *jit, int op, u32 stack_depth) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci const int last = 15, save_restore_size = 6; 4678c2ecf20Sopenharmony_ci int re = 6, rs; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (is_first_pass(jit)) { 4708c2ecf20Sopenharmony_ci /* 4718c2ecf20Sopenharmony_ci * We don't know yet which registers are used. Reserve space 4728c2ecf20Sopenharmony_ci * conservatively. 4738c2ecf20Sopenharmony_ci */ 4748c2ecf20Sopenharmony_ci jit->prg += (last - re + 1) * save_restore_size; 4758c2ecf20Sopenharmony_ci return; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci do { 4798c2ecf20Sopenharmony_ci rs = get_start(jit, re); 4808c2ecf20Sopenharmony_ci if (!rs) 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci re = get_end(jit, rs + 1); 4838c2ecf20Sopenharmony_ci if (op == REGS_SAVE) 4848c2ecf20Sopenharmony_ci save_regs(jit, rs, re); 4858c2ecf20Sopenharmony_ci else 4868c2ecf20Sopenharmony_ci restore_regs(jit, rs, re, stack_depth); 4878c2ecf20Sopenharmony_ci re++; 4888c2ecf20Sopenharmony_ci } while (re <= last); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_cistatic void bpf_skip(struct bpf_jit *jit, int size) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci if (size >= 6 && !is_valid_rel(size)) { 4948c2ecf20Sopenharmony_ci /* brcl 0xf,size */ 4958c2ecf20Sopenharmony_ci EMIT6_PCREL_RIL(0xc0f4000000, size); 4968c2ecf20Sopenharmony_ci size -= 6; 4978c2ecf20Sopenharmony_ci } else if (size >= 4 && is_valid_rel(size)) { 4988c2ecf20Sopenharmony_ci /* brc 0xf,size */ 4998c2ecf20Sopenharmony_ci EMIT4_PCREL(0xa7f40000, size); 5008c2ecf20Sopenharmony_ci size -= 4; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci while (size >= 2) { 5038c2ecf20Sopenharmony_ci /* bcr 0,%0 */ 5048c2ecf20Sopenharmony_ci _EMIT2(0x0700); 5058c2ecf20Sopenharmony_ci size -= 2; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/* 5108c2ecf20Sopenharmony_ci * Emit function prologue 5118c2ecf20Sopenharmony_ci * 5128c2ecf20Sopenharmony_ci * Save registers and create stack frame if necessary. 5138c2ecf20Sopenharmony_ci * See stack frame layout desription in "bpf_jit.h"! 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_cistatic void bpf_jit_prologue(struct bpf_jit *jit, u32 stack_depth) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci if (jit->seen & SEEN_TAIL_CALL) { 5188c2ecf20Sopenharmony_ci /* xc STK_OFF_TCCNT(4,%r15),STK_OFF_TCCNT(%r15) */ 5198c2ecf20Sopenharmony_ci _EMIT6(0xd703f000 | STK_OFF_TCCNT, 0xf000 | STK_OFF_TCCNT); 5208c2ecf20Sopenharmony_ci } else { 5218c2ecf20Sopenharmony_ci /* 5228c2ecf20Sopenharmony_ci * There are no tail calls. Insert nops in order to have 5238c2ecf20Sopenharmony_ci * tail_call_start at a predictable offset. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ci bpf_skip(jit, 6); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci /* Tail calls have to skip above initialization */ 5288c2ecf20Sopenharmony_ci jit->tail_call_start = jit->prg; 5298c2ecf20Sopenharmony_ci /* Save registers */ 5308c2ecf20Sopenharmony_ci save_restore_regs(jit, REGS_SAVE, stack_depth); 5318c2ecf20Sopenharmony_ci /* Setup literal pool */ 5328c2ecf20Sopenharmony_ci if (is_first_pass(jit) || (jit->seen & SEEN_LITERAL)) { 5338c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && 5348c2ecf20Sopenharmony_ci is_valid_ldisp(jit->size - (jit->prg + 2))) { 5358c2ecf20Sopenharmony_ci /* basr %l,0 */ 5368c2ecf20Sopenharmony_ci EMIT2(0x0d00, REG_L, REG_0); 5378c2ecf20Sopenharmony_ci jit->base_ip = jit->prg; 5388c2ecf20Sopenharmony_ci } else { 5398c2ecf20Sopenharmony_ci /* larl %l,lit32_start */ 5408c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc0000000, REG_L, jit->lit32_start); 5418c2ecf20Sopenharmony_ci jit->base_ip = jit->lit32_start; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci /* Setup stack and backchain */ 5458c2ecf20Sopenharmony_ci if (is_first_pass(jit) || (jit->seen & SEEN_STACK)) { 5468c2ecf20Sopenharmony_ci if (is_first_pass(jit) || (jit->seen & SEEN_FUNC)) 5478c2ecf20Sopenharmony_ci /* lgr %w1,%r15 (backchain) */ 5488c2ecf20Sopenharmony_ci EMIT4(0xb9040000, REG_W1, REG_15); 5498c2ecf20Sopenharmony_ci /* la %bfp,STK_160_UNUSED(%r15) (BPF frame pointer) */ 5508c2ecf20Sopenharmony_ci EMIT4_DISP(0x41000000, BPF_REG_FP, REG_15, STK_160_UNUSED); 5518c2ecf20Sopenharmony_ci /* aghi %r15,-STK_OFF */ 5528c2ecf20Sopenharmony_ci EMIT4_IMM(0xa70b0000, REG_15, -(STK_OFF + stack_depth)); 5538c2ecf20Sopenharmony_ci if (is_first_pass(jit) || (jit->seen & SEEN_FUNC)) 5548c2ecf20Sopenharmony_ci /* stg %w1,152(%r15) (backchain) */ 5558c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, 5568c2ecf20Sopenharmony_ci REG_15, 152); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci/* 5618c2ecf20Sopenharmony_ci * Function epilogue 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_cistatic void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci jit->exit_ip = jit->prg; 5668c2ecf20Sopenharmony_ci /* Load exit code: lgr %r2,%b0 */ 5678c2ecf20Sopenharmony_ci EMIT4(0xb9040000, REG_2, BPF_REG_0); 5688c2ecf20Sopenharmony_ci /* Restore registers */ 5698c2ecf20Sopenharmony_ci save_restore_regs(jit, REGS_RESTORE, stack_depth); 5708c2ecf20Sopenharmony_ci if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable) { 5718c2ecf20Sopenharmony_ci jit->r14_thunk_ip = jit->prg; 5728c2ecf20Sopenharmony_ci /* Generate __s390_indirect_jump_r14 thunk */ 5738c2ecf20Sopenharmony_ci if (test_facility(35)) { 5748c2ecf20Sopenharmony_ci /* exrl %r0,.+10 */ 5758c2ecf20Sopenharmony_ci EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10); 5768c2ecf20Sopenharmony_ci } else { 5778c2ecf20Sopenharmony_ci /* larl %r1,.+14 */ 5788c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14); 5798c2ecf20Sopenharmony_ci /* ex 0,0(%r1) */ 5808c2ecf20Sopenharmony_ci EMIT4_DISP(0x44000000, REG_0, REG_1, 0); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci /* j . */ 5838c2ecf20Sopenharmony_ci EMIT4_PCREL(0xa7f40000, 0); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci /* br %r14 */ 5868c2ecf20Sopenharmony_ci _EMIT2(0x07fe); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable && 5898c2ecf20Sopenharmony_ci (is_first_pass(jit) || (jit->seen & SEEN_FUNC))) { 5908c2ecf20Sopenharmony_ci jit->r1_thunk_ip = jit->prg; 5918c2ecf20Sopenharmony_ci /* Generate __s390_indirect_jump_r1 thunk */ 5928c2ecf20Sopenharmony_ci if (test_facility(35)) { 5938c2ecf20Sopenharmony_ci /* exrl %r0,.+10 */ 5948c2ecf20Sopenharmony_ci EMIT6_PCREL_RIL(0xc6000000, jit->prg + 10); 5958c2ecf20Sopenharmony_ci /* j . */ 5968c2ecf20Sopenharmony_ci EMIT4_PCREL(0xa7f40000, 0); 5978c2ecf20Sopenharmony_ci /* br %r1 */ 5988c2ecf20Sopenharmony_ci _EMIT2(0x07f1); 5998c2ecf20Sopenharmony_ci } else { 6008c2ecf20Sopenharmony_ci /* ex 0,S390_lowcore.br_r1_tampoline */ 6018c2ecf20Sopenharmony_ci EMIT4_DISP(0x44000000, REG_0, REG_0, 6028c2ecf20Sopenharmony_ci offsetof(struct lowcore, br_r1_trampoline)); 6038c2ecf20Sopenharmony_ci /* j . */ 6048c2ecf20Sopenharmony_ci EMIT4_PCREL(0xa7f40000, 0); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int get_probe_mem_regno(const u8 *insn) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci /* 6128c2ecf20Sopenharmony_ci * insn must point to llgc, llgh, llgf or lg, which have destination 6138c2ecf20Sopenharmony_ci * register at the same position. 6148c2ecf20Sopenharmony_ci */ 6158c2ecf20Sopenharmony_ci if (insn[0] != 0xe3) /* common llgc, llgh, llgf and lg prefix */ 6168c2ecf20Sopenharmony_ci return -1; 6178c2ecf20Sopenharmony_ci if (insn[5] != 0x90 && /* llgc */ 6188c2ecf20Sopenharmony_ci insn[5] != 0x91 && /* llgh */ 6198c2ecf20Sopenharmony_ci insn[5] != 0x16 && /* llgf */ 6208c2ecf20Sopenharmony_ci insn[5] != 0x04) /* lg */ 6218c2ecf20Sopenharmony_ci return -1; 6228c2ecf20Sopenharmony_ci return insn[1] >> 4; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic bool ex_handler_bpf(const struct exception_table_entry *x, 6268c2ecf20Sopenharmony_ci struct pt_regs *regs) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci int regno; 6298c2ecf20Sopenharmony_ci u8 *insn; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci regs->psw.addr = extable_fixup(x); 6328c2ecf20Sopenharmony_ci insn = (u8 *)__rewind_psw(regs->psw, regs->int_code >> 16); 6338c2ecf20Sopenharmony_ci regno = get_probe_mem_regno(insn); 6348c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(regno < 0)) 6358c2ecf20Sopenharmony_ci /* JIT bug - unexpected instruction. */ 6368c2ecf20Sopenharmony_ci return false; 6378c2ecf20Sopenharmony_ci regs->gprs[regno] = 0; 6388c2ecf20Sopenharmony_ci return true; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int bpf_jit_probe_mem(struct bpf_jit *jit, struct bpf_prog *fp, 6428c2ecf20Sopenharmony_ci int probe_prg, int nop_prg) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct exception_table_entry *ex; 6458c2ecf20Sopenharmony_ci s64 delta; 6468c2ecf20Sopenharmony_ci u8 *insn; 6478c2ecf20Sopenharmony_ci int prg; 6488c2ecf20Sopenharmony_ci int i; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (!fp->aux->extable) 6518c2ecf20Sopenharmony_ci /* Do nothing during early JIT passes. */ 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci insn = jit->prg_buf + probe_prg; 6548c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(get_probe_mem_regno(insn) < 0)) 6558c2ecf20Sopenharmony_ci /* JIT bug - unexpected probe instruction. */ 6568c2ecf20Sopenharmony_ci return -1; 6578c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(probe_prg + insn_length(*insn) != nop_prg)) 6588c2ecf20Sopenharmony_ci /* JIT bug - gap between probe and nop instructions. */ 6598c2ecf20Sopenharmony_ci return -1; 6608c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 6618c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(jit->excnt >= fp->aux->num_exentries)) 6628c2ecf20Sopenharmony_ci /* Verifier bug - not enough entries. */ 6638c2ecf20Sopenharmony_ci return -1; 6648c2ecf20Sopenharmony_ci ex = &fp->aux->extable[jit->excnt]; 6658c2ecf20Sopenharmony_ci /* Add extable entries for probe and nop instructions. */ 6668c2ecf20Sopenharmony_ci prg = i == 0 ? probe_prg : nop_prg; 6678c2ecf20Sopenharmony_ci delta = jit->prg_buf + prg - (u8 *)&ex->insn; 6688c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(delta < INT_MIN || delta > INT_MAX)) 6698c2ecf20Sopenharmony_ci /* JIT bug - code and extable must be close. */ 6708c2ecf20Sopenharmony_ci return -1; 6718c2ecf20Sopenharmony_ci ex->insn = delta; 6728c2ecf20Sopenharmony_ci /* 6738c2ecf20Sopenharmony_ci * Always land on the nop. Note that extable infrastructure 6748c2ecf20Sopenharmony_ci * ignores fixup field, it is handled by ex_handler_bpf(). 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci delta = jit->prg_buf + nop_prg - (u8 *)&ex->fixup; 6778c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(delta < INT_MIN || delta > INT_MAX)) 6788c2ecf20Sopenharmony_ci /* JIT bug - landing pad and extable must be close. */ 6798c2ecf20Sopenharmony_ci return -1; 6808c2ecf20Sopenharmony_ci ex->fixup = delta; 6818c2ecf20Sopenharmony_ci ex->handler = (u8 *)ex_handler_bpf - (u8 *)&ex->handler; 6828c2ecf20Sopenharmony_ci jit->excnt++; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci/* 6888c2ecf20Sopenharmony_ci * Compile one eBPF instruction into s390x code 6898c2ecf20Sopenharmony_ci * 6908c2ecf20Sopenharmony_ci * NOTE: Use noinline because for gcov (-fprofile-arcs) gcc allocates a lot of 6918c2ecf20Sopenharmony_ci * stack space for the large switch statement. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_cistatic noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, 6948c2ecf20Sopenharmony_ci int i, bool extra_pass, u32 stack_depth) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct bpf_insn *insn = &fp->insnsi[i]; 6978c2ecf20Sopenharmony_ci u32 dst_reg = insn->dst_reg; 6988c2ecf20Sopenharmony_ci u32 src_reg = insn->src_reg; 6998c2ecf20Sopenharmony_ci int last, insn_count = 1; 7008c2ecf20Sopenharmony_ci u32 *addrs = jit->addrs; 7018c2ecf20Sopenharmony_ci s32 imm = insn->imm; 7028c2ecf20Sopenharmony_ci s16 off = insn->off; 7038c2ecf20Sopenharmony_ci int probe_prg = -1; 7048c2ecf20Sopenharmony_ci unsigned int mask; 7058c2ecf20Sopenharmony_ci int nop_prg; 7068c2ecf20Sopenharmony_ci int err; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (BPF_CLASS(insn->code) == BPF_LDX && 7098c2ecf20Sopenharmony_ci BPF_MODE(insn->code) == BPF_PROBE_MEM) 7108c2ecf20Sopenharmony_ci probe_prg = jit->prg; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci switch (insn->code) { 7138c2ecf20Sopenharmony_ci /* 7148c2ecf20Sopenharmony_ci * BPF_MOV 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_X: /* dst = (u32) src */ 7178c2ecf20Sopenharmony_ci /* llgfr %dst,%src */ 7188c2ecf20Sopenharmony_ci EMIT4(0xb9160000, dst_reg, src_reg); 7198c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 7208c2ecf20Sopenharmony_ci insn_count = 2; 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_X: /* dst = src */ 7238c2ecf20Sopenharmony_ci /* lgr %dst,%src */ 7248c2ecf20Sopenharmony_ci EMIT4(0xb9040000, dst_reg, src_reg); 7258c2ecf20Sopenharmony_ci break; 7268c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_K: /* dst = (u32) imm */ 7278c2ecf20Sopenharmony_ci /* llilf %dst,imm */ 7288c2ecf20Sopenharmony_ci EMIT6_IMM(0xc00f0000, dst_reg, imm); 7298c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 7308c2ecf20Sopenharmony_ci insn_count = 2; 7318c2ecf20Sopenharmony_ci break; 7328c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_K: /* dst = imm */ 7338c2ecf20Sopenharmony_ci /* lgfi %dst,imm */ 7348c2ecf20Sopenharmony_ci EMIT6_IMM(0xc0010000, dst_reg, imm); 7358c2ecf20Sopenharmony_ci break; 7368c2ecf20Sopenharmony_ci /* 7378c2ecf20Sopenharmony_ci * BPF_LD 64 7388c2ecf20Sopenharmony_ci */ 7398c2ecf20Sopenharmony_ci case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */ 7408c2ecf20Sopenharmony_ci { 7418c2ecf20Sopenharmony_ci /* 16 byte instruction that uses two 'struct bpf_insn' */ 7428c2ecf20Sopenharmony_ci u64 imm64; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci imm64 = (u64)(u32) insn[0].imm | ((u64)(u32) insn[1].imm) << 32; 7458c2ecf20Sopenharmony_ci /* lgrl %dst,imm */ 7468c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc4080000, dst_reg, _EMIT_CONST_U64(imm64)); 7478c2ecf20Sopenharmony_ci insn_count = 2; 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci /* 7518c2ecf20Sopenharmony_ci * BPF_ADD 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_X: /* dst = (u32) dst + (u32) src */ 7548c2ecf20Sopenharmony_ci /* ar %dst,%src */ 7558c2ecf20Sopenharmony_ci EMIT2(0x1a00, dst_reg, src_reg); 7568c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 7578c2ecf20Sopenharmony_ci break; 7588c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_X: /* dst = dst + src */ 7598c2ecf20Sopenharmony_ci /* agr %dst,%src */ 7608c2ecf20Sopenharmony_ci EMIT4(0xb9080000, dst_reg, src_reg); 7618c2ecf20Sopenharmony_ci break; 7628c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_K: /* dst = (u32) dst + (u32) imm */ 7638c2ecf20Sopenharmony_ci if (imm != 0) { 7648c2ecf20Sopenharmony_ci /* alfi %dst,imm */ 7658c2ecf20Sopenharmony_ci EMIT6_IMM(0xc20b0000, dst_reg, imm); 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_K: /* dst = dst + imm */ 7708c2ecf20Sopenharmony_ci if (!imm) 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci /* agfi %dst,imm */ 7738c2ecf20Sopenharmony_ci EMIT6_IMM(0xc2080000, dst_reg, imm); 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci /* 7768c2ecf20Sopenharmony_ci * BPF_SUB 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_X: /* dst = (u32) dst - (u32) src */ 7798c2ecf20Sopenharmony_ci /* sr %dst,%src */ 7808c2ecf20Sopenharmony_ci EMIT2(0x1b00, dst_reg, src_reg); 7818c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_X: /* dst = dst - src */ 7848c2ecf20Sopenharmony_ci /* sgr %dst,%src */ 7858c2ecf20Sopenharmony_ci EMIT4(0xb9090000, dst_reg, src_reg); 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_K: /* dst = (u32) dst - (u32) imm */ 7888c2ecf20Sopenharmony_ci if (imm != 0) { 7898c2ecf20Sopenharmony_ci /* alfi %dst,-imm */ 7908c2ecf20Sopenharmony_ci EMIT6_IMM(0xc20b0000, dst_reg, -imm); 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_K: /* dst = dst - imm */ 7958c2ecf20Sopenharmony_ci if (!imm) 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci if (imm == -0x80000000) { 7988c2ecf20Sopenharmony_ci /* algfi %dst,0x80000000 */ 7998c2ecf20Sopenharmony_ci EMIT6_IMM(0xc20a0000, dst_reg, 0x80000000); 8008c2ecf20Sopenharmony_ci } else { 8018c2ecf20Sopenharmony_ci /* agfi %dst,-imm */ 8028c2ecf20Sopenharmony_ci EMIT6_IMM(0xc2080000, dst_reg, -imm); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci /* 8068c2ecf20Sopenharmony_ci * BPF_MUL 8078c2ecf20Sopenharmony_ci */ 8088c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_X: /* dst = (u32) dst * (u32) src */ 8098c2ecf20Sopenharmony_ci /* msr %dst,%src */ 8108c2ecf20Sopenharmony_ci EMIT4(0xb2520000, dst_reg, src_reg); 8118c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 8128c2ecf20Sopenharmony_ci break; 8138c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_X: /* dst = dst * src */ 8148c2ecf20Sopenharmony_ci /* msgr %dst,%src */ 8158c2ecf20Sopenharmony_ci EMIT4(0xb90c0000, dst_reg, src_reg); 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_K: /* dst = (u32) dst * (u32) imm */ 8188c2ecf20Sopenharmony_ci if (imm != 1) { 8198c2ecf20Sopenharmony_ci /* msfi %r5,imm */ 8208c2ecf20Sopenharmony_ci EMIT6_IMM(0xc2010000, dst_reg, imm); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_K: /* dst = dst * imm */ 8258c2ecf20Sopenharmony_ci if (imm == 1) 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci /* msgfi %dst,imm */ 8288c2ecf20Sopenharmony_ci EMIT6_IMM(0xc2000000, dst_reg, imm); 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci /* 8318c2ecf20Sopenharmony_ci * BPF_DIV / BPF_MOD 8328c2ecf20Sopenharmony_ci */ 8338c2ecf20Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_X: /* dst = (u32) dst / (u32) src */ 8348c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_X: /* dst = (u32) dst % (u32) src */ 8358c2ecf20Sopenharmony_ci { 8368c2ecf20Sopenharmony_ci int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* lhi %w0,0 */ 8398c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7080000, REG_W0, 0); 8408c2ecf20Sopenharmony_ci /* lr %w1,%dst */ 8418c2ecf20Sopenharmony_ci EMIT2(0x1800, REG_W1, dst_reg); 8428c2ecf20Sopenharmony_ci /* dlr %w0,%src */ 8438c2ecf20Sopenharmony_ci EMIT4(0xb9970000, REG_W0, src_reg); 8448c2ecf20Sopenharmony_ci /* llgfr %dst,%rc */ 8458c2ecf20Sopenharmony_ci EMIT4(0xb9160000, dst_reg, rc_reg); 8468c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 8478c2ecf20Sopenharmony_ci insn_count = 2; 8488c2ecf20Sopenharmony_ci break; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_X: /* dst = dst / src */ 8518c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_X: /* dst = dst % src */ 8528c2ecf20Sopenharmony_ci { 8538c2ecf20Sopenharmony_ci int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* lghi %w0,0 */ 8568c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7090000, REG_W0, 0); 8578c2ecf20Sopenharmony_ci /* lgr %w1,%dst */ 8588c2ecf20Sopenharmony_ci EMIT4(0xb9040000, REG_W1, dst_reg); 8598c2ecf20Sopenharmony_ci /* dlgr %w0,%dst */ 8608c2ecf20Sopenharmony_ci EMIT4(0xb9870000, REG_W0, src_reg); 8618c2ecf20Sopenharmony_ci /* lgr %dst,%rc */ 8628c2ecf20Sopenharmony_ci EMIT4(0xb9040000, dst_reg, rc_reg); 8638c2ecf20Sopenharmony_ci break; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_K: /* dst = (u32) dst / (u32) imm */ 8668c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_K: /* dst = (u32) dst % (u32) imm */ 8678c2ecf20Sopenharmony_ci { 8688c2ecf20Sopenharmony_ci int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (imm == 1) { 8718c2ecf20Sopenharmony_ci if (BPF_OP(insn->code) == BPF_MOD) 8728c2ecf20Sopenharmony_ci /* lhgi %dst,0 */ 8738c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7090000, dst_reg, 0); 8748c2ecf20Sopenharmony_ci else 8758c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ci /* lhi %w0,0 */ 8798c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7080000, REG_W0, 0); 8808c2ecf20Sopenharmony_ci /* lr %w1,%dst */ 8818c2ecf20Sopenharmony_ci EMIT2(0x1800, REG_W1, dst_reg); 8828c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && can_use_ldisp_for_lit32(jit)) { 8838c2ecf20Sopenharmony_ci /* dl %w0,<d(imm)>(%l) */ 8848c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0097, REG_W0, REG_0, REG_L, 8858c2ecf20Sopenharmony_ci EMIT_CONST_U32(imm)); 8868c2ecf20Sopenharmony_ci } else { 8878c2ecf20Sopenharmony_ci /* lgfrl %dst,imm */ 8888c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc40c0000, dst_reg, 8898c2ecf20Sopenharmony_ci _EMIT_CONST_U32(imm)); 8908c2ecf20Sopenharmony_ci jit->seen |= SEEN_LITERAL; 8918c2ecf20Sopenharmony_ci /* dlr %w0,%dst */ 8928c2ecf20Sopenharmony_ci EMIT4(0xb9970000, REG_W0, dst_reg); 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci /* llgfr %dst,%rc */ 8958c2ecf20Sopenharmony_ci EMIT4(0xb9160000, dst_reg, rc_reg); 8968c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 8978c2ecf20Sopenharmony_ci insn_count = 2; 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_K: /* dst = dst / imm */ 9018c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_K: /* dst = dst % imm */ 9028c2ecf20Sopenharmony_ci { 9038c2ecf20Sopenharmony_ci int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (imm == 1) { 9068c2ecf20Sopenharmony_ci if (BPF_OP(insn->code) == BPF_MOD) 9078c2ecf20Sopenharmony_ci /* lhgi %dst,0 */ 9088c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7090000, dst_reg, 0); 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci /* lghi %w0,0 */ 9128c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7090000, REG_W0, 0); 9138c2ecf20Sopenharmony_ci /* lgr %w1,%dst */ 9148c2ecf20Sopenharmony_ci EMIT4(0xb9040000, REG_W1, dst_reg); 9158c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) { 9168c2ecf20Sopenharmony_ci /* dlg %w0,<d(imm)>(%l) */ 9178c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0087, REG_W0, REG_0, REG_L, 9188c2ecf20Sopenharmony_ci EMIT_CONST_U64(imm)); 9198c2ecf20Sopenharmony_ci } else { 9208c2ecf20Sopenharmony_ci /* lgrl %dst,imm */ 9218c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc4080000, dst_reg, 9228c2ecf20Sopenharmony_ci _EMIT_CONST_U64(imm)); 9238c2ecf20Sopenharmony_ci jit->seen |= SEEN_LITERAL; 9248c2ecf20Sopenharmony_ci /* dlgr %w0,%dst */ 9258c2ecf20Sopenharmony_ci EMIT4(0xb9870000, REG_W0, dst_reg); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci /* lgr %dst,%rc */ 9288c2ecf20Sopenharmony_ci EMIT4(0xb9040000, dst_reg, rc_reg); 9298c2ecf20Sopenharmony_ci break; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci /* 9328c2ecf20Sopenharmony_ci * BPF_AND 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_X: /* dst = (u32) dst & (u32) src */ 9358c2ecf20Sopenharmony_ci /* nr %dst,%src */ 9368c2ecf20Sopenharmony_ci EMIT2(0x1400, dst_reg, src_reg); 9378c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 9388c2ecf20Sopenharmony_ci break; 9398c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_X: /* dst = dst & src */ 9408c2ecf20Sopenharmony_ci /* ngr %dst,%src */ 9418c2ecf20Sopenharmony_ci EMIT4(0xb9800000, dst_reg, src_reg); 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_K: /* dst = (u32) dst & (u32) imm */ 9448c2ecf20Sopenharmony_ci /* nilf %dst,imm */ 9458c2ecf20Sopenharmony_ci EMIT6_IMM(0xc00b0000, dst_reg, imm); 9468c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 9478c2ecf20Sopenharmony_ci break; 9488c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_K: /* dst = dst & imm */ 9498c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) { 9508c2ecf20Sopenharmony_ci /* ng %dst,<d(imm)>(%l) */ 9518c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0080, 9528c2ecf20Sopenharmony_ci dst_reg, REG_0, REG_L, 9538c2ecf20Sopenharmony_ci EMIT_CONST_U64(imm)); 9548c2ecf20Sopenharmony_ci } else { 9558c2ecf20Sopenharmony_ci /* lgrl %w0,imm */ 9568c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc4080000, REG_W0, 9578c2ecf20Sopenharmony_ci _EMIT_CONST_U64(imm)); 9588c2ecf20Sopenharmony_ci jit->seen |= SEEN_LITERAL; 9598c2ecf20Sopenharmony_ci /* ngr %dst,%w0 */ 9608c2ecf20Sopenharmony_ci EMIT4(0xb9800000, dst_reg, REG_W0); 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci break; 9638c2ecf20Sopenharmony_ci /* 9648c2ecf20Sopenharmony_ci * BPF_OR 9658c2ecf20Sopenharmony_ci */ 9668c2ecf20Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_X: /* dst = (u32) dst | (u32) src */ 9678c2ecf20Sopenharmony_ci /* or %dst,%src */ 9688c2ecf20Sopenharmony_ci EMIT2(0x1600, dst_reg, src_reg); 9698c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 9708c2ecf20Sopenharmony_ci break; 9718c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_X: /* dst = dst | src */ 9728c2ecf20Sopenharmony_ci /* ogr %dst,%src */ 9738c2ecf20Sopenharmony_ci EMIT4(0xb9810000, dst_reg, src_reg); 9748c2ecf20Sopenharmony_ci break; 9758c2ecf20Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_K: /* dst = (u32) dst | (u32) imm */ 9768c2ecf20Sopenharmony_ci /* oilf %dst,imm */ 9778c2ecf20Sopenharmony_ci EMIT6_IMM(0xc00d0000, dst_reg, imm); 9788c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 9798c2ecf20Sopenharmony_ci break; 9808c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_K: /* dst = dst | imm */ 9818c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) { 9828c2ecf20Sopenharmony_ci /* og %dst,<d(imm)>(%l) */ 9838c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0081, 9848c2ecf20Sopenharmony_ci dst_reg, REG_0, REG_L, 9858c2ecf20Sopenharmony_ci EMIT_CONST_U64(imm)); 9868c2ecf20Sopenharmony_ci } else { 9878c2ecf20Sopenharmony_ci /* lgrl %w0,imm */ 9888c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc4080000, REG_W0, 9898c2ecf20Sopenharmony_ci _EMIT_CONST_U64(imm)); 9908c2ecf20Sopenharmony_ci jit->seen |= SEEN_LITERAL; 9918c2ecf20Sopenharmony_ci /* ogr %dst,%w0 */ 9928c2ecf20Sopenharmony_ci EMIT4(0xb9810000, dst_reg, REG_W0); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci break; 9958c2ecf20Sopenharmony_ci /* 9968c2ecf20Sopenharmony_ci * BPF_XOR 9978c2ecf20Sopenharmony_ci */ 9988c2ecf20Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_X: /* dst = (u32) dst ^ (u32) src */ 9998c2ecf20Sopenharmony_ci /* xr %dst,%src */ 10008c2ecf20Sopenharmony_ci EMIT2(0x1700, dst_reg, src_reg); 10018c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 10028c2ecf20Sopenharmony_ci break; 10038c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_X: /* dst = dst ^ src */ 10048c2ecf20Sopenharmony_ci /* xgr %dst,%src */ 10058c2ecf20Sopenharmony_ci EMIT4(0xb9820000, dst_reg, src_reg); 10068c2ecf20Sopenharmony_ci break; 10078c2ecf20Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_K: /* dst = (u32) dst ^ (u32) imm */ 10088c2ecf20Sopenharmony_ci if (imm != 0) { 10098c2ecf20Sopenharmony_ci /* xilf %dst,imm */ 10108c2ecf20Sopenharmony_ci EMIT6_IMM(0xc0070000, dst_reg, imm); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_K: /* dst = dst ^ imm */ 10158c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) { 10168c2ecf20Sopenharmony_ci /* xg %dst,<d(imm)>(%l) */ 10178c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0082, 10188c2ecf20Sopenharmony_ci dst_reg, REG_0, REG_L, 10198c2ecf20Sopenharmony_ci EMIT_CONST_U64(imm)); 10208c2ecf20Sopenharmony_ci } else { 10218c2ecf20Sopenharmony_ci /* lgrl %w0,imm */ 10228c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc4080000, REG_W0, 10238c2ecf20Sopenharmony_ci _EMIT_CONST_U64(imm)); 10248c2ecf20Sopenharmony_ci jit->seen |= SEEN_LITERAL; 10258c2ecf20Sopenharmony_ci /* xgr %dst,%w0 */ 10268c2ecf20Sopenharmony_ci EMIT4(0xb9820000, dst_reg, REG_W0); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci break; 10298c2ecf20Sopenharmony_ci /* 10308c2ecf20Sopenharmony_ci * BPF_LSH 10318c2ecf20Sopenharmony_ci */ 10328c2ecf20Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_X: /* dst = (u32) dst << (u32) src */ 10338c2ecf20Sopenharmony_ci /* sll %dst,0(%src) */ 10348c2ecf20Sopenharmony_ci EMIT4_DISP(0x89000000, dst_reg, src_reg, 0); 10358c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 10368c2ecf20Sopenharmony_ci break; 10378c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_X: /* dst = dst << src */ 10388c2ecf20Sopenharmony_ci /* sllg %dst,%dst,0(%src) */ 10398c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x000d, dst_reg, dst_reg, src_reg, 0); 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_K: /* dst = (u32) dst << (u32) imm */ 10428c2ecf20Sopenharmony_ci if (imm != 0) { 10438c2ecf20Sopenharmony_ci /* sll %dst,imm(%r0) */ 10448c2ecf20Sopenharmony_ci EMIT4_DISP(0x89000000, dst_reg, REG_0, imm); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 10478c2ecf20Sopenharmony_ci break; 10488c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_K: /* dst = dst << imm */ 10498c2ecf20Sopenharmony_ci if (imm == 0) 10508c2ecf20Sopenharmony_ci break; 10518c2ecf20Sopenharmony_ci /* sllg %dst,%dst,imm(%r0) */ 10528c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x000d, dst_reg, dst_reg, REG_0, imm); 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci /* 10558c2ecf20Sopenharmony_ci * BPF_RSH 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_X: /* dst = (u32) dst >> (u32) src */ 10588c2ecf20Sopenharmony_ci /* srl %dst,0(%src) */ 10598c2ecf20Sopenharmony_ci EMIT4_DISP(0x88000000, dst_reg, src_reg, 0); 10608c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 10618c2ecf20Sopenharmony_ci break; 10628c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_X: /* dst = dst >> src */ 10638c2ecf20Sopenharmony_ci /* srlg %dst,%dst,0(%src) */ 10648c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x000c, dst_reg, dst_reg, src_reg, 0); 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_K: /* dst = (u32) dst >> (u32) imm */ 10678c2ecf20Sopenharmony_ci if (imm != 0) { 10688c2ecf20Sopenharmony_ci /* srl %dst,imm(%r0) */ 10698c2ecf20Sopenharmony_ci EMIT4_DISP(0x88000000, dst_reg, REG_0, imm); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 10728c2ecf20Sopenharmony_ci break; 10738c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_K: /* dst = dst >> imm */ 10748c2ecf20Sopenharmony_ci if (imm == 0) 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci /* srlg %dst,%dst,imm(%r0) */ 10778c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x000c, dst_reg, dst_reg, REG_0, imm); 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci /* 10808c2ecf20Sopenharmony_ci * BPF_ARSH 10818c2ecf20Sopenharmony_ci */ 10828c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_X: /* ((s32) dst) >>= src */ 10838c2ecf20Sopenharmony_ci /* sra %dst,%dst,0(%src) */ 10848c2ecf20Sopenharmony_ci EMIT4_DISP(0x8a000000, dst_reg, src_reg, 0); 10858c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 10868c2ecf20Sopenharmony_ci break; 10878c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_X: /* ((s64) dst) >>= src */ 10888c2ecf20Sopenharmony_ci /* srag %dst,%dst,0(%src) */ 10898c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, src_reg, 0); 10908c2ecf20Sopenharmony_ci break; 10918c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_K: /* ((s32) dst >> imm */ 10928c2ecf20Sopenharmony_ci if (imm != 0) { 10938c2ecf20Sopenharmony_ci /* sra %dst,imm(%r0) */ 10948c2ecf20Sopenharmony_ci EMIT4_DISP(0x8a000000, dst_reg, REG_0, imm); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_K: /* ((s64) dst) >>= imm */ 10998c2ecf20Sopenharmony_ci if (imm == 0) 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci /* srag %dst,%dst,imm(%r0) */ 11028c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, REG_0, imm); 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci /* 11058c2ecf20Sopenharmony_ci * BPF_NEG 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_ci case BPF_ALU | BPF_NEG: /* dst = (u32) -dst */ 11088c2ecf20Sopenharmony_ci /* lcr %dst,%dst */ 11098c2ecf20Sopenharmony_ci EMIT2(0x1300, dst_reg, dst_reg); 11108c2ecf20Sopenharmony_ci EMIT_ZERO(dst_reg); 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_NEG: /* dst = -dst */ 11138c2ecf20Sopenharmony_ci /* lcgr %dst,%dst */ 11148c2ecf20Sopenharmony_ci EMIT4(0xb9030000, dst_reg, dst_reg); 11158c2ecf20Sopenharmony_ci break; 11168c2ecf20Sopenharmony_ci /* 11178c2ecf20Sopenharmony_ci * BPF_FROM_BE/LE 11188c2ecf20Sopenharmony_ci */ 11198c2ecf20Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_BE: 11208c2ecf20Sopenharmony_ci /* s390 is big endian, therefore only clear high order bytes */ 11218c2ecf20Sopenharmony_ci switch (imm) { 11228c2ecf20Sopenharmony_ci case 16: /* dst = (u16) cpu_to_be16(dst) */ 11238c2ecf20Sopenharmony_ci /* llghr %dst,%dst */ 11248c2ecf20Sopenharmony_ci EMIT4(0xb9850000, dst_reg, dst_reg); 11258c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 11268c2ecf20Sopenharmony_ci insn_count = 2; 11278c2ecf20Sopenharmony_ci break; 11288c2ecf20Sopenharmony_ci case 32: /* dst = (u32) cpu_to_be32(dst) */ 11298c2ecf20Sopenharmony_ci if (!fp->aux->verifier_zext) 11308c2ecf20Sopenharmony_ci /* llgfr %dst,%dst */ 11318c2ecf20Sopenharmony_ci EMIT4(0xb9160000, dst_reg, dst_reg); 11328c2ecf20Sopenharmony_ci break; 11338c2ecf20Sopenharmony_ci case 64: /* dst = (u64) cpu_to_be64(dst) */ 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_LE: 11388c2ecf20Sopenharmony_ci switch (imm) { 11398c2ecf20Sopenharmony_ci case 16: /* dst = (u16) cpu_to_le16(dst) */ 11408c2ecf20Sopenharmony_ci /* lrvr %dst,%dst */ 11418c2ecf20Sopenharmony_ci EMIT4(0xb91f0000, dst_reg, dst_reg); 11428c2ecf20Sopenharmony_ci /* srl %dst,16(%r0) */ 11438c2ecf20Sopenharmony_ci EMIT4_DISP(0x88000000, dst_reg, REG_0, 16); 11448c2ecf20Sopenharmony_ci /* llghr %dst,%dst */ 11458c2ecf20Sopenharmony_ci EMIT4(0xb9850000, dst_reg, dst_reg); 11468c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 11478c2ecf20Sopenharmony_ci insn_count = 2; 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci case 32: /* dst = (u32) cpu_to_le32(dst) */ 11508c2ecf20Sopenharmony_ci /* lrvr %dst,%dst */ 11518c2ecf20Sopenharmony_ci EMIT4(0xb91f0000, dst_reg, dst_reg); 11528c2ecf20Sopenharmony_ci if (!fp->aux->verifier_zext) 11538c2ecf20Sopenharmony_ci /* llgfr %dst,%dst */ 11548c2ecf20Sopenharmony_ci EMIT4(0xb9160000, dst_reg, dst_reg); 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci case 64: /* dst = (u64) cpu_to_le64(dst) */ 11578c2ecf20Sopenharmony_ci /* lrvgr %dst,%dst */ 11588c2ecf20Sopenharmony_ci EMIT4(0xb90f0000, dst_reg, dst_reg); 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci break; 11628c2ecf20Sopenharmony_ci /* 11638c2ecf20Sopenharmony_ci * BPF_NOSPEC (speculation barrier) 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_ci case BPF_ST | BPF_NOSPEC: 11668c2ecf20Sopenharmony_ci break; 11678c2ecf20Sopenharmony_ci /* 11688c2ecf20Sopenharmony_ci * BPF_ST(X) 11698c2ecf20Sopenharmony_ci */ 11708c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src_reg */ 11718c2ecf20Sopenharmony_ci /* stcy %src,off(%dst) */ 11728c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0072, src_reg, dst_reg, REG_0, off); 11738c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = src */ 11768c2ecf20Sopenharmony_ci /* sthy %src,off(%dst) */ 11778c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0070, src_reg, dst_reg, REG_0, off); 11788c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = src */ 11818c2ecf20Sopenharmony_ci /* sty %src,off(%dst) */ 11828c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0050, src_reg, dst_reg, REG_0, off); 11838c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 11848c2ecf20Sopenharmony_ci break; 11858c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_DW: /* (u64 *)(dst + off) = src */ 11868c2ecf20Sopenharmony_ci /* stg %src,off(%dst) */ 11878c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0024, src_reg, dst_reg, REG_0, off); 11888c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 11898c2ecf20Sopenharmony_ci break; 11908c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = imm */ 11918c2ecf20Sopenharmony_ci /* lhi %w0,imm */ 11928c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7080000, REG_W0, (u8) imm); 11938c2ecf20Sopenharmony_ci /* stcy %w0,off(dst) */ 11948c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0072, REG_W0, dst_reg, REG_0, off); 11958c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 11968c2ecf20Sopenharmony_ci break; 11978c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = imm */ 11988c2ecf20Sopenharmony_ci /* lhi %w0,imm */ 11998c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7080000, REG_W0, (u16) imm); 12008c2ecf20Sopenharmony_ci /* sthy %w0,off(dst) */ 12018c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0070, REG_W0, dst_reg, REG_0, off); 12028c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = imm */ 12058c2ecf20Sopenharmony_ci /* llilf %w0,imm */ 12068c2ecf20Sopenharmony_ci EMIT6_IMM(0xc00f0000, REG_W0, (u32) imm); 12078c2ecf20Sopenharmony_ci /* sty %w0,off(%dst) */ 12088c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, dst_reg, REG_0, off); 12098c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12108c2ecf20Sopenharmony_ci break; 12118c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_DW: /* *(u64 *)(dst + off) = imm */ 12128c2ecf20Sopenharmony_ci /* lgfi %w0,imm */ 12138c2ecf20Sopenharmony_ci EMIT6_IMM(0xc0010000, REG_W0, imm); 12148c2ecf20Sopenharmony_ci /* stg %w0,off(%dst) */ 12158c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W0, dst_reg, REG_0, off); 12168c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12178c2ecf20Sopenharmony_ci break; 12188c2ecf20Sopenharmony_ci /* 12198c2ecf20Sopenharmony_ci * BPF_STX XADD (atomic_add) 12208c2ecf20Sopenharmony_ci */ 12218c2ecf20Sopenharmony_ci case BPF_STX | BPF_XADD | BPF_W: /* *(u32 *)(dst + off) += src */ 12228c2ecf20Sopenharmony_ci /* laal %w0,%src,off(%dst) */ 12238c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W0, src_reg, 12248c2ecf20Sopenharmony_ci dst_reg, off); 12258c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12268c2ecf20Sopenharmony_ci break; 12278c2ecf20Sopenharmony_ci case BPF_STX | BPF_XADD | BPF_DW: /* *(u64 *)(dst + off) += src */ 12288c2ecf20Sopenharmony_ci /* laalg %w0,%src,off(%dst) */ 12298c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x00ea, REG_W0, src_reg, 12308c2ecf20Sopenharmony_ci dst_reg, off); 12318c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12328c2ecf20Sopenharmony_ci break; 12338c2ecf20Sopenharmony_ci /* 12348c2ecf20Sopenharmony_ci * BPF_LDX 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */ 12378c2ecf20Sopenharmony_ci case BPF_LDX | BPF_PROBE_MEM | BPF_B: 12388c2ecf20Sopenharmony_ci /* llgc %dst,0(off,%src) */ 12398c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0090, dst_reg, src_reg, REG_0, off); 12408c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12418c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 12428c2ecf20Sopenharmony_ci insn_count = 2; 12438c2ecf20Sopenharmony_ci break; 12448c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */ 12458c2ecf20Sopenharmony_ci case BPF_LDX | BPF_PROBE_MEM | BPF_H: 12468c2ecf20Sopenharmony_ci /* llgh %dst,0(off,%src) */ 12478c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0091, dst_reg, src_reg, REG_0, off); 12488c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12498c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 12508c2ecf20Sopenharmony_ci insn_count = 2; 12518c2ecf20Sopenharmony_ci break; 12528c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */ 12538c2ecf20Sopenharmony_ci case BPF_LDX | BPF_PROBE_MEM | BPF_W: 12548c2ecf20Sopenharmony_ci /* llgf %dst,off(%src) */ 12558c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12568c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0016, dst_reg, src_reg, REG_0, off); 12578c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[1])) 12588c2ecf20Sopenharmony_ci insn_count = 2; 12598c2ecf20Sopenharmony_ci break; 12608c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */ 12618c2ecf20Sopenharmony_ci case BPF_LDX | BPF_PROBE_MEM | BPF_DW: 12628c2ecf20Sopenharmony_ci /* lg %dst,0(off,%src) */ 12638c2ecf20Sopenharmony_ci jit->seen |= SEEN_MEM; 12648c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0004, dst_reg, src_reg, REG_0, off); 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci /* 12678c2ecf20Sopenharmony_ci * BPF_JMP / CALL 12688c2ecf20Sopenharmony_ci */ 12698c2ecf20Sopenharmony_ci case BPF_JMP | BPF_CALL: 12708c2ecf20Sopenharmony_ci { 12718c2ecf20Sopenharmony_ci u64 func; 12728c2ecf20Sopenharmony_ci bool func_addr_fixed; 12738c2ecf20Sopenharmony_ci int ret; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci ret = bpf_jit_get_func_addr(fp, insn, extra_pass, 12768c2ecf20Sopenharmony_ci &func, &func_addr_fixed); 12778c2ecf20Sopenharmony_ci if (ret < 0) 12788c2ecf20Sopenharmony_ci return -1; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci REG_SET_SEEN(BPF_REG_5); 12818c2ecf20Sopenharmony_ci jit->seen |= SEEN_FUNC; 12828c2ecf20Sopenharmony_ci /* lgrl %w1,func */ 12838c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc4080000, REG_W1, _EMIT_CONST_U64(func)); 12848c2ecf20Sopenharmony_ci if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable) { 12858c2ecf20Sopenharmony_ci /* brasl %r14,__s390_indirect_jump_r1 */ 12868c2ecf20Sopenharmony_ci EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip); 12878c2ecf20Sopenharmony_ci } else { 12888c2ecf20Sopenharmony_ci /* basr %r14,%w1 */ 12898c2ecf20Sopenharmony_ci EMIT2(0x0d00, REG_14, REG_W1); 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci /* lgr %b0,%r2: load return value into %b0 */ 12928c2ecf20Sopenharmony_ci EMIT4(0xb9040000, BPF_REG_0, REG_2); 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci case BPF_JMP | BPF_TAIL_CALL: { 12968c2ecf20Sopenharmony_ci int patch_1_clrj, patch_2_clij, patch_3_brc; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* 12998c2ecf20Sopenharmony_ci * Implicit input: 13008c2ecf20Sopenharmony_ci * B1: pointer to ctx 13018c2ecf20Sopenharmony_ci * B2: pointer to bpf_array 13028c2ecf20Sopenharmony_ci * B3: index in bpf_array 13038c2ecf20Sopenharmony_ci */ 13048c2ecf20Sopenharmony_ci jit->seen |= SEEN_TAIL_CALL; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci /* 13078c2ecf20Sopenharmony_ci * if (index >= array->map.max_entries) 13088c2ecf20Sopenharmony_ci * goto out; 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci /* llgf %w1,map.max_entries(%b2) */ 13128c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2, 13138c2ecf20Sopenharmony_ci offsetof(struct bpf_array, map.max_entries)); 13148c2ecf20Sopenharmony_ci /* if ((u32)%b3 >= (u32)%w1) goto out; */ 13158c2ecf20Sopenharmony_ci /* clrj %b3,%w1,0xa,out */ 13168c2ecf20Sopenharmony_ci patch_1_clrj = jit->prg; 13178c2ecf20Sopenharmony_ci EMIT6_PCREL_RIEB(0xec000000, 0x0077, BPF_REG_3, REG_W1, 0xa, 13188c2ecf20Sopenharmony_ci jit->prg); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* 13218c2ecf20Sopenharmony_ci * if (tail_call_cnt++ > MAX_TAIL_CALL_CNT) 13228c2ecf20Sopenharmony_ci * goto out; 13238c2ecf20Sopenharmony_ci */ 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (jit->seen & SEEN_STACK) 13268c2ecf20Sopenharmony_ci off = STK_OFF_TCCNT + STK_OFF + stack_depth; 13278c2ecf20Sopenharmony_ci else 13288c2ecf20Sopenharmony_ci off = STK_OFF_TCCNT; 13298c2ecf20Sopenharmony_ci /* lhi %w0,1 */ 13308c2ecf20Sopenharmony_ci EMIT4_IMM(0xa7080000, REG_W0, 1); 13318c2ecf20Sopenharmony_ci /* laal %w1,%w0,off(%r15) */ 13328c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off); 13338c2ecf20Sopenharmony_ci /* clij %w1,MAX_TAIL_CALL_CNT,0x2,out */ 13348c2ecf20Sopenharmony_ci patch_2_clij = jit->prg; 13358c2ecf20Sopenharmony_ci EMIT6_PCREL_RIEC(0xec000000, 0x007f, REG_W1, MAX_TAIL_CALL_CNT, 13368c2ecf20Sopenharmony_ci 2, jit->prg); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* 13398c2ecf20Sopenharmony_ci * prog = array->ptrs[index]; 13408c2ecf20Sopenharmony_ci * if (prog == NULL) 13418c2ecf20Sopenharmony_ci * goto out; 13428c2ecf20Sopenharmony_ci */ 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci /* llgfr %r1,%b3: %r1 = (u32) index */ 13458c2ecf20Sopenharmony_ci EMIT4(0xb9160000, REG_1, BPF_REG_3); 13468c2ecf20Sopenharmony_ci /* sllg %r1,%r1,3: %r1 *= 8 */ 13478c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xeb000000, 0x000d, REG_1, REG_1, REG_0, 3); 13488c2ecf20Sopenharmony_ci /* ltg %r1,prog(%b2,%r1) */ 13498c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0002, REG_1, BPF_REG_2, 13508c2ecf20Sopenharmony_ci REG_1, offsetof(struct bpf_array, ptrs)); 13518c2ecf20Sopenharmony_ci /* brc 0x8,out */ 13528c2ecf20Sopenharmony_ci patch_3_brc = jit->prg; 13538c2ecf20Sopenharmony_ci EMIT4_PCREL_RIC(0xa7040000, 8, jit->prg); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* 13568c2ecf20Sopenharmony_ci * Restore registers before calling function 13578c2ecf20Sopenharmony_ci */ 13588c2ecf20Sopenharmony_ci save_restore_regs(jit, REGS_RESTORE, stack_depth); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci /* 13618c2ecf20Sopenharmony_ci * goto *(prog->bpf_func + tail_call_start); 13628c2ecf20Sopenharmony_ci */ 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* lg %r1,bpf_func(%r1) */ 13658c2ecf20Sopenharmony_ci EMIT6_DISP_LH(0xe3000000, 0x0004, REG_1, REG_1, REG_0, 13668c2ecf20Sopenharmony_ci offsetof(struct bpf_prog, bpf_func)); 13678c2ecf20Sopenharmony_ci /* bc 0xf,tail_call_start(%r1) */ 13688c2ecf20Sopenharmony_ci _EMIT4(0x47f01000 + jit->tail_call_start); 13698c2ecf20Sopenharmony_ci /* out: */ 13708c2ecf20Sopenharmony_ci if (jit->prg_buf) { 13718c2ecf20Sopenharmony_ci *(u16 *)(jit->prg_buf + patch_1_clrj + 2) = 13728c2ecf20Sopenharmony_ci (jit->prg - patch_1_clrj) >> 1; 13738c2ecf20Sopenharmony_ci *(u16 *)(jit->prg_buf + patch_2_clij + 2) = 13748c2ecf20Sopenharmony_ci (jit->prg - patch_2_clij) >> 1; 13758c2ecf20Sopenharmony_ci *(u16 *)(jit->prg_buf + patch_3_brc + 2) = 13768c2ecf20Sopenharmony_ci (jit->prg - patch_3_brc) >> 1; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci break; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci case BPF_JMP | BPF_EXIT: /* return b0 */ 13818c2ecf20Sopenharmony_ci last = (i == fp->len - 1) ? 1 : 0; 13828c2ecf20Sopenharmony_ci if (last) 13838c2ecf20Sopenharmony_ci break; 13848c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && can_use_rel(jit, jit->exit_ip)) 13858c2ecf20Sopenharmony_ci /* brc 0xf, <exit> */ 13868c2ecf20Sopenharmony_ci EMIT4_PCREL_RIC(0xa7040000, 0xf, jit->exit_ip); 13878c2ecf20Sopenharmony_ci else 13888c2ecf20Sopenharmony_ci /* brcl 0xf, <exit> */ 13898c2ecf20Sopenharmony_ci EMIT6_PCREL_RILC(0xc0040000, 0xf, jit->exit_ip); 13908c2ecf20Sopenharmony_ci break; 13918c2ecf20Sopenharmony_ci /* 13928c2ecf20Sopenharmony_ci * Branch relative (number of skipped instructions) to offset on 13938c2ecf20Sopenharmony_ci * condition. 13948c2ecf20Sopenharmony_ci * 13958c2ecf20Sopenharmony_ci * Condition code to mask mapping: 13968c2ecf20Sopenharmony_ci * 13978c2ecf20Sopenharmony_ci * CC | Description | Mask 13988c2ecf20Sopenharmony_ci * ------------------------------ 13998c2ecf20Sopenharmony_ci * 0 | Operands equal | 8 14008c2ecf20Sopenharmony_ci * 1 | First operand low | 4 14018c2ecf20Sopenharmony_ci * 2 | First operand high | 2 14028c2ecf20Sopenharmony_ci * 3 | Unused | 1 14038c2ecf20Sopenharmony_ci * 14048c2ecf20Sopenharmony_ci * For s390x relative branches: ip = ip + off_bytes 14058c2ecf20Sopenharmony_ci * For BPF relative branches: insn = insn + off_insns + 1 14068c2ecf20Sopenharmony_ci * 14078c2ecf20Sopenharmony_ci * For example for s390x with offset 0 we jump to the branch 14088c2ecf20Sopenharmony_ci * instruction itself (loop) and for BPF with offset 0 we 14098c2ecf20Sopenharmony_ci * branch to the instruction behind the branch. 14108c2ecf20Sopenharmony_ci */ 14118c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JA: /* if (true) */ 14128c2ecf20Sopenharmony_ci mask = 0xf000; /* j */ 14138c2ecf20Sopenharmony_ci goto branch_oc; 14148c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_K: /* ((s64) dst > (s64) imm) */ 14158c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_K: /* ((s32) dst > (s32) imm) */ 14168c2ecf20Sopenharmony_ci mask = 0x2000; /* jh */ 14178c2ecf20Sopenharmony_ci goto branch_ks; 14188c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_K: /* ((s64) dst < (s64) imm) */ 14198c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_K: /* ((s32) dst < (s32) imm) */ 14208c2ecf20Sopenharmony_ci mask = 0x4000; /* jl */ 14218c2ecf20Sopenharmony_ci goto branch_ks; 14228c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_K: /* ((s64) dst >= (s64) imm) */ 14238c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_K: /* ((s32) dst >= (s32) imm) */ 14248c2ecf20Sopenharmony_ci mask = 0xa000; /* jhe */ 14258c2ecf20Sopenharmony_ci goto branch_ks; 14268c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_K: /* ((s64) dst <= (s64) imm) */ 14278c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_K: /* ((s32) dst <= (s32) imm) */ 14288c2ecf20Sopenharmony_ci mask = 0xc000; /* jle */ 14298c2ecf20Sopenharmony_ci goto branch_ks; 14308c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_K: /* (dst_reg > imm) */ 14318c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_K: /* ((u32) dst_reg > (u32) imm) */ 14328c2ecf20Sopenharmony_ci mask = 0x2000; /* jh */ 14338c2ecf20Sopenharmony_ci goto branch_ku; 14348c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_K: /* (dst_reg < imm) */ 14358c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_K: /* ((u32) dst_reg < (u32) imm) */ 14368c2ecf20Sopenharmony_ci mask = 0x4000; /* jl */ 14378c2ecf20Sopenharmony_ci goto branch_ku; 14388c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_K: /* (dst_reg >= imm) */ 14398c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_K: /* ((u32) dst_reg >= (u32) imm) */ 14408c2ecf20Sopenharmony_ci mask = 0xa000; /* jhe */ 14418c2ecf20Sopenharmony_ci goto branch_ku; 14428c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_K: /* (dst_reg <= imm) */ 14438c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_K: /* ((u32) dst_reg <= (u32) imm) */ 14448c2ecf20Sopenharmony_ci mask = 0xc000; /* jle */ 14458c2ecf20Sopenharmony_ci goto branch_ku; 14468c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_K: /* (dst_reg != imm) */ 14478c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_K: /* ((u32) dst_reg != (u32) imm) */ 14488c2ecf20Sopenharmony_ci mask = 0x7000; /* jne */ 14498c2ecf20Sopenharmony_ci goto branch_ku; 14508c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_K: /* (dst_reg == imm) */ 14518c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_K: /* ((u32) dst_reg == (u32) imm) */ 14528c2ecf20Sopenharmony_ci mask = 0x8000; /* je */ 14538c2ecf20Sopenharmony_ci goto branch_ku; 14548c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_K: /* (dst_reg & imm) */ 14558c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_K: /* ((u32) dst_reg & (u32) imm) */ 14568c2ecf20Sopenharmony_ci mask = 0x7000; /* jnz */ 14578c2ecf20Sopenharmony_ci if (BPF_CLASS(insn->code) == BPF_JMP32) { 14588c2ecf20Sopenharmony_ci /* llilf %w1,imm (load zero extend imm) */ 14598c2ecf20Sopenharmony_ci EMIT6_IMM(0xc00f0000, REG_W1, imm); 14608c2ecf20Sopenharmony_ci /* nr %w1,%dst */ 14618c2ecf20Sopenharmony_ci EMIT2(0x1400, REG_W1, dst_reg); 14628c2ecf20Sopenharmony_ci } else { 14638c2ecf20Sopenharmony_ci /* lgfi %w1,imm (load sign extend imm) */ 14648c2ecf20Sopenharmony_ci EMIT6_IMM(0xc0010000, REG_W1, imm); 14658c2ecf20Sopenharmony_ci /* ngr %w1,%dst */ 14668c2ecf20Sopenharmony_ci EMIT4(0xb9800000, REG_W1, dst_reg); 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci goto branch_oc; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_X: /* ((s64) dst > (s64) src) */ 14718c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_X: /* ((s32) dst > (s32) src) */ 14728c2ecf20Sopenharmony_ci mask = 0x2000; /* jh */ 14738c2ecf20Sopenharmony_ci goto branch_xs; 14748c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_X: /* ((s64) dst < (s64) src) */ 14758c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_X: /* ((s32) dst < (s32) src) */ 14768c2ecf20Sopenharmony_ci mask = 0x4000; /* jl */ 14778c2ecf20Sopenharmony_ci goto branch_xs; 14788c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_X: /* ((s64) dst >= (s64) src) */ 14798c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_X: /* ((s32) dst >= (s32) src) */ 14808c2ecf20Sopenharmony_ci mask = 0xa000; /* jhe */ 14818c2ecf20Sopenharmony_ci goto branch_xs; 14828c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_X: /* ((s64) dst <= (s64) src) */ 14838c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_X: /* ((s32) dst <= (s32) src) */ 14848c2ecf20Sopenharmony_ci mask = 0xc000; /* jle */ 14858c2ecf20Sopenharmony_ci goto branch_xs; 14868c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_X: /* (dst > src) */ 14878c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_X: /* ((u32) dst > (u32) src) */ 14888c2ecf20Sopenharmony_ci mask = 0x2000; /* jh */ 14898c2ecf20Sopenharmony_ci goto branch_xu; 14908c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_X: /* (dst < src) */ 14918c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_X: /* ((u32) dst < (u32) src) */ 14928c2ecf20Sopenharmony_ci mask = 0x4000; /* jl */ 14938c2ecf20Sopenharmony_ci goto branch_xu; 14948c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_X: /* (dst >= src) */ 14958c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_X: /* ((u32) dst >= (u32) src) */ 14968c2ecf20Sopenharmony_ci mask = 0xa000; /* jhe */ 14978c2ecf20Sopenharmony_ci goto branch_xu; 14988c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_X: /* (dst <= src) */ 14998c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_X: /* ((u32) dst <= (u32) src) */ 15008c2ecf20Sopenharmony_ci mask = 0xc000; /* jle */ 15018c2ecf20Sopenharmony_ci goto branch_xu; 15028c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_X: /* (dst != src) */ 15038c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_X: /* ((u32) dst != (u32) src) */ 15048c2ecf20Sopenharmony_ci mask = 0x7000; /* jne */ 15058c2ecf20Sopenharmony_ci goto branch_xu; 15068c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_X: /* (dst == src) */ 15078c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_X: /* ((u32) dst == (u32) src) */ 15088c2ecf20Sopenharmony_ci mask = 0x8000; /* je */ 15098c2ecf20Sopenharmony_ci goto branch_xu; 15108c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_X: /* (dst & src) */ 15118c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_X: /* ((u32) dst & (u32) src) */ 15128c2ecf20Sopenharmony_ci { 15138c2ecf20Sopenharmony_ci bool is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci mask = 0x7000; /* jnz */ 15168c2ecf20Sopenharmony_ci /* nrk or ngrk %w1,%dst,%src */ 15178c2ecf20Sopenharmony_ci EMIT4_RRF((is_jmp32 ? 0xb9f40000 : 0xb9e40000), 15188c2ecf20Sopenharmony_ci REG_W1, dst_reg, src_reg); 15198c2ecf20Sopenharmony_ci goto branch_oc; 15208c2ecf20Sopenharmony_cibranch_ks: 15218c2ecf20Sopenharmony_ci is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; 15228c2ecf20Sopenharmony_ci /* cfi or cgfi %dst,imm */ 15238c2ecf20Sopenharmony_ci EMIT6_IMM(is_jmp32 ? 0xc20d0000 : 0xc20c0000, 15248c2ecf20Sopenharmony_ci dst_reg, imm); 15258c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && 15268c2ecf20Sopenharmony_ci can_use_rel(jit, addrs[i + off + 1])) { 15278c2ecf20Sopenharmony_ci /* brc mask,off */ 15288c2ecf20Sopenharmony_ci EMIT4_PCREL_RIC(0xa7040000, 15298c2ecf20Sopenharmony_ci mask >> 12, addrs[i + off + 1]); 15308c2ecf20Sopenharmony_ci } else { 15318c2ecf20Sopenharmony_ci /* brcl mask,off */ 15328c2ecf20Sopenharmony_ci EMIT6_PCREL_RILC(0xc0040000, 15338c2ecf20Sopenharmony_ci mask >> 12, addrs[i + off + 1]); 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci break; 15368c2ecf20Sopenharmony_cibranch_ku: 15378c2ecf20Sopenharmony_ci /* lgfi %w1,imm (load sign extend imm) */ 15388c2ecf20Sopenharmony_ci src_reg = REG_1; 15398c2ecf20Sopenharmony_ci EMIT6_IMM(0xc0010000, src_reg, imm); 15408c2ecf20Sopenharmony_ci goto branch_xu; 15418c2ecf20Sopenharmony_cibranch_xs: 15428c2ecf20Sopenharmony_ci is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; 15438c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && 15448c2ecf20Sopenharmony_ci can_use_rel(jit, addrs[i + off + 1])) { 15458c2ecf20Sopenharmony_ci /* crj or cgrj %dst,%src,mask,off */ 15468c2ecf20Sopenharmony_ci EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0076 : 0x0064), 15478c2ecf20Sopenharmony_ci dst_reg, src_reg, i, off, mask); 15488c2ecf20Sopenharmony_ci } else { 15498c2ecf20Sopenharmony_ci /* cr or cgr %dst,%src */ 15508c2ecf20Sopenharmony_ci if (is_jmp32) 15518c2ecf20Sopenharmony_ci EMIT2(0x1900, dst_reg, src_reg); 15528c2ecf20Sopenharmony_ci else 15538c2ecf20Sopenharmony_ci EMIT4(0xb9200000, dst_reg, src_reg); 15548c2ecf20Sopenharmony_ci /* brcl mask,off */ 15558c2ecf20Sopenharmony_ci EMIT6_PCREL_RILC(0xc0040000, 15568c2ecf20Sopenharmony_ci mask >> 12, addrs[i + off + 1]); 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci break; 15598c2ecf20Sopenharmony_cibranch_xu: 15608c2ecf20Sopenharmony_ci is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; 15618c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && 15628c2ecf20Sopenharmony_ci can_use_rel(jit, addrs[i + off + 1])) { 15638c2ecf20Sopenharmony_ci /* clrj or clgrj %dst,%src,mask,off */ 15648c2ecf20Sopenharmony_ci EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0077 : 0x0065), 15658c2ecf20Sopenharmony_ci dst_reg, src_reg, i, off, mask); 15668c2ecf20Sopenharmony_ci } else { 15678c2ecf20Sopenharmony_ci /* clr or clgr %dst,%src */ 15688c2ecf20Sopenharmony_ci if (is_jmp32) 15698c2ecf20Sopenharmony_ci EMIT2(0x1500, dst_reg, src_reg); 15708c2ecf20Sopenharmony_ci else 15718c2ecf20Sopenharmony_ci EMIT4(0xb9210000, dst_reg, src_reg); 15728c2ecf20Sopenharmony_ci /* brcl mask,off */ 15738c2ecf20Sopenharmony_ci EMIT6_PCREL_RILC(0xc0040000, 15748c2ecf20Sopenharmony_ci mask >> 12, addrs[i + off + 1]); 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_cibranch_oc: 15788c2ecf20Sopenharmony_ci if (!is_first_pass(jit) && 15798c2ecf20Sopenharmony_ci can_use_rel(jit, addrs[i + off + 1])) { 15808c2ecf20Sopenharmony_ci /* brc mask,off */ 15818c2ecf20Sopenharmony_ci EMIT4_PCREL_RIC(0xa7040000, 15828c2ecf20Sopenharmony_ci mask >> 12, addrs[i + off + 1]); 15838c2ecf20Sopenharmony_ci } else { 15848c2ecf20Sopenharmony_ci /* brcl mask,off */ 15858c2ecf20Sopenharmony_ci EMIT6_PCREL_RILC(0xc0040000, 15868c2ecf20Sopenharmony_ci mask >> 12, addrs[i + off + 1]); 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci break; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci default: /* too complex, give up */ 15918c2ecf20Sopenharmony_ci pr_err("Unknown opcode %02x\n", insn->code); 15928c2ecf20Sopenharmony_ci return -1; 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci if (probe_prg != -1) { 15968c2ecf20Sopenharmony_ci /* 15978c2ecf20Sopenharmony_ci * Handlers of certain exceptions leave psw.addr pointing to 15988c2ecf20Sopenharmony_ci * the instruction directly after the failing one. Therefore, 15998c2ecf20Sopenharmony_ci * create two exception table entries and also add a nop in 16008c2ecf20Sopenharmony_ci * case two probing instructions come directly after each 16018c2ecf20Sopenharmony_ci * other. 16028c2ecf20Sopenharmony_ci */ 16038c2ecf20Sopenharmony_ci nop_prg = jit->prg; 16048c2ecf20Sopenharmony_ci /* bcr 0,%0 */ 16058c2ecf20Sopenharmony_ci _EMIT2(0x0700); 16068c2ecf20Sopenharmony_ci err = bpf_jit_probe_mem(jit, fp, probe_prg, nop_prg); 16078c2ecf20Sopenharmony_ci if (err < 0) 16088c2ecf20Sopenharmony_ci return err; 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci return insn_count; 16128c2ecf20Sopenharmony_ci} 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci/* 16158c2ecf20Sopenharmony_ci * Return whether new i-th instruction address does not violate any invariant 16168c2ecf20Sopenharmony_ci */ 16178c2ecf20Sopenharmony_cistatic bool bpf_is_new_addr_sane(struct bpf_jit *jit, int i) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci /* On the first pass anything goes */ 16208c2ecf20Sopenharmony_ci if (is_first_pass(jit)) 16218c2ecf20Sopenharmony_ci return true; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci /* The codegen pass must not change anything */ 16248c2ecf20Sopenharmony_ci if (is_codegen_pass(jit)) 16258c2ecf20Sopenharmony_ci return jit->addrs[i] == jit->prg; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* Passes in between must not increase code size */ 16288c2ecf20Sopenharmony_ci return jit->addrs[i] >= jit->prg; 16298c2ecf20Sopenharmony_ci} 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci/* 16328c2ecf20Sopenharmony_ci * Update the address of i-th instruction 16338c2ecf20Sopenharmony_ci */ 16348c2ecf20Sopenharmony_cistatic int bpf_set_addr(struct bpf_jit *jit, int i) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci int delta; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (is_codegen_pass(jit)) { 16398c2ecf20Sopenharmony_ci delta = jit->prg - jit->addrs[i]; 16408c2ecf20Sopenharmony_ci if (delta < 0) 16418c2ecf20Sopenharmony_ci bpf_skip(jit, -delta); 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!bpf_is_new_addr_sane(jit, i))) 16448c2ecf20Sopenharmony_ci return -1; 16458c2ecf20Sopenharmony_ci jit->addrs[i] = jit->prg; 16468c2ecf20Sopenharmony_ci return 0; 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci/* 16508c2ecf20Sopenharmony_ci * Compile eBPF program into s390x code 16518c2ecf20Sopenharmony_ci */ 16528c2ecf20Sopenharmony_cistatic int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp, 16538c2ecf20Sopenharmony_ci bool extra_pass, u32 stack_depth) 16548c2ecf20Sopenharmony_ci{ 16558c2ecf20Sopenharmony_ci int i, insn_count, lit32_size, lit64_size; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci jit->lit32 = jit->lit32_start; 16588c2ecf20Sopenharmony_ci jit->lit64 = jit->lit64_start; 16598c2ecf20Sopenharmony_ci jit->prg = 0; 16608c2ecf20Sopenharmony_ci jit->excnt = 0; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci bpf_jit_prologue(jit, stack_depth); 16638c2ecf20Sopenharmony_ci if (bpf_set_addr(jit, 0) < 0) 16648c2ecf20Sopenharmony_ci return -1; 16658c2ecf20Sopenharmony_ci for (i = 0; i < fp->len; i += insn_count) { 16668c2ecf20Sopenharmony_ci insn_count = bpf_jit_insn(jit, fp, i, extra_pass, stack_depth); 16678c2ecf20Sopenharmony_ci if (insn_count < 0) 16688c2ecf20Sopenharmony_ci return -1; 16698c2ecf20Sopenharmony_ci /* Next instruction address */ 16708c2ecf20Sopenharmony_ci if (bpf_set_addr(jit, i + insn_count) < 0) 16718c2ecf20Sopenharmony_ci return -1; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci bpf_jit_epilogue(jit, stack_depth); 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci lit32_size = jit->lit32 - jit->lit32_start; 16768c2ecf20Sopenharmony_ci lit64_size = jit->lit64 - jit->lit64_start; 16778c2ecf20Sopenharmony_ci jit->lit32_start = jit->prg; 16788c2ecf20Sopenharmony_ci if (lit32_size) 16798c2ecf20Sopenharmony_ci jit->lit32_start = ALIGN(jit->lit32_start, 4); 16808c2ecf20Sopenharmony_ci jit->lit64_start = jit->lit32_start + lit32_size; 16818c2ecf20Sopenharmony_ci if (lit64_size) 16828c2ecf20Sopenharmony_ci jit->lit64_start = ALIGN(jit->lit64_start, 8); 16838c2ecf20Sopenharmony_ci jit->size = jit->lit64_start + lit64_size; 16848c2ecf20Sopenharmony_ci jit->size_prg = jit->prg; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(fp->aux->extable && 16878c2ecf20Sopenharmony_ci jit->excnt != fp->aux->num_exentries)) 16888c2ecf20Sopenharmony_ci /* Verifier bug - too many entries. */ 16898c2ecf20Sopenharmony_ci return -1; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci return 0; 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_cibool bpf_jit_needs_zext(void) 16958c2ecf20Sopenharmony_ci{ 16968c2ecf20Sopenharmony_ci return true; 16978c2ecf20Sopenharmony_ci} 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_cistruct s390_jit_data { 17008c2ecf20Sopenharmony_ci struct bpf_binary_header *header; 17018c2ecf20Sopenharmony_ci struct bpf_jit ctx; 17028c2ecf20Sopenharmony_ci int pass; 17038c2ecf20Sopenharmony_ci}; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic struct bpf_binary_header *bpf_jit_alloc(struct bpf_jit *jit, 17068c2ecf20Sopenharmony_ci struct bpf_prog *fp) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci struct bpf_binary_header *header; 17098c2ecf20Sopenharmony_ci u32 extable_size; 17108c2ecf20Sopenharmony_ci u32 code_size; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci /* We need two entries per insn. */ 17138c2ecf20Sopenharmony_ci fp->aux->num_exentries *= 2; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci code_size = roundup(jit->size, 17168c2ecf20Sopenharmony_ci __alignof__(struct exception_table_entry)); 17178c2ecf20Sopenharmony_ci extable_size = fp->aux->num_exentries * 17188c2ecf20Sopenharmony_ci sizeof(struct exception_table_entry); 17198c2ecf20Sopenharmony_ci header = bpf_jit_binary_alloc(code_size + extable_size, &jit->prg_buf, 17208c2ecf20Sopenharmony_ci 8, jit_fill_hole); 17218c2ecf20Sopenharmony_ci if (!header) 17228c2ecf20Sopenharmony_ci return NULL; 17238c2ecf20Sopenharmony_ci fp->aux->extable = (struct exception_table_entry *) 17248c2ecf20Sopenharmony_ci (jit->prg_buf + code_size); 17258c2ecf20Sopenharmony_ci return header; 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci/* 17298c2ecf20Sopenharmony_ci * Compile eBPF program "fp" 17308c2ecf20Sopenharmony_ci */ 17318c2ecf20Sopenharmony_cistruct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) 17328c2ecf20Sopenharmony_ci{ 17338c2ecf20Sopenharmony_ci u32 stack_depth = round_up(fp->aux->stack_depth, 8); 17348c2ecf20Sopenharmony_ci struct bpf_prog *tmp, *orig_fp = fp; 17358c2ecf20Sopenharmony_ci struct bpf_binary_header *header; 17368c2ecf20Sopenharmony_ci struct s390_jit_data *jit_data; 17378c2ecf20Sopenharmony_ci bool tmp_blinded = false; 17388c2ecf20Sopenharmony_ci bool extra_pass = false; 17398c2ecf20Sopenharmony_ci struct bpf_jit jit; 17408c2ecf20Sopenharmony_ci int pass; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci if (!fp->jit_requested) 17438c2ecf20Sopenharmony_ci return orig_fp; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci tmp = bpf_jit_blind_constants(fp); 17468c2ecf20Sopenharmony_ci /* 17478c2ecf20Sopenharmony_ci * If blinding was requested and we failed during blinding, 17488c2ecf20Sopenharmony_ci * we must fall back to the interpreter. 17498c2ecf20Sopenharmony_ci */ 17508c2ecf20Sopenharmony_ci if (IS_ERR(tmp)) 17518c2ecf20Sopenharmony_ci return orig_fp; 17528c2ecf20Sopenharmony_ci if (tmp != fp) { 17538c2ecf20Sopenharmony_ci tmp_blinded = true; 17548c2ecf20Sopenharmony_ci fp = tmp; 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci jit_data = fp->aux->jit_data; 17588c2ecf20Sopenharmony_ci if (!jit_data) { 17598c2ecf20Sopenharmony_ci jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL); 17608c2ecf20Sopenharmony_ci if (!jit_data) { 17618c2ecf20Sopenharmony_ci fp = orig_fp; 17628c2ecf20Sopenharmony_ci goto out; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci fp->aux->jit_data = jit_data; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci if (jit_data->ctx.addrs) { 17678c2ecf20Sopenharmony_ci jit = jit_data->ctx; 17688c2ecf20Sopenharmony_ci header = jit_data->header; 17698c2ecf20Sopenharmony_ci extra_pass = true; 17708c2ecf20Sopenharmony_ci pass = jit_data->pass + 1; 17718c2ecf20Sopenharmony_ci goto skip_init_ctx; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci memset(&jit, 0, sizeof(jit)); 17758c2ecf20Sopenharmony_ci jit.addrs = kvcalloc(fp->len + 1, sizeof(*jit.addrs), GFP_KERNEL); 17768c2ecf20Sopenharmony_ci if (jit.addrs == NULL) { 17778c2ecf20Sopenharmony_ci fp = orig_fp; 17788c2ecf20Sopenharmony_ci goto free_addrs; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci /* 17818c2ecf20Sopenharmony_ci * Three initial passes: 17828c2ecf20Sopenharmony_ci * - 1/2: Determine clobbered registers 17838c2ecf20Sopenharmony_ci * - 3: Calculate program size and addrs arrray 17848c2ecf20Sopenharmony_ci */ 17858c2ecf20Sopenharmony_ci for (pass = 1; pass <= 3; pass++) { 17868c2ecf20Sopenharmony_ci if (bpf_jit_prog(&jit, fp, extra_pass, stack_depth)) { 17878c2ecf20Sopenharmony_ci fp = orig_fp; 17888c2ecf20Sopenharmony_ci goto free_addrs; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci /* 17928c2ecf20Sopenharmony_ci * Final pass: Allocate and generate program 17938c2ecf20Sopenharmony_ci */ 17948c2ecf20Sopenharmony_ci header = bpf_jit_alloc(&jit, fp); 17958c2ecf20Sopenharmony_ci if (!header) { 17968c2ecf20Sopenharmony_ci fp = orig_fp; 17978c2ecf20Sopenharmony_ci goto free_addrs; 17988c2ecf20Sopenharmony_ci } 17998c2ecf20Sopenharmony_ciskip_init_ctx: 18008c2ecf20Sopenharmony_ci if (bpf_jit_prog(&jit, fp, extra_pass, stack_depth)) { 18018c2ecf20Sopenharmony_ci bpf_jit_binary_free(header); 18028c2ecf20Sopenharmony_ci fp = orig_fp; 18038c2ecf20Sopenharmony_ci goto free_addrs; 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci if (bpf_jit_enable > 1) { 18068c2ecf20Sopenharmony_ci bpf_jit_dump(fp->len, jit.size, pass, jit.prg_buf); 18078c2ecf20Sopenharmony_ci print_fn_code(jit.prg_buf, jit.size_prg); 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci if (!fp->is_func || extra_pass) { 18108c2ecf20Sopenharmony_ci bpf_jit_binary_lock_ro(header); 18118c2ecf20Sopenharmony_ci } else { 18128c2ecf20Sopenharmony_ci jit_data->header = header; 18138c2ecf20Sopenharmony_ci jit_data->ctx = jit; 18148c2ecf20Sopenharmony_ci jit_data->pass = pass; 18158c2ecf20Sopenharmony_ci } 18168c2ecf20Sopenharmony_ci fp->bpf_func = (void *) jit.prg_buf; 18178c2ecf20Sopenharmony_ci fp->jited = 1; 18188c2ecf20Sopenharmony_ci fp->jited_len = jit.size; 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci if (!fp->is_func || extra_pass) { 18218c2ecf20Sopenharmony_ci bpf_prog_fill_jited_linfo(fp, jit.addrs + 1); 18228c2ecf20Sopenharmony_cifree_addrs: 18238c2ecf20Sopenharmony_ci kvfree(jit.addrs); 18248c2ecf20Sopenharmony_ci kfree(jit_data); 18258c2ecf20Sopenharmony_ci fp->aux->jit_data = NULL; 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ciout: 18288c2ecf20Sopenharmony_ci if (tmp_blinded) 18298c2ecf20Sopenharmony_ci bpf_jit_prog_release_other(fp, fp == orig_fp ? 18308c2ecf20Sopenharmony_ci tmp : orig_fp); 18318c2ecf20Sopenharmony_ci return fp; 18328c2ecf20Sopenharmony_ci} 1833