powerpc fixes for 7.2 #3

- Ensure vpa,slb_shadow & dtl are unregistered during crash
  - fix nap return address corruption on async interrupt exit in 970 platform
  - Fix exit_flags field placement in pt_regs for ptrace
  - Fix map failure path in dma_ioc0_map_pages() in ps3 platfrom
  - MAINTAINERS: Demote myself to reviewer
  - misc fixes and cleanup
 
 Thanks to:
 Amit Machhiwal, Andreas Schwab, Anushree Mathur, Athira Rajeev, Christophe
 Leroy (CS GROUP), Dmitry V. Levin, Geert Uytterhoeven, John Ogness, Michael
 Ellerman, Mukesh Kumar Chaurasiya (IBM), Ritesh Harjani (IBM), Thorsten Blum,
 Vaibhav Jain
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEqX2DNAOgU8sBX3pRpnEsdPSHZJQFAmpq5/gACgkQpnEsdPSH
 ZJR3NQ//d2RIqe/XzW6VOoU0k0KS0mldkj8B8pykkO1XgsWRirJNdq4l+/DNwfsq
 OpIaB7dHoDQP8NIbruYC6tDnDLsEpaQMR6SIr2EeH4H5xHQWUKLiFRQMKOhdzujy
 MHc6EzazEFjW2/ItbcxLOkW8+zhP5K02Zwmj/sF9hsSKFTq4dAnc9LX8OunJfEbz
 /JTXS+SK+Z4BQmDlL22b5rEk432zFtvE33Dw0401Vdsn3x/dEKpynlc1LTdbHJXL
 rkmt3Kc41SnQlFBSO2NzKs6lzz1kQYSC3DdlYOwQ1evvBNqdhzMotg0jKOXFC3C7
 m4FbJKpQjTXHhtJZx4+Vrr5k4MFp6fUg5LIbe+rBeN8Ckgk3Yj7qCw8UVjlXyUTp
 KlkqG6J1Eteg3KMGQClZzZz0kyqWrSsnO7eR8O41wSRmAv27vBxsn9nOKBHcV9Cq
 gzG0IJTIP+4/qTbXhUjBQLlgRpoCjz5UnmAbisKHBXGUI+wz58Uhf2b8/M53RH1b
 qnrb81Vp6nLEtPJrjRXeCwYnTRT4qQ8ON9PB1uAIImG8phdxfsfhTivftLJVQqUA
 DGjFNLpbME2WbyLd0YxDj8jzHp1845/vR+jwyHMQAoQHFJjvAf4/RZ58zKVUtFVR
 susxnX6YodNMfZisVwcZTaj1pds8YSz72gOE44Qn0K3YjqAej9w=
 =On4C
 -----END PGP SIGNATURE-----

Merge tag 'powerpc-7.2-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc fixes from Madhavan Srinivasan:

 - ensure vpa,slb_shadow & dtl are unregistered during crash

 - fix nap return address corruption on async interrupt exit in 970
   platform

 - fix exit_flags field placement in pt_regs for ptrace

 - fix map failure path in dma_ioc0_map_pages() in ps3 platfrom

 - MAINTAINERS: Michael Ellerman demotes himself to reviewer

 - misc fixes and cleanup

Thanks to Amit Machhiwal, Andreas Schwab, Anushree Mathur, Athira
Rajeev, Christophe Leroy (CS GROUP), Dmitry V. Levin, Geert
Uytterhoeven, John Ogness, Michael Ellerman, Mukesh Kumar Chaurasiya
(IBM), Ritesh Harjani (IBM), Thorsten Blum, and Vaibhav Jain

* tag 'powerpc-7.2-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux:
  MAINTAINERS: Demote myself to reviewer
  powerpc/serial: Fix include guard comment
  powerpc/perf: Use strstarts() to simplify is_thread_imc_pmu()
  powerpc/ps3: Fix map failure path in dma_ioc0_map_pages()
  powerpc/ps3: Remove unused struct table in setup_areas()
  powerpc/boot: Fix treeboot-akebono CPU node lookup check
  powerpc/boot: Fix treeboot-currituck CPU node lookup check
  powerpc/boot: Fix simpleboot CPU node lookup check
  powerpc: Fix exit_flags field placement in pt_regs for ptrace
  powerpc/970: fix nap return address corruption on async interrupt exit
  powerpc/pseries: Skip vpa_init() for boot cpu in smp_setup_cpu()
  powerpc/pseries: Ensure vpa,slb_shadow & dtl are unregistered during crash
This commit is contained in:
Linus Torvalds 2026-07-30 08:24:12 -07:00
commit b96890b3e5
18 changed files with 55 additions and 54 deletions

View File

@ -14887,7 +14887,7 @@ X: drivers/macintosh/via-macii.c
LINUX FOR POWERPC (32-BIT AND 64-BIT)
M: Madhavan Srinivasan <maddy@linux.ibm.com>
M: Michael Ellerman <mpe@ellerman.id.au>
R: Michael Ellerman <mpe@ellerman.id.au>
R: Nicholas Piggin <npiggin@gmail.com>
R: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
L: linuxppc-dev@lists.ozlabs.org

View File

@ -68,7 +68,7 @@ void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
/* finally, setup the timebase */
node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
"cpu", sizeof("cpu"));
if (!node)
if (node < 0)
fatal("Cannot find cpu node\n");
timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
if (timebase && (size == 4))

View File

@ -146,7 +146,7 @@ void platform_init(char *userdata)
node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
"cpu", sizeof("cpu"));
if (!node)
if (node < 0)
fatal("Cannot find cpu node\n");
timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
if (timebase && (size == 4))

View File

@ -102,7 +102,7 @@ void platform_init(void)
node = fdt_node_offset_by_prop_value(_dtb_start, -1, "device_type",
"cpu", sizeof("cpu"));
if (!node)
if (node < 0)
fatal("Cannot find cpu node\n");
timebase = fdt_getprop(_dtb_start, node, "timebase-frequency", &size);
if (timebase && (size == 4))

View File

@ -66,6 +66,13 @@ static inline void srr_regs_clobbered(void)
static inline void nap_adjust_return(struct pt_regs *regs)
{
#ifdef CONFIG_PPC_970_NAP
/*
* Adjust the nap return address before irq_exit_rcu(). irq_exit_rcu()
* may invoke softirqs with interrupts re-enabled, allowing a nested
* async interrupt to arrive. If _TLF_NAPPING is still set at that
* point, the nested interrupt would erroneously redirect its own
* return address to power4_idle_nap_return, corrupting the stack.
*/
if (unlikely(test_thread_local_flags(_TLF_NAPPING))) {
/* Can avoid a test-and-clear because NMIs do not call this */
clear_thread_local_flags(_TLF_NAPPING);
@ -286,14 +293,6 @@ static inline void arch_interrupt_async_enter_prepare(struct pt_regs *regs)
static inline void arch_interrupt_async_exit_prepare(struct pt_regs *regs)
{
/*
* Adjust at exit so the main handler sees the true NIA. This must
* come before irq_exit() because irq_exit can enable interrupts, and
* if another interrupt is taken before nap_adjust_return has run
* here, then that interrupt would return directly to idle nap return.
*/
nap_adjust_return(regs);
arch_interrupt_exit_prepare(regs);
}

View File

@ -246,6 +246,7 @@ interrupt_handler void func(struct pt_regs *regs) \
instrumentation_begin(); \
irq_enter_rcu(); \
____##func (regs); \
nap_adjust_return(regs); \
irq_exit_rcu(); \
instrumentation_end(); \
arch_interrupt_async_exit_prepare(regs); \

View File

@ -53,9 +53,6 @@ struct pt_regs
unsigned long esr;
};
unsigned long result;
unsigned long exit_flags;
/* Maintain 16 byte interrupt stack alignment */
unsigned long __pt_regs_pad[3];
};
};
#if defined(CONFIG_PPC64) || defined(CONFIG_PPC_KUAP)

View File

@ -1,6 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
*/
#ifndef _ASM_POWERPC_SERIAL_H
#define _ASM_POWERPC_SERIAL_H
@ -18,4 +16,4 @@ extern void find_legacy_serial_ports(void);
#define find_legacy_serial_ports() do { } while (0)
#endif
#endif /* _PPC64_SERIAL_H */
#endif /* _ASM_POWERPC_SERIAL_H */

View File

@ -57,6 +57,7 @@ struct thread_info {
#ifdef CONFIG_SMP
unsigned int cpu;
#endif
unsigned long exit_flags; /* Exit Flags for entry/exit */
unsigned long syscall_work; /* SYSCALL_WORK_ flags */
unsigned long local_flags; /* private flags for thread */
#ifdef CONFIG_LIVEPATCH_64

View File

@ -55,8 +55,6 @@ struct pt_regs
unsigned long dar; /* Fault registers */
unsigned long dsisr; /* on 4xx/Book-E used for ESR */
unsigned long result; /* Result of a system call */
unsigned long exit_flags; /* System call exit flags */
unsigned long __pt_regs_pad[3]; /* Maintain 16 byte interrupt stack alignment */
};
#endif /* __ASSEMBLER__ */
@ -116,12 +114,10 @@ struct pt_regs
#define PT_DAR 41
#define PT_DSISR 42
#define PT_RESULT 43
#define PT_EXIT_FLAGS 44
#define PT_PAD 47 /* 3 times */
#define PT_DSCR 48
#define PT_REGS_COUNT 48
#define PT_DSCR 44
#define PT_REGS_COUNT 44
#define PT_FPR0 (PT_REGS_COUNT + 4) /* each FP reg occupies 2 slots in this space */
#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */
#ifndef __powerpc64__
@ -133,7 +129,7 @@ struct pt_regs
#define PT_FPSCR (PT_FPR0 + 32) /* each FP reg occupies 1 slot in 64-bit space */
#define PT_VR0 (PT_FPSCR + 2) /* <82> each Vector reg occupies 2 slots in 64-bit */
#define PT_VR0 82 /* each Vector reg occupies 2 slots in 64-bit */
#define PT_VSCR (PT_VR0 + 32*2 + 1)
#define PT_VRSAVE (PT_VR0 + 33*2)
@ -141,7 +137,7 @@ struct pt_regs
/*
* Only store first 32 VSRs here. The second 32 VSRs in VR0-31
*/
#define PT_VSR0 (PT_VRSAVE + 2) /* each VSR reg occupies 2 slots in 64-bit */
#define PT_VSR0 150 /* each VSR reg occupies 2 slots in 64-bit */
#define PT_VSR31 (PT_VSR0 + 2*31)
#endif /* __powerpc64__ */

View File

