Commit 28ceac69 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull powerpc fixes from Michael Ellerman:

 - Fix breakage of strace (and other ptracers etc.) when using the new
   scv ABI (Power9 or later with glibc >= 2.33).

 - Fix early_ioremap() on 64-bit, which broke booting on some machines.

Thanks to Dmitry V. Levin, Nicholas Piggin, Alexey Kardashevskiy, and
Christophe Leroy.

* tag 'powerpc-5.13-4' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  powerpc/64s/syscall: Fix ptrace syscall info with scv syscalls
  powerpc/64s/syscall: Use pt_regs.trap to distinguish syscall ABI difference between sc and scv syscalls
  powerpc: Fix early setup to make early_ioremap() work
parents 4d762034 d72500f9
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -109,6 +109,16 @@ auxiliary vector.

scv 0 syscalls will always behave as PPC_FEATURE2_HTM_NOSC.

ptrace
------
When ptracing system calls (PTRACE_SYSCALL), the pt_regs.trap value contains
the system call type that can be used to distinguish between sc and scv 0
system calls, and the different register conventions can be accounted for.

If the value of (pt_regs.trap & 0xfff0) is 0xc00 then the system call was
performed with the sc instruction, if it is 0x3000 then the system call was
performed with the scv 0 instruction.

vsyscall
========

+26 −19
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#ifndef _ASM_POWERPC_PTRACE_H
#define _ASM_POWERPC_PTRACE_H

#include <linux/err.h>
#include <uapi/asm/ptrace.h>
#include <asm/asm-const.h>

@@ -152,25 +153,6 @@ extern unsigned long profile_pc(struct pt_regs *regs);
long do_syscall_trace_enter(struct pt_regs *regs);
void do_syscall_trace_leave(struct pt_regs *regs);

#define kernel_stack_pointer(regs) ((regs)->gpr[1])
static inline int is_syscall_success(struct pt_regs *regs)
{
	return !(regs->ccr & 0x10000000);
}

static inline long regs_return_value(struct pt_regs *regs)
{
	if (is_syscall_success(regs))
		return regs->gpr[3];
	else
		return -regs->gpr[3];
}

static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
{
	regs->gpr[3] = rc;
}

#ifdef __powerpc64__
#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
#else
@@ -235,6 +217,31 @@ static __always_inline void set_trap_norestart(struct pt_regs *regs)
	regs->trap |= 0x1;
}

#define kernel_stack_pointer(regs) ((regs)->gpr[1])
static inline int is_syscall_success(struct pt_regs *regs)
{
	if (trap_is_scv(regs))
		return !IS_ERR_VALUE((unsigned long)regs->gpr[3]);
	else
		return !(regs->ccr & 0x10000000);
}

static inline long regs_return_value(struct pt_regs *regs)
{
	if (trap_is_scv(regs))
		return regs->gpr[3];

	if (is_syscall_success(regs))
		return regs->gpr[3];
	else
		return -regs->gpr[3];
}

static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
{
	regs->gpr[3] = rc;
}

#define arch_has_single_step()	(1)
#define arch_has_block_step()	(true)
#define ARCH_HAS_USER_SINGLE_STEP_REPORT
+26 −16
Original line number Diff line number Diff line
@@ -41,12 +41,18 @@ static inline void syscall_rollback(struct task_struct *task,
static inline long syscall_get_error(struct task_struct *task,
				     struct pt_regs *regs)
{
	if (trap_is_scv(regs)) {
		unsigned long error = regs->gpr[3];

		return IS_ERR_VALUE(error) ? error : 0;
	} else {
		/*
		 * If the system call failed,
		 * regs->gpr[3] contains a positive ERRORCODE.
		 */
		return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
	}
}

static inline long syscall_get_return_value(struct task_struct *task,
					    struct pt_regs *regs)
@@ -58,11 +64,14 @@ static inline void syscall_set_return_value(struct task_struct *task,
					    struct pt_regs *regs,
					    int error, long val)
{
	if (trap_is_scv(regs)) {
		regs->gpr[3] = (long) error ?: val;
	} else {
		/*
	 * In the general case it's not obvious that we must deal with CCR
	 * here, as the syscall exit path will also do that for us. However
	 * there are some places, eg. the signal code, which check ccr to
	 * decide if the value in r3 is actually an error.
		 * In the general case it's not obvious that we must deal with
		 * CCR here, as the syscall exit path will also do that for us.
		 * However there are some places, eg. the signal code, which
		 * check ccr to decide if the value in r3 is actually an error.
		 */
		if (error) {
			regs->ccr |= 0x10000000L;
@@ -72,6 +81,7 @@ static inline void syscall_set_return_value(struct task_struct *task,
			regs->gpr[3] = val;
		}
	}
}

static inline void syscall_get_arguments(struct task_struct *task,
					 struct pt_regs *regs,
+2 −2
Original line number Diff line number Diff line
@@ -369,11 +369,11 @@ void __init early_setup(unsigned long dt_ptr)
	apply_feature_fixups();
	setup_feature_keys();

	early_ioremap_setup();

	/* Initialize the hash table or TLB handling */
	early_init_mmu();

	early_ioremap_setup();

	/*
	 * After firmware and early platform setup code has set things up,
	 * we note the SPR values for configurable control/performance
+18 −9
Original line number Diff line number Diff line
@@ -1753,9 +1753,17 @@ TEST_F(TRACE_poke, getpid_runs_normally)
# define SYSCALL_RET_SET(_regs, _val)				\
	do {							\
		typeof(_val) _result = (_val);			\
		if ((_regs.trap & 0xfff0) == 0x3000) {		\
			/*					\
		 * A syscall error is signaled by CR0 SO bit	\
		 * and the code is stored as a positive value.	\
			 * scv 0 system call uses -ve result	\
			 * for error, so no need to adjust.	\
			 */					\
			SYSCALL_RET(_regs) = _result;		\
		} else {					\
			/*					\
			 * A syscall error is signaled by the	\
			 * CR0 SO bit and the code is stored as	\
			 * a positive value.			\
			 */					\
			if (_result < 0) {			\
				SYSCALL_RET(_regs) = -_result;	\
@@ -1764,6 +1772,7 @@ TEST_F(TRACE_poke, getpid_runs_normally)
				SYSCALL_RET(_regs) = _result;	\
				(_regs).ccr &= ~0x10000000;	\
			}					\
		}						\
	} while (0)
# define SYSCALL_RET_SET_ON_PTRACE_EXIT
#elif defined(__s390__)