162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * OpenRISC ptrace.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Linux architectural port borrowing liberally from similar works of
662306a36Sopenharmony_ci * others.  All original copyrights apply as per the original source
762306a36Sopenharmony_ci * declaration.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Modifications for the OpenRISC architecture:
1062306a36Sopenharmony_ci * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
1162306a36Sopenharmony_ci * Copyright (C) 2005 Gyorgy Jeney <nog@bsemi.com>
1262306a36Sopenharmony_ci * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/sched.h>
1762306a36Sopenharmony_ci#include <linux/sched/task_stack.h>
1862306a36Sopenharmony_ci#include <linux/string.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/mm.h>
2162306a36Sopenharmony_ci#include <linux/errno.h>
2262306a36Sopenharmony_ci#include <linux/ptrace.h>
2362306a36Sopenharmony_ci#include <linux/audit.h>
2462306a36Sopenharmony_ci#include <linux/regset.h>
2562306a36Sopenharmony_ci#include <linux/elf.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <asm/thread_info.h>
2862306a36Sopenharmony_ci#include <asm/page.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciasmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciasmlinkage void do_syscall_trace_leave(struct pt_regs *regs);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * Copy the thread state to a regset that can be interpreted by userspace.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * It doesn't matter what our internal pt_regs structure looks like.  The
3862306a36Sopenharmony_ci * important thing is that we export a consistent view of the thread state
3962306a36Sopenharmony_ci * to userspace.  As such, we need to make sure that the regset remains
4062306a36Sopenharmony_ci * ABI compatible as defined by the struct user_regs_struct:
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * (Each item is a 32-bit word)
4362306a36Sopenharmony_ci * r0 = 0 (exported for clarity)
4462306a36Sopenharmony_ci * 31 GPRS r1-r31
4562306a36Sopenharmony_ci * PC (Program counter)
4662306a36Sopenharmony_ci * SR (Supervision register)
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistatic int genregs_get(struct task_struct *target,
4962306a36Sopenharmony_ci		       const struct user_regset *regset,
5062306a36Sopenharmony_ci		       struct membuf to)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	const struct pt_regs *regs = task_pt_regs(target);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	/* r0 */
5562306a36Sopenharmony_ci	membuf_zero(&to, 4);
5662306a36Sopenharmony_ci	membuf_write(&to, regs->gpr + 1, 31 * 4);
5762306a36Sopenharmony_ci	membuf_store(&to, regs->pc);
5862306a36Sopenharmony_ci	return membuf_store(&to, regs->sr);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/*
6262306a36Sopenharmony_ci * Set the thread state from a regset passed in via ptrace
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_cistatic int genregs_set(struct task_struct *target,
6562306a36Sopenharmony_ci		       const struct user_regset *regset,
6662306a36Sopenharmony_ci		       unsigned int pos, unsigned int count,
6762306a36Sopenharmony_ci		       const void *kbuf, const void __user * ubuf)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct pt_regs *regs = task_pt_regs(target);
7062306a36Sopenharmony_ci	int ret;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* ignore r0 */
7362306a36Sopenharmony_ci	user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4);
7462306a36Sopenharmony_ci	/* r1 - r31 */
7562306a36Sopenharmony_ci	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
7662306a36Sopenharmony_ci					 regs->gpr+1, 4, 4*32);
7762306a36Sopenharmony_ci	/* PC */
7862306a36Sopenharmony_ci	if (!ret)
7962306a36Sopenharmony_ci		ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
8062306a36Sopenharmony_ci				 &regs->pc, 4*32, 4*33);
8162306a36Sopenharmony_ci	/*
8262306a36Sopenharmony_ci	 * Skip SR and padding... userspace isn't allowed to changes bits in
8362306a36Sopenharmony_ci	 * the Supervision register
8462306a36Sopenharmony_ci	 */
8562306a36Sopenharmony_ci	if (!ret)
8662306a36Sopenharmony_ci		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 4*33, -1);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return ret;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*
9262306a36Sopenharmony_ci * As OpenRISC shares GPRs and floating point registers we don't need to export
9362306a36Sopenharmony_ci * the floating point registers again.  So here we only export the fpcsr special
9462306a36Sopenharmony_ci * purpose register.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistatic int fpregs_get(struct task_struct *target,
9762306a36Sopenharmony_ci		       const struct user_regset *regset,
9862306a36Sopenharmony_ci		       struct membuf to)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	const struct pt_regs *regs = task_pt_regs(target);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return membuf_store(&to, regs->fpcsr);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int fpregs_set(struct task_struct *target,
10662306a36Sopenharmony_ci		       const struct user_regset *regset,
10762306a36Sopenharmony_ci		       unsigned int pos, unsigned int count,
10862306a36Sopenharmony_ci		       const void *kbuf, const void __user *ubuf)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct pt_regs *regs = task_pt_regs(target);
11162306a36Sopenharmony_ci	int ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	/* FPCSR */
11462306a36Sopenharmony_ci	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
11562306a36Sopenharmony_ci				 &regs->fpcsr, 0, 4);
11662306a36Sopenharmony_ci	return ret;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/*
12062306a36Sopenharmony_ci * Define the register sets available on OpenRISC under Linux
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_cienum or1k_regset {
12362306a36Sopenharmony_ci	REGSET_GENERAL,
12462306a36Sopenharmony_ci	REGSET_FPU,
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct user_regset or1k_regsets[] = {
12862306a36Sopenharmony_ci	[REGSET_GENERAL] = {
12962306a36Sopenharmony_ci			    .core_note_type = NT_PRSTATUS,
13062306a36Sopenharmony_ci			    .n = ELF_NGREG,
13162306a36Sopenharmony_ci			    .size = sizeof(long),
13262306a36Sopenharmony_ci			    .align = sizeof(long),
13362306a36Sopenharmony_ci			    .regset_get = genregs_get,
13462306a36Sopenharmony_ci			    .set = genregs_set,
13562306a36Sopenharmony_ci			    },
13662306a36Sopenharmony_ci	[REGSET_FPU] = {
13762306a36Sopenharmony_ci			    .core_note_type = NT_PRFPREG,
13862306a36Sopenharmony_ci			    .n = sizeof(struct __or1k_fpu_state) / sizeof(long),
13962306a36Sopenharmony_ci			    .size = sizeof(long),
14062306a36Sopenharmony_ci			    .align = sizeof(long),
14162306a36Sopenharmony_ci			    .regset_get = fpregs_get,
14262306a36Sopenharmony_ci			    .set = fpregs_set,
14362306a36Sopenharmony_ci			    },
14462306a36Sopenharmony_ci};
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic const struct user_regset_view user_or1k_native_view = {
14762306a36Sopenharmony_ci	.name = "or1k",
14862306a36Sopenharmony_ci	.e_machine = EM_OPENRISC,
14962306a36Sopenharmony_ci	.regsets = or1k_regsets,
15062306a36Sopenharmony_ci	.n = ARRAY_SIZE(or1k_regsets),
15162306a36Sopenharmony_ci};
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciconst struct user_regset_view *task_user_regset_view(struct task_struct *task)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	return &user_or1k_native_view;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/*
15962306a36Sopenharmony_ci * does not yet catch signals sent when the child dies.
16062306a36Sopenharmony_ci * in exit.c or in signal.c.
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/*
16562306a36Sopenharmony_ci * Called by kernel/ptrace.c when detaching..
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci * Make sure the single step bit is not set.
16862306a36Sopenharmony_ci */
16962306a36Sopenharmony_civoid ptrace_disable(struct task_struct *child)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	pr_debug("ptrace_disable(): TODO\n");
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	user_disable_single_step(child);
17462306a36Sopenharmony_ci	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cilong arch_ptrace(struct task_struct *child, long request, unsigned long addr,
17862306a36Sopenharmony_ci		 unsigned long data)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	int ret;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	switch (request) {
18362306a36Sopenharmony_ci	default:
18462306a36Sopenharmony_ci		ret = ptrace_request(child, request, addr, data);
18562306a36Sopenharmony_ci		break;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return ret;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/*
19262306a36Sopenharmony_ci * Notification of system call entry/exit
19362306a36Sopenharmony_ci * - triggered by current->work.syscall_trace
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_ciasmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	long ret = 0;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (test_thread_flag(TIF_SYSCALL_TRACE) &&
20062306a36Sopenharmony_ci	    ptrace_report_syscall_entry(regs))
20162306a36Sopenharmony_ci		/*
20262306a36Sopenharmony_ci		 * Tracing decided this syscall should not happen.
20362306a36Sopenharmony_ci		 * We'll return a bogus call number to get an ENOSYS
20462306a36Sopenharmony_ci		 * error, but leave the original number in <something>.
20562306a36Sopenharmony_ci		 */
20662306a36Sopenharmony_ci		ret = -1L;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	audit_syscall_entry(regs->gpr[11], regs->gpr[3], regs->gpr[4],
20962306a36Sopenharmony_ci			    regs->gpr[5], regs->gpr[6]);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return ret ? : regs->gpr[11];
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ciasmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	int step;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	audit_syscall_exit(regs);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	step = test_thread_flag(TIF_SINGLESTEP);
22162306a36Sopenharmony_ci	if (step || test_thread_flag(TIF_SYSCALL_TRACE))
22262306a36Sopenharmony_ci		ptrace_report_syscall_exit(regs, step);
22362306a36Sopenharmony_ci}
224