// SPDX-License-Identifier: GPL-2.0
/*
* BPF JIT compiler for PA-RISC (64-bit)
*
* Copyright(c) 2023 Helge Deller <deller@gmx.de>
*
* The code is based on the BPF JIT compiler for RV64 by Björn Töpel.
*
* TODO:
* - check if bpf_jit_needs_zext() is needed (currently enabled)
* - implement arch_prepare_bpf_trampoline(), poke(), ...
*/
#include <linux/bitfield.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/libgcc.h>
#include "bpf_jit.h"
static const int regmap[] = {
[BPF_REG_0] = HPPA_REG_RET0,
[BPF_REG_1] = HPPA_R(5),
[BPF_REG_2] = HPPA_R(6),
[BPF_REG_3] = HPPA_R(7),
[BPF_REG_4] = HPPA_R(8),
[BPF_REG_5] = HPPA_R(9),
[BPF_REG_6] = HPPA_R(10),
[BPF_REG_7] = HPPA_R(11),
[BPF_REG_8] = HPPA_R(12),
[BPF_REG_9] = HPPA_R(13),
[BPF_REG_FP] = HPPA_R(14),
[BPF_REG_AX] = HPPA_R(15),
};
/*
* Stack layout during BPF program execution (note: stack grows up):
*
* high
* HPPA64 sp => +----------+ <= HPPA64 fp
* | saved sp |
* | saved rp |
* | ... | HPPA64 callee-saved registers
* | curr args|
* | local var|
* +----------+ <= (BPF FP)
* | |
* | ... | BPF program stack
* | |
* | ... | Function call stack
* | |
* +----------+
* low
*/
/* Offset from fp for BPF registers stored on stack. */
#define STACK_ALIGN FRAME_SIZE
#define EXIT_PTR_LOAD(reg) hppa64_ldd_im16(-FRAME_SIZE, HPPA_REG_SP, reg)
#define EXIT_PTR_STORE(reg) hppa64_std_im16(reg, -FRAME_SIZE, HPPA_REG_SP)
#define EXIT_PTR_JUMP(reg, nop) hppa_bv(HPPA_REG_ZERO, reg, nop)
static u8 bpf_to_hppa_reg(int bpf_reg, struct hppa_jit_context *ctx)
{
u8 reg = regmap[bpf_reg];
REG_SET_SEEN(ctx, reg);
return reg;
};
static void emit_hppa_copy(const s8 rs, const s8 rd, struct hppa_jit_context *ctx)
{
REG_SET_SEEN(ctx, rd);
if (OPTIMIZE_HPPA && (rs == rd))
return;
REG_SET_SEEN(ctx, rs);
emit(hppa_copy(rs, rd), ctx);
}
static void emit_hppa64_depd(u8 src, u8 pos, u8 len, u8 target, bool no_zero, struct hppa_jit_context *ctx)
{
int c;
pos &= (BITS_PER_LONG - 1);
pos = 63 - pos;
len = 64 - len;
c = (len < 32) ? 0x4 : 0;
c |= (pos >= 32) ? 0x2 : 0;
c |= (no_zero) ? 0x1 : 0;
emit(hppa_t10_insn(0x3c, target, src, 0, c, pos & 0x1f, len & 0x1f), ctx);
}
static void emit_hppa64_shld(u8 src, int num, u8 target, struct hppa_jit_context *ctx)
{
emit_hppa64_depd(src, 63-num, 64-num, target, 0, ctx);
}
static void emit_hppa64_extrd(u8 src, u8 pos, u8 len, u8 target, bool signed_op, struct hppa_jit_context *ctx)
{
int c;
pos &= (BITS_PER_LONG - 1);
len = 64 - len;
c = (len < 32) ? 0x4 : 0;
c |= (pos >= 32) ? 0x2 : 0;
c |= signed_op ? 0x1 : 0;
emit(hppa_t10_insn(0x36, src, target, 0, c, pos & 0x1f, len & 0x1f), ctx);
}
static void emit_hppa64_extrw(u8 src, u8 pos, u8 len, u8 target, bool signed_op, struct hppa_jit_context *ctx)
{
int c;
pos &= (32 - 1);
len = 32 - len;
c = 0x06