parisc architecture fixes and updates for kernel v7.1-rc1:

- A fix to make modules on 32-bit parisc architecture work again
 - Drop ip_fast_csum() inline assembly to avoid unaligned memory accesses
 - Allow to build kernel without 32-bit VDSO
 - Reference leak fix in error path in LED driver
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCaeOk+QAKCRD3ErUQojoP
 X6fjAQD0DK47ZT3fuUGVH0T1mg6kZ2a7fSrNkjbGW+B87jlZVQD/ez6eLdZ7+B4f
 k+sQ9Y0e18Ypgi1uvtNFe1lzX25jrQg=
 =GnPk
 -----END PGP SIGNATURE-----

Merge tag 'parisc-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc architecture updates from Helge Deller:

 - A fix to make modules on 32-bit parisc architecture work again

 - Drop ip_fast_csum() inline assembly to avoid unaligned memory
   accesses

 - Allow to build kernel without 32-bit VDSO

 - Reference leak fix in error path in LED driver

* tag 'parisc-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: led: fix reference leak on failed device registration
  module.lds.S: Fix modules on 32-bit parisc architecture
  parisc: Allow to build without VDSO32
  parisc: Include 32-bit VDSO only when building for 32-bit or compat mode
  parisc: Allow to disable COMPAT mode on 64-bit kernel
  parisc: Fix default stack size when COMPAT=n
  parisc: Fix signal code to depend on CONFIG_COMPAT instead of CONFIG_64BIT
  parisc: is_compat_task() shall return false for COMPAT=n
  parisc: Avoid compat syscalls when COMPAT=n
  parisc: _llseek syscall is only available for 32-bit userspace
  parisc: Drop ip_fast_csum() inline assembly implementation
  parisc: update outdated comments for renamed ccio_alloc_consistent()
This commit is contained in:
Linus Torvalds 2026-04-18 11:37:36 -07:00
commit eb5249b125
16 changed files with 56 additions and 212 deletions

View File

@ -1127,6 +1127,13 @@ config ARCH_WANTS_MODULES_DATA_IN_VMALLOC
For architectures like powerpc/32 which have constraints on module
allocation and need to allocate module data outside of module area.
config ARCH_WANTS_MODULES_TEXT_SECTIONS
bool
help
For architectures like 32-bit parisc which require that functions in
modules have to keep code in own text sections (-ffunction-sections)
and to avoid merging all text into one big text section,
config ARCH_WANTS_EXECMEM_LATE
bool
help

View File

@ -8,6 +8,7 @@ config PARISC
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_SYSCALL_TRACEPOINTS
select ARCH_WANT_FRAME_POINTERS
select ARCH_WANTS_MODULES_TEXT_SECTIONS if !64BIT
select ARCH_HAS_CPU_CACHE_ALIASING
select ARCH_HAS_DMA_ALLOC if PA11
select ARCH_HAS_DMA_OPS
@ -130,6 +131,9 @@ config GENERIC_BUG
config GENERIC_BUG_RELATIVE_POINTERS
bool
config GENERIC_CSUM
def_bool y
config GENERIC_HWEIGHT
bool
default y
@ -354,7 +358,8 @@ config ARCH_SPARSEMEM_DEFAULT
source "kernel/Kconfig.hz"
config COMPAT
def_bool y
bool "Kernel support for 32-bit binaries"
default 64BIT
depends on 64BIT
config AUDIT_ARCH

View File

@ -176,10 +176,12 @@ prepare: vdso_prepare
vdso_prepare: prepare0
$(if $(CONFIG_64BIT),$(Q)$(MAKE) \
$(build)=arch/parisc/kernel/vdso64 include/generated/vdso64-offsets.h)
$(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 include/generated/vdso32-offsets.h
$(if $(CONFIG_PA11)$(CONFIG_COMPAT),$(Q)$(MAKE) \
$(build)=arch/parisc/kernel/vdso32 include/generated/vdso32-offsets.h)
endif
vdso-install-y += arch/parisc/kernel/vdso32/vdso32.so
vdso-install-$(CONFIG_PA11) += arch/parisc/kernel/vdso32/vdso32.so
vdso-install-$(CONFIG_COMPAT) += arch/parisc/kernel/vdso32/vdso32.so
vdso-install-$(CONFIG_64BIT) += arch/parisc/kernel/vdso64/vdso64.so
install: KBUILD_IMAGE := vmlinux

View File

@ -4,73 +4,7 @@
#include <linux/in6.h>
/*
* computes the checksum of a memory block at buff, length len,
* and adds in "sum" (32-bit)
*
* returns a 32-bit number suitable for feeding into itself
* or csum_tcpudp_magic
*
* this function must be called with even lengths, except
* for the last fragment, which may be odd
*
* it's best to have buff aligned on a 32-bit boundary
*/
extern __wsum csum_partial(const void *, int, __wsum);
/*
* Optimized for IP headers, which always checksum on 4 octet boundaries.
*
* Written by Randolph Chung <tausq@debian.org>, and then mucked with by
* LaMont Jones <lamont@debian.org>
*/
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
unsigned int sum;
unsigned long t0, t1, t2;
__asm__ __volatile__ (
" ldws,ma 4(%1), %0\n"
" addib,<= -4, %2, 2f\n"
"\n"
" ldws 4(%1), %4\n"
" ldws 8(%1), %5\n"
" add %0, %4, %0\n"
" ldws,ma 12(%1), %3\n"
" addc %0, %5, %0\n"
" addc %0, %3, %0\n"
"1: ldws,ma 4(%1), %3\n"
" addib,> -1, %2, 1b\n"
" addc %0, %3, %0\n"
"\n"
" extru %0, 31, 16, %4\n"
" extru %0, 15, 16, %5\n"
" addc %4, %5, %0\n"
" extru %0, 15, 16, %5\n"
" add %0, %5, %0\n"
" subi -1, %0, %0\n"
"2:\n"
: "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (t0), "=r" (t1), "=r" (t2)
: "1" (iph), "2" (ihl)
: "memory");
return (__force __sum16)sum;
}
/*
* Fold a partial checksum
*/
static inline __sum16 csum_fold(__wsum csum)
{
u32 sum = (__force u32)csum;
/* add the swapped two 16-bit halves of sum,
a possible carry from adding the two 16-bit halves,
will carry from the lower half into the upper half,
giving us the correct sum in the upper half. */
sum += (sum << 16) + (sum >> 16);
return (__force __sum16)(~sum >> 16);
}
#define csum_tcpudp_nofold csum_tcpudp_nofold
static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto,
__wsum sum)
@ -85,26 +19,7 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
return sum;
}
/*
* computes the checksum of the TCP/UDP pseudo-header
* returns a 16-bit checksum, already complemented
*/
static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
__u32 len, __u8 proto,
__wsum sum)
{
return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
}
/*
* this routine is used for miscellaneous IP-like checksums, mainly
* in icmp.c
*/
static inline __sum16 ip_compute_csum(const void *buf, int len)
{
return csum_fold (csum_partial(buf, len, 0));
}
#include <asm-generic/checksum.h>
#define _HAVE_ARCH_IPV6_CSUM
static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,

View File

@ -130,7 +130,7 @@ typedef compat_ulong_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
static inline int __is_compat_task(struct task_struct *t)
{
return test_tsk_thread_flag(t, TIF_32BIT);
return IS_ENABLED(CONFIG_COMPAT) && test_tsk_thread_flag(t, TIF_32BIT);
}
static inline int is_compat_task(void)

View File

@ -7,7 +7,9 @@
#ifdef CONFIG_64BIT
#include <generated/vdso64-offsets.h>
#endif
#if !defined(CONFIG_64BIT) || defined(CONFIG_COMPAT)
#include <generated/vdso32-offsets.h>
#endif
#define VDSO64_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso64_offset_##name))
#define VDSO32_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso32_offset_##name))

View File

@ -47,4 +47,5 @@ obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
# vdso
obj-y += vdso.o
obj-$(CONFIG_64BIT) += vdso64/
obj-y += vdso32/
obj-$(CONFIG_PA11) += vdso32/
obj-$(CONFIG_COMPAT) += vdso32/

View File

