Skip to content

Commit

Permalink
Merge tag 'powerpc-5.13-4' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/powerpc/linux

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
  • Loading branch information
Linus Torvalds committed May 23, 2021
2 parents 4d76203 + d72500f commit 28ceac6
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 46 deletions.
10 changes: 10 additions & 0 deletions Documentation/powerpc/syscall64-abi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
========

Expand Down
45 changes: 26 additions & 19 deletions arch/powerpc/include/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
42 changes: 26 additions & 16 deletions arch/powerpc/include/asm/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,17 @@ static inline void syscall_rollback(struct task_struct *task,
static inline long syscall_get_error(struct task_struct *task,
struct pt_regs *regs)
{
/*
* If the system call failed,
* regs->gpr[3] contains a positive ERRORCODE.
*/
return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 0;
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,
Expand All @@ -58,18 +64,22 @@ static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs,
int error, long val)
{
/*
* 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;
regs->gpr[3] = error;
if (trap_is_scv(regs)) {
regs->gpr[3] = (long) error ?: val;
} else {
regs->ccr &= ~0x10000000L;
regs->gpr[3] = val;
/*
* 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;
regs->gpr[3] = error;
} else {
regs->ccr &= ~0x10000000L;
regs->gpr[3] = val;
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/kernel/setup_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 18 additions & 9 deletions tools/testing/selftests/seccomp/seccomp_bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1753,16 +1753,25 @@ TEST_F(TRACE_poke, getpid_runs_normally)
# define SYSCALL_RET_SET(_regs, _val) \
do { \
typeof(_val) _result = (_val); \
/* \
* A syscall error is signaled by CR0 SO bit \
* and the code is stored as a positive value. \
*/ \
if (_result < 0) { \
SYSCALL_RET(_regs) = -_result; \
(_regs).ccr |= 0x10000000; \
} else { \
if ((_regs.trap & 0xfff0) == 0x3000) { \
/* \
* scv 0 system call uses -ve result \
* for error, so no need to adjust. \
*/ \
SYSCALL_RET(_regs) = _result; \
(_regs).ccr &= ~0x10000000; \
} 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; \
(_regs).ccr |= 0x10000000; \
} else { \
SYSCALL_RET(_regs) = _result; \
(_regs).ccr &= ~0x10000000; \
} \
} \
} while (0)
# define SYSCALL_RET_SET_ON_PTRACE_EXIT
Expand Down

0 comments on commit 28ceac6

Please sign in to comment.