dbcd7f5faf
Inspired by commit 800834285361("bpf, arm64: Add BPF exception tables"), do similar to LoongArch to add BPF exception tables. When a tracing BPF program attempts to read memory without using the bpf_probe_read() helper, the verifier marks the load instruction with the BPF_PROBE_MEM flag. Since the LoongArch JIT does not currently recognize this flag it falls back to the interpreter. Add support for BPF_PROBE_MEM, by appending an exception table to the BPF program. If the load instruction causes a data abort, the fixup infrastructure finds the exception table and fixes up the fault, by clearing the destination register and jumping over the faulting instruction. To keep the compact exception table entry format, inspect the pc in fixup_exception(). A more generic solution would add a "handler" field to the table entry, like on x86, s390 and arm64, etc. Signed-off-by: Youling Tang <tangyouling@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
48 lines
1.3 KiB
C
48 lines
1.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _ASM_LOONGARCH_EXTABLE_H
|
|
#define _ASM_LOONGARCH_EXTABLE_H
|
|
|
|
/*
|
|
* The exception table consists of pairs of relative offsets: the first
|
|
* is the relative offset to an instruction that is allowed to fault,
|
|
* and the second is the relative offset at which the program should
|
|
* continue. No registers are modified, so it is entirely up to the
|
|
* continuation code to figure out what to do.
|
|
*
|
|
* All the routines below use bits of fixup code that are out of line
|
|
* with the main instruction path. This means when everything is well,
|
|
* we don't even have to jump over them. Further, they do not intrude
|
|
* on our cache or tlb entries.
|
|
*/
|
|
|
|
struct exception_table_entry {
|
|
int insn, fixup;
|
|
short type, data;
|
|
};
|
|
|
|
#define ARCH_HAS_RELATIVE_EXTABLE
|
|
|
|
#define swap_ex_entry_fixup(a, b, tmp, delta) \
|
|
do { \
|
|
(a)->fixup = (b)->fixup + (delta); \
|
|
(b)->fixup = (tmp).fixup - (delta); \
|
|
(a)->type = (b)->type; \
|
|
(b)->type = (tmp).type; \
|
|
(a)->data = (b)->data; \
|
|
(b)->data = (tmp).data; \
|
|
} while (0)
|
|
|
|
#ifdef CONFIG_BPF_JIT
|
|
bool ex_handler_bpf(const struct exception_table_entry *ex, struct pt_regs *regs);
|
|
#else
|
|
static inline
|
|
bool ex_handler_bpf(const struct exception_table_entry *ex, struct pt_regs *regs)
|
|
{
|
|
return false;
|
|
}
|
|
#endif /* !CONFIG_BPF_JIT */
|
|
|
|
bool fixup_exception(struct pt_regs *regs);
|
|
|
|
#endif
|