Skip to content

WIP: BPF support for ARCv2 and ARCv3 #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: arc64
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions arch/arc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ config ARC
select HAVE_KERNEL_LZMA
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_MOD_ARCH_SPECIFIC
select HAVE_PERF_EVENTS
select HAVE_SYSCALL_TRACEPOINTS
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select OF
Expand Down
4 changes: 4 additions & 0 deletions arch/arc/include/asm/perf_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ struct arc_reg_cc_build {

#define PERF_COUNT_ARC_HW_MAX (PERF_COUNT_HW_MAX + 8)

#ifdef CONFIG_PERF_EVENTS
#define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs
#endif

/*
* Some ARC pct quirks:
*
Expand Down
28 changes: 28 additions & 0 deletions arch/arc/include/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#define __ASM_ARC_PTRACE_H

#include <uapi/asm/ptrace.h>
#include <linux/compiler.h>

#ifndef __ASSEMBLY__

Expand Down Expand Up @@ -53,6 +54,8 @@ struct pt_regs {
ecr_reg ecr;
};

#define MAX_REG_OFFSET offsetof(struct pt_regs, ecr)

struct callee_regs {
unsigned long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
};
Expand Down Expand Up @@ -95,6 +98,8 @@ struct pt_regs {
unsigned long status32;
};

#define MAX_REG_OFFSET offsetof(struct pt_regs, status32)

struct callee_regs {
unsigned long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
};
Expand All @@ -119,6 +124,8 @@ struct pt_regs {
unsigned long status32;
};

#define MAX_REG_OFFSET offsetof(struct pt_regs, status32)

/* ARCv3 callee regs start from r14; gp is r30 not r26 */
struct callee_regs {
unsigned long r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26;
Expand Down Expand Up @@ -170,6 +177,27 @@ static inline void instruction_pointer_set(struct pt_regs *regs,
{
instruction_pointer(regs) = val;
}

static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
{
return regs->sp;
}

extern int regs_query_register_offset(const char *name);
extern const char *regs_query_register_name(unsigned int offset);
extern bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr);
extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
unsigned int n);

static inline unsigned long regs_get_register(struct pt_regs *regs,
unsigned int offset)
{
if (unlikely(offset > MAX_REG_OFFSET))
return 0;

return *(unsigned long *)((unsigned long)regs + offset);
}

#endif /* !__ASSEMBLY__ */

#endif /* __ASM_PTRACE_H */
2 changes: 2 additions & 0 deletions arch/arc/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <asm/unistd.h>
#include <asm/ptrace.h> /* in_syscall() */

extern void *sys_call_table[];

static inline long
syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
Expand Down
4 changes: 4 additions & 0 deletions arch/arc/include/asm/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ static inline __attribute_const__ struct thread_info *current_thread_info(void)
#define TIF_NOTIFY_SIGNAL 5 /* signal notifications exist */
#define TIF_SYSCALL_TRACE 15 /* syscall trace active */
#define TIF_MEMDIE 16
#define TIF_SYSCALL_TRACEPOINT 17 /* syscall tracepoint instrumentation */

#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
Expand All @@ -91,11 +92,14 @@ static inline __attribute_const__ struct thread_info *current_thread_info(void)
#define _TIF_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL)
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_MEMDIE (1<<TIF_MEMDIE)
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)

/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_NOTIFY_SIGNAL)

#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)

/*
* _TIF_ALLWORK_MASK includes SYSCALL_TRACE, but we don't need it.
* SYSCALL_TRACE is anyway seperately/unconditionally tested right after a
Expand Down
9 changes: 9 additions & 0 deletions arch/arc/include/uapi/asm/bpf_perf_event.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
#define _UAPI__ASM_BPF_PERF_EVENT_H__

#include <asm/ptrace.h>

typedef struct user_regs_struct bpf_user_pt_regs_t;

#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
117 changes: 115 additions & 2 deletions arch/arc/kernel/disasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,18 +434,60 @@ long __kprobes get_reg(int reg, struct pt_regs *regs,
{
long *p;

#if defined(CONFIG_ISA_ARCOMPACT)
if (reg <= 12) {
p = &regs->r0;
return p[-reg];
}

if (cregs && (reg <= 25)) {
p = &cregs->r13;
return p[13-reg];
return p[13 - reg];
}

if (reg == 26)
return regs->gp;

#elif defined(CONFIG_ISA_ARCV2)
if (reg <= 11) {
p = &regs->r0;
return p[reg];
}

if (reg == 12)
return regs->r12;

if (cregs && (reg <= 25)) {
p = &cregs->r13;
return p[13 - reg];
}

if (reg == 26)
return regs->gp;
if (reg == 30)
return regs->r30;
#ifdef CONFIG_ARC_HAS_ACCL_REGS
if (reg == 58)
return regs->r58;
if (reg == 59)
return regs->r59;
#endif

#else /* CONFIG_ISA_ARCV3 */
if (reg <= 13) {
p = &regs->r0;
return p[reg];
}

