Commit 28ceac69 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'powerpc-5.13-4' of git://git.kernel.org/pub/scm/linux/kernel/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
parents 4d762034 d72500f9
...@@ -109,6 +109,16 @@ auxiliary vector. ...@@ -109,6 +109,16 @@ auxiliary vector.
scv 0 syscalls will always behave as PPC_FEATURE2_HTM_NOSC. 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 vsyscall
======== ========
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#ifndef _ASM_POWERPC_PTRACE_H #ifndef _ASM_POWERPC_PTRACE_H
#define _ASM_POWERPC_PTRACE_H #define _ASM_POWERPC_PTRACE_H
#include <linux/err.h>
#include <uapi/asm/ptrace.h> #include <uapi/asm/ptrace.h>
#include <asm/asm-const.h> #include <asm/asm-const.h>
...@@ -152,25 +153,6 @@ extern unsigned long profile_pc(struct pt_regs *regs); ...@@ -152,25 +153,6 @@ extern unsigned long profile_pc(struct pt_regs *regs);
long do_syscall_trace_enter(struct pt_regs *regs); long do_syscall_trace_enter(struct pt_regs *regs);
void do_syscall_trace_leave(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__ #ifdef __powerpc64__
#define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1) #define user_mode(regs) ((((regs)->msr) >> MSR_PR_LG) & 0x1)
#else #else
...@@ -235,6 +217,31 @@ static __always_inline void set_trap_norestart(struct pt_regs *regs) ...@@ -235,6 +217,31 @@ static __always_inline void set_trap_norestart(struct pt_regs *regs)
regs->trap |= 0x1; 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_single_step() (1)
#define arch_has_block_step() (true) #define arch_has_block_step() (true)
#define ARCH_HAS_USER_SINGLE_STEP_REPORT #define ARCH_HAS_USER_SINGLE_STEP_REPORT
......
...@@ -41,11 +41,17 @@ static inline void syscall_rollback(struct task_struct *task, ...@@ -41,11 +41,17 @@ static inline void syscall_rollback(struct task_struct *task,
static inline long syscall_get_error(struct task_struct *task, static inline long syscall_get_error(struct task_struct *task,
struct pt_regs *regs) struct pt_regs *regs)
{ {
/* if (trap_is_scv(regs)) {
* If the system call failed, unsigned long error = regs->gpr[3];
* regs->gpr[3] contains a positive ERRORCODE.
*/ return IS_ERR_VALUE(error) ? error : 0;
return (regs->ccr & 0x10000000UL) ? -regs->gpr[3] : 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, static inline long syscall_get_return_value(struct task_struct *task,
...@@ -58,18 +64,22 @@ static inline void syscall_set_return_value(struct task_struct *task, ...@@ -58,18 +64,22 @@ static inline void syscall_set_return_value(struct task_struct *task,
struct pt_regs *regs, struct pt_regs *regs,
int error, long val) int error, long val)
{ {
/* if (trap_is_scv(regs)) {
* In the general case it's not obvious that we must deal with CCR regs->gpr[3] = (long) error ?: val;
* 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 { } 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;
}
} }
} }
......
...@@ -369,11 +369,11 @@ void __init early_setup(unsigned long dt_ptr) ...@@ -369,11 +369,11 @@ void __init early_setup(unsigned long dt_ptr)
apply_feature_fixups(); apply_feature_fixups();
setup_feature_keys(); setup_feature_keys();
early_ioremap_setup();
/* Initialize the hash table or TLB handling */ /* Initialize the hash table or TLB handling */
early_init_mmu(); early_init_mmu();
early_ioremap_setup();
/* /*
* After firmware and early platform setup code has set things up, * After firmware and early platform setup code has set things up,
* we note the SPR values for configurable control/performance * we note the SPR values for configurable control/performance
......
...@@ -1753,16 +1753,25 @@ TEST_F(TRACE_poke, getpid_runs_normally) ...@@ -1753,16 +1753,25 @@ TEST_F(TRACE_poke, getpid_runs_normally)
# define SYSCALL_RET_SET(_regs, _val) \ # define SYSCALL_RET_SET(_regs, _val) \
do { \ do { \
typeof(_val) _result = (_val); \ 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. \
if (_result < 0) { \ */ \
SYSCALL_RET(_regs) = -_result; \
(_regs).ccr |= 0x10000000; \
} else { \
SYSCALL_RET(_regs) = _result; \ 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) } while (0)
# define SYSCALL_RET_SET_ON_PTRACE_EXIT # define SYSCALL_RET_SET_ON_PTRACE_EXIT
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment