// SPDX-License-Identifier: GPL-2.0-only
/*
* BPF JIT compiler for LoongArch
*
* Copyright (C) 2022 Loongson Technology Corporation Limited
*/
#include "bpf_jit.h"
#define REG_TCC LOONGARCH_GPR_A6
#define TCC_SAVED LOONGARCH_GPR_S5
#define SAVE_RA BIT(0)
#define SAVE_TCC BIT(1)
static const int regmap[] = {
/* return value from in-kernel function, and exit value for eBPF program */
[BPF_REG_0] = LOONGARCH_GPR_A5,
/* arguments from eBPF program to in-kernel function */
[BPF_REG_1] = LOONGARCH_GPR_A0,
[BPF_REG_2] = LOONGARCH_GPR_A1,
[BPF_REG_3] = LOONGARCH_GPR_A2,
[BPF_REG_4] = LOONGARCH_GPR_A3,
[BPF_REG_5] = LOONGARCH_GPR_A4,
/* callee saved registers that in-kernel function will preserve */
[BPF_REG_6] = LOONGARCH_GPR_S0,
[BPF_REG_7] = LOONGARCH_GPR_S1,
[BPF_REG_8] = LOONGARCH_GPR_S2,
[BPF_REG_9] = LOONGARCH_GPR_S3,
/* read-only frame pointer to access stack */
[BPF_REG_FP] = LOONGARCH_GPR_S4,
/* temporary register for blinding constants */
[BPF_REG_AX] = LOONGARCH_GPR_T0,
};
static void mark_call(struct jit_ctx *ctx)
{
ctx->flags |= SAVE_RA;
}
static void mark_tail_call(struct jit_ctx *ctx)
{
ctx->flags |= SAVE_TCC;
}
static bool seen_call(struct jit_ctx *ctx)
{
return (ctx->flags & SAVE_RA);
}
static bool seen_tail_call(struct jit_ctx *ctx)
{
return (ctx->flags & SAVE_TCC);
}
static u8 tail_call_reg(struct jit_ctx *ctx)
{
if (seen_call(ctx))
return TCC_SAVED;
return REG_TCC;
}
/*
* eBPF prog stack layout:
*
* high
* original $sp ------------> +-------------------------+ <--LOONGARCH_GPR_FP
* | $ra |
* +-------------------------+
* | $fp |
* +-------------------------+
* | $s0 |
* +-------------------------+
* | $s1 |
* +-------------------------+
* | $s2 |
* +-------------------------+
* | $s3 |
* +-------------------------+
* | $s4 |
* +-------------------------+
* | $s5 |
* +-------------------------+ <--BPF_REG_FP
* | prog->aux->stack_depth |
* | (optional) |
* current $sp -------------> +-------------------------+
* low
*/
static void build_prologue(struct jit_ctx *ctx)
{
int stack_adjust = 0, store_offset, bpf_stack_adjust;
bpf_stack_adjust = round_up(ctx->prog->aux->stack_depth, 16);
/* To store ra, fp, s0, s1, s2, s3, s4 and s5. */
stack_adjust += sizeof(long) * 8;
stack_adjust = round_up(stack_adjust, 16);
stack_adjust += bpf_stack_adjust;
/*
* First instruction initializes the tail call count (TCC).
* On tail call we skip this instruction, and the TCC is
* passed in REG_TCC from the caller.
*/
emit_insn(ctx, addid, REG_TCC