if (cregs && (reg <= 26)) {
p = &cregs->r14;
return p[reg - 14];
}

if (reg == 30)
return regs->gp;
#endif

if (reg == 27)
return regs->fp;
if (reg == 28)
Expand All @@ -461,6 +503,7 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
{
long *p;

#if defined(CONFIG_ISA_ARCOMPACT)
switch (reg) {
case 0 ... 12:
p = &regs->r0;
Expand All @@ -469,7 +512,7 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
case 13 ... 25:
if (cregs) {
p = &cregs->r13;
p[13-reg] = val;
p[13 - reg] = val;
}
break;
case 26:
Expand All @@ -487,6 +530,76 @@ void __kprobes set_reg(int reg, long val, struct pt_regs *regs,
default:
break;
}
#elif defined(CONFIG_ISA_ARCV2)
switch (reg) {
case 0 ... 11:
p = &regs->r0;
p[reg] = val;
break;
case 12:
regs->r12 = val;
break;
case 13 ... 25:
if (cregs) {
p = &cregs->r13;
p[13 - reg] = val;
}
break;
case 26:
regs->gp = val;
break;
case 27:
regs->fp = val;
break;
case 28:
regs->sp = val;
break;
case 30:
regs->r30 = val;
break;
case 31:
regs->blink = val;
break;
#ifdef CONFIG_ARC_HAS_ACCL_REGS
case 58:
regs->r58 = val;
break;
case 59:
regs->r59 = val;
break;
#endif
default:
break;
}
#else /* CONFIG_ISA_ARCV3 */
switch (reg) {
case 0 ... 13:
p = &regs->r0;
p[reg] = val;
break;
case 14 ... 26:
if (cregs) {
p = &cregs->r14;
p[reg - 14] = val;
}
break;
case 27:
regs->fp = val;
break;
case 28:
regs->sp = val;
break;
case 30:
regs->gp = val;
break;
case 31:
regs->blink = val;
break;
default:
break;
}

#endif
}

/*
Expand Down
13 changes: 7 additions & 6 deletions arch/arc/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ ENTRY(sys_clone_wrapper)
DISCARD_CALLEE_SAVED_USER

GET_CURR_THR_INFO_FLAGS r10
btst r10, TIF_SYSCALL_TRACE
bnz tracesys_exit
and.f 0, r10, _TIF_SYSCALL_WORK
bnz tracesys_exit

b .Lret_from_system_call
END(sys_clone_wrapper)
Expand All @@ -41,8 +41,8 @@ ENTRY(sys_clone3_wrapper)
DISCARD_CALLEE_SAVED_USER

GET_CURR_THR_INFO_FLAGS r10
btst r10, TIF_SYSCALL_TRACE
bnz tracesys_exit
and.f 0, r10, _TIF_SYSCALL_WORK
bnz tracesys_exit

b .Lret_from_system_call
END(sys_clone3_wrapper)
Expand Down Expand Up @@ -175,6 +175,7 @@ tracesys_exit:
STR r0, sp, PT_r0

; POST syscall trace hook
MOVR r0, sp ; pt_regs
bl @syscall_trace_exit

; don't call ret_from_system_call as it saves r0, already done above
Expand Down Expand Up @@ -223,8 +224,8 @@ ENTRY(EV_Trap)

; syscall tracing ongoing, invoke pre-post-hooks around syscall
GET_CURR_THR_INFO_FLAGS r10
btst r10, TIF_SYSCALL_TRACE
bnz tracesys ; this never comes back
and.f 0, r10, _TIF_SYSCALL_WORK
bnz tracesys ; this never comes back

;============ Normal syscall case

Expand Down
Loading