@ -80,7 +80,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
sigset_t set;
unsigned long usp = (regs->gr[30] & ~(0x01UL));
unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
struct compat_rt_sigframe __user * compat_frame;
if (is_compat_task())
@ -96,7 +96,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
regs->orig_r28 = 1; /* no restarts for sigreturn */
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
compat_frame = (struct compat_rt_sigframe __user *)frame;
if (is_compat_task()) {
@ -112,7 +112,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
set_current_blocked(&set);
/* Good thing we saved the old gr[30], eh? */
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
if (is_compat_task()) {
DBG(1, "%s: compat_frame->uc.uc_mcontext 0x%p\n",
__func__, &compat_frame->uc.uc_mcontext);
@ -218,13 +218,13 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs,
unsigned long haddr, sigframe_size;
unsigned long start;
int err = 0;
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
struct compat_rt_sigframe __user * compat_frame;
#endif
usp = (regs->gr[30] & ~(0x01UL));
sigframe_size = PARISC_RT_SIGFRAME_SIZE;
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
if (is_compat_task()) {
/* The gcc alloca implementation leaves garbage in the upper 32 bits of sp */
usp = (compat_uint_t)usp;
@ -239,7 +239,7 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs,
if (start >= TASK_SIZE_MAX - sigframe_size)
return -EFAULT;
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
compat_frame = (struct compat_rt_sigframe __user *)frame;
@ -349,8 +349,8 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs,
regs->gr[2] = rp; /* userland return pointer */
regs->gr[26] = ksig->sig; /* signal number */
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
if (is_compat_task()) {
regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */

View File

@ -50,9 +50,13 @@ static inline unsigned long COLOR_ALIGN(unsigned long addr,
}
#ifdef CONFIG_COMPAT
#define STACK_SIZE_DEFAULT (USER_WIDE_MODE \
? (1 << 30) /* 1 GB */ \
: (CONFIG_STACK_MAX_DEFAULT_SIZE_MB*1024*1024))
#else
#define STACK_SIZE_DEFAULT (1 << 30)
#endif
unsigned long calc_max_stack_size(unsigned long stack_max)
{

View File

@ -241,7 +241,7 @@ linux_gateway_entry:
/* Note! We cannot use the syscall table that is mapped
nearby since the gateway page is mapped execute-only. */
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
ldil L%sys_call_table, %r1
or,ev %r2,%r2,%r2
ldil L%sys_call_table64, %r1
@ -250,7 +250,7 @@ linux_gateway_entry:
ldo R%sys_call_table64(%r1), %r19
#else
load32 sys_call_table, %r19
#endif
#endif
comiclr,>> __NR_Linux_syscalls, %r20, %r0
b,n .Lsyscall_nosys
@ -374,7 +374,7 @@ tracesys_next:
/* Note! We cannot use the syscall table that is mapped
nearby since the gateway page is mapped execute-only. */
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
LDREG TASK_PT_GR30(%r1), %r19 /* get users sp back */
extrd,u %r19,63,1,%r2 /* W hidden in bottom bit */
@ -1326,16 +1326,19 @@ ENTRY(lws_table)
END(lws_table)
/* End of lws table */
#ifdef CONFIG_64BIT
#ifdef CONFIG_COMPAT
#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, compat)
#else
#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native)
#endif
#define __SYSCALL(nr, entry) ASM_ULONG_INSN entry
.align 8
ENTRY(sys_call_table)
.export sys_call_table,data
#if defined(CONFIG_COMPAT) || !defined(CONFIG_64BIT)
#include <asm/syscall_table_32.h> /* 32-bit syscalls */
#endif
END(sys_call_table)
#ifdef CONFIG_64BIT

View File

@ -154,7 +154,7 @@
# 137 was afs_syscall
138 common setfsuid sys_setfsuid
139 common setfsgid sys_setfsgid
140 common _llseek sys_llseek
140 32 _llseek sys_llseek
141 common getdents sys_getdents compat_sys_getdents
142 common _newselect sys_select compat_sys_select
143 common flock sys_flock

View File

@ -3,7 +3,7 @@
# Makefile for parisc-specific library files
#
lib-y := lusercopy.o bitops.o checksum.o io.o memset.o memcpy.o \
lib-y := lusercopy.o bitops.o io.o memset.o memcpy.o \
ucmpdi2.o delay.o
obj-y := iomap.o

View File

@ -1,99 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
*
* MIPS specific IP/TCP/UDP checksumming routines
*
* Authors: Ralf Baechle, <ralf@waldorf-gmbh.de>
* Lots of code moved from tcp.c and ip.c; see those files
* for more names.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <asm/byteorder.h>
#include <asm/string.h>
#include <linux/uaccess.h>
#define addc(_t,_r) \
__asm__ __volatile__ ( \
" add %0, %1, %0\n" \
" addc %0, %%r0, %0\n" \
: "=r"(_t) \
: "r"(_r), "0"(_t));
static inline unsigned int do_csum(const unsigned char * buff, int len)
{
int odd, count;
unsigned int result = 0;
if (len <= 0)
goto out;
odd = 1 & (unsigned long) buff;
if (odd) {
result = be16_to_cpu(*buff);
len--;
buff++;
}
count = len >> 1; /* nr of 16-bit words.. */
if (count) {
if (2 & (unsigned long) buff) {
result += *(unsigned short *) buff;
count--;
len -= 2;
buff += 2;
}
count >>= 1; /* nr of 32-bit words.. */
if (count) {
while (count >= 4) {
unsigned int r1, r2, r3, r4;
r1 = *(unsigned int *)(buff + 0);
r2 = *(unsigned int *)(buff + 4);
r3 = *(unsigned int *)(buff + 8);
r4 = *(unsigned int *)(buff + 12);
addc(result, r1);
addc(result, r2);
addc(result, r3);
addc(result, r4);
count -= 4;
buff += 16;
}
while (count) {
unsigned int w = *(unsigned int *) buff;
count--;
buff += 4;
addc(result, w);
}
result = (result & 0xffff) + (result >> 16);
}
if (len & 2) {
result += *(unsigned short *) buff;
buff += 2;
}
}
if (len & 1)
result += le16_to_cpu(*buff);
result = csum_from32to16(result);
if (odd)
result = swab16(result);
out:
return result;
}
/*
* computes a partial checksum, e.g. for TCP/UDP fragments
*/
/*
* why bother folding?
*/
__wsum csum_partial(const void *buff, int len, __wsum sum)
{
unsigned int result = do_csum(buff, len);
addc(result, sum);
return (__force __wsum)csum_from32to16(result);
}
EXPORT_SYMBOL(csum_partial);

View File

@ -503,8 +503,8 @@ typedef unsigned long space_t;
/*
** Use direction (ie PCI_DMA_TODEVICE) to pick hint.
** ccio_alloc_consistent() depends on this to get SAFE_DMA
** Use direction (ie DMA_TO_DEVICE) to pick hint.
** ccio_alloc() depends on this to get SAFE_DMA
** when it passes in BIDIRECTIONAL flag.
*/
static u32 hint_lookup[] = {
@ -865,8 +865,8 @@ ccio_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag,
* ccio_free - Free a consistent DMA mapping.
* @dev: The PCI device.
* @size: The length of the DMA region.
* @cpu_addr: The cpu address returned from the ccio_alloc_consistent.
* @dma_handle: The device address returned from the ccio_alloc_consistent.
* @cpu_addr: The cpu address returned from ccio_alloc().
* @dma_handle: The device address returned from ccio_alloc().
* @attrs: attributes
*
* This function implements the pci_free_consistent function.

View File

@ -543,8 +543,10 @@ static void __init register_led_regions(void)
static int __init startup_leds(void)
{
if (platform_device_register(&platform_leds))
printk(KERN_INFO "LED: failed to register LEDs\n");
if (platform_device_register(&platform_leds)) {
pr_info("LED: failed to register LEDs\n");
platform_device_put(&platform_leds);
}
register_led_regions();
return 0;
}

View File

@ -40,9 +40,11 @@ SECTIONS {
__kcfi_traps 0 : { KEEP(*(.kcfi_traps)) }
#endif
#ifndef CONFIG_ARCH_WANTS_MODULES_TEXT_SECTIONS
.text 0 : {
*(.text .text.[0-9a-zA-Z_]*)
}
#endif
.bss 0 : {
*(.bss .bss.[0-9a-zA-Z_]*)