@ -89,15 +89,17 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
long scv)
{
unsigned long ti_flags;
unsigned long ret = 0;
bool is_not_scv = !IS_ENABLED(CONFIG_PPC_BOOK3S_64) || !scv;
kuap_assert_locked();
regs->result = r3;
regs->exit_flags = 0;
/* Clear exit_flags so only flags set during this exit are visible */
current->thread_info.exit_flags = 0;
ti_flags = read_thread_flags();
if (unlikely(r3 >= (unsigned long)-MAX_ERRNO) && is_not_scv) {
if (likely(!(ti_flags & (_TIF_NOERROR | _TIF_RESTOREALL)))) {
r3 = -r3;
@ -107,7 +109,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
if (unlikely(ti_flags & _TIF_PERSYSCALL_MASK)) {
if (ti_flags & _TIF_RESTOREALL)
regs->exit_flags = _TIF_RESTOREALL;
ret = _TIF_RESTOREALL;
else
regs->gpr[3] = r3;
clear_bits(_TIF_PERSYSCALL_MASK, &current_thread_info()->flags);
@ -116,7 +118,7 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
}
if (unlikely(ti_flags & _TIF_SYSCALL_DOTRACE)) {
regs->exit_flags |= _TIF_RESTOREALL;
ret |= _TIF_RESTOREALL;
}
syscall_exit_to_user_mode(regs);
@ -132,17 +134,19 @@ notrace unsigned long syscall_exit_prepare(unsigned long r3,
/* Restore user access locks last */
kuap_user_restore(regs);
ret |= current->thread_info.exit_flags;
#ifdef CONFIG_PPC64
regs->exit_result = regs->exit_flags;
regs->exit_result = ret;
#endif
return regs->exit_flags;
return ret;
}
#ifdef CONFIG_PPC64
notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *regs)
{
unsigned long ret;
/*
* This is called when detecting a soft-pending interrupt as well as
* an alternate-return interrupt. So we can't just have the alternate
@ -167,9 +171,11 @@ notrace unsigned long syscall_exit_restart(unsigned long r3, struct pt_regs *reg
}
kuap_user_restore(regs);
regs->exit_result |= regs->exit_flags;
ret = current_thread_info()->exit_flags & _TIF_RESTOREALL;
current_thread_info()->exit_flags &= ~_TIF_RESTOREALL;
regs->exit_result |= ret;
return regs->exit_result;
return ret;
}
#endif
@ -186,8 +192,10 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs)
*/
kuap_assert_locked();
/* Clear exit_flags so only flags set during this exit are visible */
current_thread_info()->exit_flags = 0;
local_irq_disable();
regs->exit_flags = 0;
again:
check_return_regs_valid(regs);
user_enter_irqoff();
@ -200,9 +208,7 @@ notrace unsigned long interrupt_exit_user_prepare(struct pt_regs *regs)
/* Restore user access locks last */
kuap_user_restore(regs);
ret = regs->exit_flags;
ret = current_thread_info()->exit_flags & _TIF_RESTOREALL;
#ifdef CONFIG_PPC64
regs->exit_result = ret;
#endif

View File

@ -291,7 +291,6 @@ void __init pt_regs_check(void)
CHECK_REG(PT_DAR, dar);
CHECK_REG(PT_DSISR, dsisr);
CHECK_REG(PT_RESULT, result);
CHECK_REG(PT_EXIT_FLAGS, exit_flags);
#undef CHECK_REG
BUILD_BUG_ON(PT_REGS_COUNT != sizeof(struct user_pt_regs) / sizeof(unsigned long));

View File

@ -356,6 +356,6 @@ void signal_fault(struct task_struct *tsk, struct pt_regs *regs,
void arch_do_signal_or_restart(struct pt_regs *regs)
{
BUG_ON(regs != current->thread.regs);
regs->exit_flags |= _TIF_RESTOREALL;
current_thread_info()->exit_flags |= _TIF_RESTOREALL;
do_signal(current);
}

View File

@ -1023,10 +1023,7 @@ static int thread_imc_event_init(struct perf_event *event)
static bool is_thread_imc_pmu(struct perf_event *event)
{
if (!strncmp(event->pmu->name, "thread_imc", strlen("thread_imc")))
return true;
return false;
return strstarts(event->pmu->name, "thread_imc");
}
static __be64 *get_event_base_addr(struct perf_event *event)

View File

@ -615,6 +615,7 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
fail_map:
for (iopage--; 0 <= iopage; iopage--) {
offset = (1 << r->page_size) * iopage;
lv1_put_iopte(0,
c->bus_addr + offset,
c->lpar_addr + offset,

View File

@ -191,8 +191,6 @@ static void spu_unmap(struct spu *spu)
static int __init setup_areas(struct spu *spu)
{
struct table {char* name; unsigned long addr; unsigned long size;};
spu_pdata(spu)->shadow = ioremap_prot(spu_pdata(spu)->shadow_addr,
sizeof(struct spe_shadow),
pgprot_noncached_wc(PAGE_KERNEL_RO));

View File

@ -20,12 +20,15 @@
void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
{
/*
* Don't risk a hypervisor call if we're crashing
* XXX: Why? The hypervisor is not crashing. It might be better
* to at least attempt unregister to avoid the hypervisor stepping
* on our memory.
* Ensure vpa/slb_shadow/dtl cleanup even while we are crashing.
* Why? The hypervisor is not crashing so at least attempt unregister to
* avoid the hypervisor stepping on our memory. If hypervisor or kexec
* kernel steps on the old memory allocated to these areas before the
* new kexec-kernel happens to allocate and register new areas,
* the hypervisor will see invalid content which may cause
* unexpected behavior.
*/
if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
int ret;
int cpu = smp_processor_id();
int hwcpu = hard_smp_processor_id();

View File

@ -128,7 +128,12 @@ static void smp_setup_cpu(int cpu)
else if (cpu != boot_cpuid)
xics_setup_cpu();
if (firmware_has_feature(FW_FEATURE_SPLPAR))
/*
* Initialize VPA on non-boot cpus since boot-cpu vpa was
* already initialized in pSeries_setup_arch()
*/
if (firmware_has_feature(FW_FEATURE_SPLPAR) &&
cpu != boot_cpuid)
vpa_init(cpu);
cpumask_clear_cpu(cpu, of_spin_mask);