powerpc fixes for 6.1 #2
- Fix 32-bit syscall wrappers with 64-bit arguments of unaligned register-pairs. Notably this broke ftruncate64 & pread/write64, which can lead to file corruption. - Fix lost interrupts when returning to soft-masked context on 64-bit. - Fix build failure when CONFIG_DTL=n. Thanks to: Nicholas Piggin, Jason A. Donenfeld, Guenter Roeck, Arnd Bergmann, Sachin Sant. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEJFGtCPCthwEv2Y/bUevqPMjhpYAFAmNJQp8THG1wZUBlbGxl cm1hbi5pZC5hdQAKCRBR6+o8yOGlgPd3D/9+uPapAs6/ZGkrbojseiF/fZNyIfTF HcLZ3iWUP9+APuaRxd1m3HbBoWdgFQ9yC5abYnX1z+E/yEhbTaOof9Gu1vXfxbIF Orlc+X12uZMrdU1L2qlgk/89QLeKOTlp/b2eUXJ332Vl4DfJDoknMsqTqbMz9NrL EDj6vmG3JzJgKHmplwxd7d4CExQNh9khZr3lZ6Ae/hC1cZ1PVXD67akwxsc0i8E2 dBGzwsP1SYXPrBMXONT1GNs/whXrKBHNyLWFueab3p0FsSkbc4sY/HaAPzjq7YzK aPV0FQi2YpIZ5IIunZA+vW+tQ8EvyOpOUPMGb7iiN/31YcFbf/k6Y92AlCFlHRq3 9vvsNGzDeFBfvH2wWcR1XaAMQHmBpC4L+dYbCKIyuK9DjgZtpZUV3acagRMFXqMN TeN9h2GXAYxCdNc27I5v3wAvbNcx69E4Bs5F7voKGD4pb7V/4d/li2oix6v0FKIy qAt1PGhD4IgPE3oJOEOYsJRVQNyDfG4eKlFh5ijyyc5hQeGNeKiAH+G+a61R3ueo GvVOdkR/1QxK1XkbgrMyclb0nHN1kEjRHeIcMFW1+dMKA9UvOlJ6u8nkOFRvA3js r00O1uE7DT5WzdGXgEHCCDd7PybBKxpM32m4/vzgDM7xG+DHxp3j7LTQsDOfkFsH bkc31LqrAw3yDQ== =B+7s -----END PGP SIGNATURE----- Merge tag 'powerpc-6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux Pull powerpc fixes from Michael Ellerman: - Fix 32-bit syscall wrappers with 64-bit arguments of unaligned register-pairs. Notably this broke ftruncate64 & pread/write64, which can lead to file corruption. - Fix lost interrupts when returning to soft-masked context on 64-bit. - Fix build failure when CONFIG_DTL=n. Thanks to Nicholas Piggin, Jason A. Donenfeld, Guenter Roeck, Arnd Bergmann, and Sachin Sant. * tag 'powerpc-6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: powerpc/pseries: Fix CONFIG_DTL=n build powerpc/64s/interrupt: Fix lost interrupts when returning to soft-masked context powerpc/32: fix syscall wrappers with 64-bit arguments of unaligned register-pairs
This commit is contained in:
commit
70609c1495
@ -89,6 +89,22 @@ long compat_sys_rt_sigreturn(void);
|
||||
* responsible for combining parameter pairs.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PPC32
|
||||
long sys_ppc_pread64(unsigned int fd,
|
||||
char __user *ubuf, compat_size_t count,
|
||||
u32 reg6, u32 pos1, u32 pos2);
|
||||
long sys_ppc_pwrite64(unsigned int fd,
|
||||
const char __user *ubuf, compat_size_t count,
|
||||
u32 reg6, u32 pos1, u32 pos2);
|
||||
long sys_ppc_readahead(int fd, u32 r4,
|
||||
u32 offset1, u32 offset2, u32 count);
|
||||
long sys_ppc_truncate64(const char __user *path, u32 reg4,
|
||||
unsigned long len1, unsigned long len2);
|
||||
long sys_ppc_ftruncate64(unsigned int fd, u32 reg4,
|
||||
unsigned long len1, unsigned long len2);
|
||||
long sys_ppc32_fadvise64(int fd, u32 unused, u32 offset1, u32 offset2,
|
||||
size_t len, int advice);
|
||||
#endif
|
||||
#ifdef CONFIG_COMPAT
|
||||
long compat_sys_mmap2(unsigned long addr, size_t len,
|
||||
unsigned long prot, unsigned long flags,
|
||||
|
@ -73,6 +73,7 @@ obj-y := cputable.o syscalls.o \
|
||||
obj-y += ptrace/
|
||||
obj-$(CONFIG_PPC64) += setup_64.o irq_64.o\
|
||||
paca.o nvram_64.o note.o
|
||||
obj-$(CONFIG_PPC32) += sys_ppc32.o
|
||||
obj-$(CONFIG_COMPAT) += sys_ppc32.o signal_32.o
|
||||
obj-$(CONFIG_VDSO32) += vdso32_wrapper.o
|
||||
obj-$(CONFIG_PPC_WATCHDOG) += watchdog.o
|
||||
|
@ -538,7 +538,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel)
|
||||
beq .Lfast_kernel_interrupt_return_\srr\() // EE already disabled
|
||||
lbz r11,PACAIRQHAPPENED(r13)
|
||||
andi. r10,r11,PACA_IRQ_MUST_HARD_MASK
|
||||
beq 1f // No HARD_MASK pending
|
||||
beq .Lfast_kernel_interrupt_return_\srr\() // No HARD_MASK pending
|
||||
|
||||
/* Must clear MSR_EE from _MSR */
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
@ -555,12 +555,23 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return_\srr\()_kernel)
|
||||
b .Lfast_kernel_interrupt_return_\srr\()
|
||||
|
||||
.Linterrupt_return_\srr\()_soft_enabled:
|
||||
/*
|
||||
* In the soft-enabled case, need to double-check that we have no
|
||||
* pending interrupts that might have come in before we reached the
|
||||
* restart section of code, and restart the exit so those can be
|
||||
* handled.
|
||||
*
|
||||
* If there are none, it is be possible that the interrupt still
|
||||
* has PACA_IRQ_HARD_DIS set, which needs to be cleared for the
|
||||
* interrupted context. This clear will not clobber a new pending
|
||||
* interrupt coming in, because we're in the restart section, so
|
||||
* such would return to the restart location.
|
||||
*/
|
||||
#ifdef CONFIG_PPC_BOOK3S
|
||||
lbz r11,PACAIRQHAPPENED(r13)
|
||||
andi. r11,r11,(~PACA_IRQ_HARD_DIS)@l
|
||||
bne- interrupt_return_\srr\()_kernel_restart
|
||||
#endif
|
||||
1:
|
||||
li r11,0
|
||||
stb r11,PACAIRQHAPPENED(r13) // clear the possible HARD_DIS
|
||||
|
||||
|
@ -1,13 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* sys_ppc32.c: Conversion between 32bit and 64bit native syscalls.
|
||||
* sys_ppc32.c: 32-bit system calls with complex calling conventions.
|
||||
*
|
||||
* Copyright (C) 2001 IBM
|
||||
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
|
||||
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
|
||||
*
|
||||
* These routines maintain argument size conversion between 32bit and 64bit
|
||||
* environment.
|
||||
* 32-bit system calls with 64-bit arguments pass those in register pairs.
|
||||
* This must be specially dealt with on 64-bit kernels. The compat_arg_u64_dual
|
||||
* in generic compat syscalls is not always usable because the register
|
||||
* pairing is constrained depending on preceding arguments.
|
||||
*
|
||||
* An analogous problem exists on 32-bit kernels with ARCH_HAS_SYSCALL_WRAPPER,
|
||||
* the defined system call functions take the pt_regs as an argument, and there
|
||||
* is a mapping macro which maps registers to arguments
|
||||
* (SC_POWERPC_REGS_TO_ARGS) which also does not deal with these 64-bit
|
||||
* arguments.
|
||||
*
|
||||
* This file contains these system calls.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -47,7 +57,17 @@
|
||||
#include <asm/syscalls.h>
|
||||
#include <asm/switch_to.h>
|
||||
|
||||
COMPAT_SYSCALL_DEFINE6(ppc_pread64,
|
||||
#ifdef CONFIG_PPC32
|
||||
#define PPC32_SYSCALL_DEFINE4 SYSCALL_DEFINE4
|
||||
#define PPC32_SYSCALL_DEFINE5 SYSCALL_DEFINE5
|
||||
#define PPC32_SYSCALL_DEFINE6 SYSCALL_DEFINE6
|
||||
#else
|
||||
#define PPC32_SYSCALL_DEFINE4 COMPAT_SYSCALL_DEFINE4
|
||||
#define PPC32_SYSCALL_DEFINE5 COMPAT_SYSCALL_DEFINE5
|
||||
#define PPC32_SYSCALL_DEFINE6 COMPAT_SYSCALL_DEFINE6
|
||||
#endif
|
||||
|
||||
PPC32_SYSCALL_DEFINE6(ppc_pread64,
|
||||
unsigned int, fd,
|
||||
char __user *, ubuf, compat_size_t, count,
|
||||
u32, reg6, u32, pos1, u32, pos2)
|
||||
@ -55,7 +75,7 @@ COMPAT_SYSCALL_DEFINE6(ppc_pread64,
|
||||
return ksys_pread64(fd, ubuf, count, merge_64(pos1, pos2));
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE6(ppc_pwrite64,
|
||||
PPC32_SYSCALL_DEFINE6(ppc_pwrite64,
|
||||
unsigned int, fd,
|
||||
const char __user *, ubuf, compat_size_t, count,
|
||||
u32, reg6, u32, pos1, u32, pos2)
|
||||
@ -63,28 +83,28 @@ COMPAT_SYSCALL_DEFINE6(ppc_pwrite64,
|
||||
return ksys_pwrite64(fd, ubuf, count, merge_64(pos1, pos2));
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE5(ppc_readahead,
|
||||
PPC32_SYSCALL_DEFINE5(ppc_readahead,
|
||||
int, fd, u32, r4,
|
||||
u32, offset1, u32, offset2, u32, count)
|
||||
{
|
||||
return ksys_readahead(fd, merge_64(offset1, offset2), count);
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE4(ppc_truncate64,
|
||||
PPC32_SYSCALL_DEFINE4(ppc_truncate64,
|
||||
const char __user *, path, u32, reg4,
|
||||
unsigned long, len1, unsigned long, len2)
|
||||
{
|
||||
return ksys_truncate(path, merge_64(len1, len2));
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE4(ppc_ftruncate64,
|
||||
PPC32_SYSCALL_DEFINE4(ppc_ftruncate64,
|
||||
unsigned int, fd, u32, reg4,
|
||||
unsigned long, len1, unsigned long, len2)
|
||||
{
|
||||
return ksys_ftruncate(fd, merge_64(len1, len2));
|
||||
}
|
||||
|
||||
COMPAT_SYSCALL_DEFINE6(ppc32_fadvise64,
|
||||
PPC32_SYSCALL_DEFINE6(ppc32_fadvise64,
|
||||
int, fd, u32, unused, u32, offset1, u32, offset2,
|
||||
size_t, len, int, advice)
|
||||
{
|
||||
|
@ -228,8 +228,10 @@
|
||||
176 64 rt_sigtimedwait sys_rt_sigtimedwait
|
||||
177 nospu rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
|
||||
178 nospu rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
|
||||
179 common pread64 sys_pread64 compat_sys_ppc_pread64
|
||||
180 common pwrite64 sys_pwrite64 compat_sys_ppc_pwrite64
|
||||
179 32 pread64 sys_ppc_pread64 compat_sys_ppc_pread64
|
||||
179 64 pread64 sys_pread64
|
||||
180 32 pwrite64 sys_ppc_pwrite64 compat_sys_ppc_pwrite64
|
||||
180 64 pwrite64 sys_pwrite64
|
||||
181 common chown sys_chown
|
||||
182 common getcwd sys_getcwd
|
||||
183 common capget sys_capget
|
||||
@ -242,10 +244,11 @@
|
||||
188 common putpmsg sys_ni_syscall
|
||||
189 nospu vfork sys_vfork
|
||||
190 common ugetrlimit sys_getrlimit compat_sys_getrlimit
|
||||
191 common readahead sys_readahead compat_sys_ppc_readahead
|
||||
191 32 readahead sys_ppc_readahead compat_sys_ppc_readahead
|
||||
191 64 readahead sys_readahead
|
||||
192 32 mmap2 sys_mmap2 compat_sys_mmap2
|
||||
193 32 truncate64 sys_truncate64 compat_sys_ppc_truncate64
|
||||
194 32 ftruncate64 sys_ftruncate64 compat_sys_ppc_ftruncate64
|
||||
193 32 truncate64 sys_ppc_truncate64 compat_sys_ppc_truncate64
|
||||
194 32 ftruncate64 sys_ppc_ftruncate64 compat_sys_ppc_ftruncate64
|
||||
195 32 stat64 sys_stat64
|
||||
196 32 lstat64 sys_lstat64
|
||||
197 32 fstat64 sys_fstat64
|
||||
@ -288,7 +291,8 @@
|
||||
230 common io_submit sys_io_submit compat_sys_io_submit
|
||||
231 common io_cancel sys_io_cancel
|
||||
232 nospu set_tid_address sys_set_tid_address
|
||||
233 common fadvise64 sys_fadvise64 compat_sys_ppc32_fadvise64
|
||||
233 32 fadvise64 sys_ppc32_fadvise64 compat_sys_ppc32_fadvise64
|
||||
233 64 fadvise64 sys_fadvise64
|
||||
234 nospu exit_group sys_exit_group
|
||||
235 nospu lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
|
||||
236 common epoll_create sys_epoll_create
|
||||
|
@ -7,7 +7,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
|
||||
setup.o iommu.o event_sources.o ras.o \
|
||||
firmware.o power.o dlpar.o mobility.o rng.o \
|
||||
pci.o pci_dlpar.o eeh_pseries.o msi.o \
|
||||
papr_platform_attributes.o
|
||||
papr_platform_attributes.o dtl.o
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_KEXEC_CORE) += kexec.o
|
||||
obj-$(CONFIG_PSERIES_ENERGY) += pseries_energy.o
|
||||
@ -19,7 +19,6 @@ obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
|
||||
obj-$(CONFIG_HVCS) += hvcserver.o
|
||||
obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o
|
||||
obj-$(CONFIG_CMM) += cmm.o
|
||||
obj-$(CONFIG_DTL) += dtl.o
|
||||
obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o
|
||||
obj-$(CONFIG_LPARCFG) += lparcfg.o
|
||||
obj-$(CONFIG_IBMVIO) += vio.o
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <asm/plpar_wrappers.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
#ifdef CONFIG_DTL
|
||||
struct dtl {
|
||||
struct dtl_entry *buf;
|
||||
int cpu;
|
||||
@ -57,78 +58,6 @@ static DEFINE_PER_CPU(struct dtl_ring, dtl_rings);
|
||||
|
||||
static atomic_t dtl_count;
|
||||
|
||||
/*
|
||||
* Scan the dispatch trace log and count up the stolen time.
|
||||
* Should be called with interrupts disabled.
|
||||
*/
|
||||
static notrace u64 scan_dispatch_log(u64 stop_tb)
|
||||
{
|
||||
u64 i = local_paca->dtl_ridx;
|
||||
struct dtl_entry *dtl = local_paca->dtl_curr;
|
||||
struct dtl_entry *dtl_end = local_paca->dispatch_log_end;
|
||||
struct lppaca *vpa = local_paca->lppaca_ptr;
|
||||
u64 tb_delta;
|
||||
u64 stolen = 0;
|
||||
u64 dtb;
|
||||
|
||||
if (!dtl)
|
||||
return 0;
|
||||
|
||||
if (i == be64_to_cpu(vpa->dtl_idx))
|
||||
return 0;
|
||||
while (i < be64_to_cpu(vpa->dtl_idx)) {
|
||||
dtb = be64_to_cpu(dtl->timebase);
|
||||
tb_delta = be32_to_cpu(dtl->enqueue_to_dispatch_time) +
|
||||
be32_to_cpu(dtl->ready_to_enqueue_time);
|
||||
barrier();
|
||||
if (i + N_DISPATCH_LOG < be64_to_cpu(vpa->dtl_idx)) {
|
||||
/* buffer has overflowed */
|
||||
i = be64_to_cpu(vpa->dtl_idx) - N_DISPATCH_LOG;
|
||||
dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG);
|
||||
continue;
|
||||
}
|
||||
if (dtb > stop_tb)
|
||||
break;
|
||||
if (dtl_consumer)
|
||||
dtl_consumer(dtl, i);
|
||||
stolen += tb_delta;
|
||||
++i;
|
||||
++dtl;
|
||||
if (dtl == dtl_end)
|
||||
dtl = local_paca->dispatch_log;
|
||||
}
|
||||
local_paca->dtl_ridx = i;
|
||||
local_paca->dtl_curr = dtl;
|
||||
return stolen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accumulate stolen time by scanning the dispatch trace log.
|
||||
* Called on entry from user mode.
|
||||
*/
|
||||
void notrace pseries_accumulate_stolen_time(void)
|
||||
{
|
||||
u64 sst, ust;
|
||||
struct cpu_accounting_data *acct = &local_paca->accounting;
|
||||
|
||||
sst = scan_dispatch_log(acct->starttime_user);
|
||||
ust = scan_dispatch_log(acct->starttime);
|
||||
acct->stime -= sst;
|
||||
acct->utime -= ust;
|
||||
acct->steal_time += ust + sst;
|
||||
}
|
||||
|
||||
u64 pseries_calculate_stolen_time(u64 stop_tb)
|
||||
{
|
||||
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
|
||||
return 0;
|
||||
|
||||
if (get_paca()->dtl_ridx != be64_to_cpu(get_lppaca()->dtl_idx))
|
||||
return scan_dispatch_log(stop_tb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The cpu accounting code controls the DTL ring buffer, and we get
|
||||
* given entries as they are processed.
|
||||
@ -436,3 +365,81 @@ static int dtl_init(void)
|
||||
return 0;
|
||||
}
|
||||
machine_arch_initcall(pseries, dtl_init);
|
||||
#endif /* CONFIG_DTL */
|
||||
|
||||
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
|
||||
/*
|
||||
* Scan the dispatch trace log and count up the stolen time.
|
||||
* Should be called with interrupts disabled.
|
||||
*/
|
||||
static notrace u64 scan_dispatch_log(u64 stop_tb)
|
||||
{
|
||||
u64 i = local_paca->dtl_ridx;
|
||||
struct dtl_entry *dtl = local_paca->dtl_curr;
|
||||
struct dtl_entry *dtl_end = local_paca->dispatch_log_end;
|
||||
struct lppaca *vpa = local_paca->lppaca_ptr;
|
||||
u64 tb_delta;
|
||||
u64 stolen = 0;
|
||||
u64 dtb;
|
||||
|
||||
if (!dtl)
|
||||
return 0;
|
||||
|
||||
if (i == be64_to_cpu(vpa->dtl_idx))
|
||||
return 0;
|
||||
while (i < be64_to_cpu(vpa->dtl_idx)) {
|
||||
dtb = be64_to_cpu(dtl->timebase);
|
||||
tb_delta = be32_to_cpu(dtl->enqueue_to_dispatch_time) +
|
||||
be32_to_cpu(dtl->ready_to_enqueue_time);
|
||||
barrier();
|
||||
if (i + N_DISPATCH_LOG < be64_to_cpu(vpa->dtl_idx)) {
|
||||
/* buffer has overflowed */
|
||||
i = be64_to_cpu(vpa->dtl_idx) - N_DISPATCH_LOG;
|
||||
dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG);
|
||||
continue;
|
||||
}
|
||||
if (dtb > stop_tb)
|
||||
break;
|
||||
#ifdef CONFIG_DTL
|
||||
if (dtl_consumer)
|
||||
dtl_consumer(dtl, i);
|
||||
#endif
|
||||
stolen += tb_delta;
|
||||
++i;
|
||||
++dtl;
|
||||
if (dtl == dtl_end)
|
||||
dtl = local_paca->dispatch_log;
|
||||
}
|
||||
local_paca->dtl_ridx = i;
|
||||
local_paca->dtl_curr = dtl;
|
||||
return stolen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accumulate stolen time by scanning the dispatch trace log.
|
||||
* Called on entry from user mode.
|
||||
*/
|
||||
void notrace pseries_accumulate_stolen_time(void)
|
||||
{
|
||||
u64 sst, ust;
|
||||
struct cpu_accounting_data *acct = &local_paca->accounting;
|
||||
|
||||
sst = scan_dispatch_log(acct->starttime_user);
|
||||
ust = scan_dispatch_log(acct->starttime);
|
||||
acct->stime -= sst;
|
||||
acct->utime -= ust;
|
||||
acct->steal_time += ust + sst;
|
||||
}
|
||||
|
||||
u64 pseries_calculate_stolen_time(u64 stop_tb)
|
||||
{
|
||||
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
|
||||
return 0;
|
||||
|
||||
if (get_paca()->dtl_ridx != be64_to_cpu(get_lppaca()->dtl_idx))
|
||||
return scan_dispatch_log(stop_tb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user