diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-09 20:20:17 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-02-09 20:20:17 -0800 |
| commit | 7e3a1e0cccbf6d9bcc05e2710f53a480639cf81d (patch) | |
| tree | 9860fe05fc3212b5bc6a4c98101a224918ff8634 /arch | |
| parent | b33c3b84045e880d8a7596f260860038c71cf393 (diff) | |
| parent | d844152d85cfcc7d2ef9430a25882604c12da279 (diff) | |
Merge tag 'sparc-for-7.0-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/alarsson/linux-sparc
Pull sparc updates from Andreas Larsson:
- Hardcode uapi ioctls.h TC* constants to not rely upon struct termio
that has been dropped by glibc
- Fix bug for fork/clone and add support for clone3
- Add ARCH_HAS_CC_CAN_LINK
- API choice improvements and cleanup of unused variables
* tag 'sparc-for-7.0-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/alarsson/linux-sparc:
sparc: remove unused variable strtab
sparc64: fix unused variable warning
sparc: don't reference obsolete termio struct for TC* constants
sparc: vio: Replace snprintf with strscpy in vio_create_one
sparc: Add architecture support for clone3
sparc: Synchronize user stack on fork and clone
sparc: Implement ARCH_HAS_CC_CAN_LINK
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/sparc/Kconfig | 11 | ||||
| -rw-r--r-- | arch/sparc/include/asm/syscalls.h | 1 | ||||
| -rw-r--r-- | arch/sparc/include/asm/unistd.h | 2 | ||||
| -rw-r--r-- | arch/sparc/include/uapi/asm/ioctls.h | 8 | ||||
| -rw-r--r-- | arch/sparc/kernel/entry.S | 15 | ||||
| -rw-r--r-- | arch/sparc/kernel/kernel.h | 1 | ||||
| -rw-r--r-- | arch/sparc/kernel/module.c | 2 | ||||
| -rw-r--r-- | arch/sparc/kernel/process.c | 52 | ||||
| -rw-r--r-- | arch/sparc/kernel/process_32.c | 23 | ||||
| -rw-r--r-- | arch/sparc/kernel/process_64.c | 27 | ||||
| -rw-r--r-- | arch/sparc/kernel/syscalls.S | 8 | ||||
| -rw-r--r-- | arch/sparc/kernel/syscalls/syscall.tbl | 2 | ||||
| -rw-r--r-- | arch/sparc/kernel/vio.c | 4 | ||||
| -rw-r--r-- | arch/sparc/mm/init_64.c | 6 |
14 files changed, 119 insertions, 43 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index a630d373e645..68b553a47d03 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -13,6 +13,7 @@ config 64BIT config SPARC bool default y + select ARCH_HAS_CC_CAN_LINK select ARCH_HAS_CPU_CACHE_ALIASING select ARCH_HAS_DMA_OPS select ARCH_MIGHT_HAVE_PC_PARPORT if SPARC64 && PCI @@ -475,4 +476,14 @@ config COMPAT select ARCH_WANT_OLD_COMPAT_IPC select COMPAT_OLD_SIGACTION +config ARCH_CC_CAN_LINK + bool + default $(cc_can_link_user,-m64) if 64BIT + default $(cc_can_link_user,-m32) + +config ARCH_USERFLAGS + string + default "-m64" if 64BIT + default "-m32" + source "drivers/sbus/char/Kconfig" diff --git a/arch/sparc/include/asm/syscalls.h b/arch/sparc/include/asm/syscalls.h index 35575fbfb9dc..282e62b66518 100644 --- a/arch/sparc/include/asm/syscalls.h +++ b/arch/sparc/include/asm/syscalls.h @@ -7,5 +7,6 @@ struct pt_regs; asmlinkage long sparc_fork(struct pt_regs *regs); asmlinkage long sparc_vfork(struct pt_regs *regs); asmlinkage long sparc_clone(struct pt_regs *regs); +asmlinkage long sparc_clone3(struct pt_regs *regs); #endif /* _SPARC64_SYSCALLS_H */ diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h index 3380411a4537..d6bc76706a7a 100644 --- a/arch/sparc/include/asm/unistd.h +++ b/arch/sparc/include/asm/unistd.h @@ -49,8 +49,6 @@ #define __ARCH_WANT_COMPAT_STAT #endif -#define __ARCH_BROKEN_SYS_CLONE3 - #ifdef __32bit_syscall_numbers__ /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, * it never had the plain ones and there is no value to adding those diff --git a/arch/sparc/include/uapi/asm/ioctls.h b/arch/sparc/include/uapi/asm/ioctls.h index 7fd2f5873c9e..a8bbdf9877a4 100644 --- a/arch/sparc/include/uapi/asm/ioctls.h +++ b/arch/sparc/include/uapi/asm/ioctls.h @@ -5,10 +5,10 @@ #include <asm/ioctl.h> /* Big T */ -#define TCGETA _IOR('T', 1, struct termio) -#define TCSETA _IOW('T', 2, struct termio) -#define TCSETAW _IOW('T', 3, struct termio) -#define TCSETAF _IOW('T', 4, struct termio) +#define TCGETA 0x40125401 /* _IOR('T', 1, struct termio) */ +#define TCSETA 0x80125402 /* _IOW('T', 2, struct termio) */ +#define TCSETAW 0x80125403 /* _IOW('T', 3, struct termio) */ +#define TCSETAF 0x80125404 /* _IOW('T', 4, struct termio) */ #define TCSBRK _IO('T', 5) #define TCXONC _IO('T', 6) #define TCFLSH _IO('T', 7) diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index a3fdee4cd6fa..ea51ef52c952 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -907,6 +907,21 @@ flush_patch_four: jmpl %l1 + %lo(sparc_vfork), %g0 add %sp, STACKFRAME_SZ, %o0 + .globl __sys_clone3, flush_patch_five +__sys_clone3: + mov %o7, %l5 +flush_patch_five: + FLUSH_ALL_KERNEL_WINDOWS; + ld [%curptr + TI_TASK], %o4 + rd %psr, %g4 + WRITE_PAUSE + rd %wim, %g5 + WRITE_PAUSE + std %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr] + add %sp, STACKFRAME_SZ, %o0 + call sparc_clone3 + mov %l5, %o7 + .align 4 linux_sparc_ni_syscall: sethi %hi(sys_ni_syscall), %l7 diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index 8328a3b78a44..4ee85051521a 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h @@ -18,6 +18,7 @@ extern int ncpus_probed; asmlinkage long sparc_clone(struct pt_regs *regs); asmlinkage long sparc_fork(struct pt_regs *regs); asmlinkage long sparc_vfork(struct pt_regs *regs); +asmlinkage long sparc_clone3(struct pt_regs *regs); #ifdef CONFIG_SPARC64 /* setup_64.c */ diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 49740450a685..2a8770369beb 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -29,7 +29,6 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, { unsigned int symidx; Elf_Sym *sym; - char *strtab; int i; for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) { @@ -39,7 +38,6 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, } } sym = (Elf_Sym *)sechdrs[symidx].sh_addr; - strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr; for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) { if (sym[i].st_shndx == SHN_UNDEF) { diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 0442ab00518d..d72fa0665943 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -12,19 +12,24 @@ #include <linux/sched/task.h> #include <linux/sched/task_stack.h> #include <linux/signal.h> +#include <linux/syscalls.h> #include "kernel.h" asmlinkage long sparc_fork(struct pt_regs *regs) { - unsigned long orig_i1 = regs->u_regs[UREG_I1]; + unsigned long orig_i1; long ret; struct kernel_clone_args args = { .exit_signal = SIGCHLD, - /* Reuse the parent's stack for the child. */ - .stack = regs->u_regs[UREG_FP], }; + synchronize_user_stack(); + + orig_i1 = regs->u_regs[UREG_I1]; + /* Reuse the parent's stack for the child. */ + args.stack = regs->u_regs[UREG_FP]; + ret = kernel_clone(&args); /* If we get an error and potentially restart the system @@ -40,16 +45,19 @@ asmlinkage long sparc_fork(struct pt_regs *regs) asmlinkage long sparc_vfork(struct pt_regs *regs) { - unsigned long orig_i1 = regs->u_regs[UREG_I1]; + unsigned long orig_i1; long ret; - struct kernel_clone_args args = { .flags = CLONE_VFORK | CLONE_VM, .exit_signal = SIGCHLD, - /* Reuse the parent's stack for the child. */ - .stack = regs->u_regs[UREG_FP], }; + synchronize_user_stack(); + + orig_i1 = regs->u_regs[UREG_I1]; + /* Reuse the parent's stack for the child. */ + args.stack = regs->u_regs[UREG_FP]; + ret = kernel_clone(&args); /* If we get an error and potentially restart the system @@ -65,15 +73,18 @@ asmlinkage long sparc_vfork(struct pt_regs *regs) asmlinkage long sparc_clone(struct pt_regs *regs) { - unsigned long orig_i1 = regs->u_regs[UREG_I1]; - unsigned int flags = lower_32_bits(regs->u_regs[UREG_I0]); + unsigned long orig_i1; + unsigned int flags; long ret; + struct kernel_clone_args args = {0}; - struct kernel_clone_args args = { - .flags = (flags & ~CSIGNAL), - .exit_signal = (flags & CSIGNAL), - .tls = regs->u_regs[UREG_I3], - }; + synchronize_user_stack(); + + orig_i1 = regs->u_regs[UREG_I1]; + flags = lower_32_bits(regs->u_regs[UREG_I0]); + args.flags = (flags & ~CSIGNAL); + args.exit_signal = (flags & CSIGNAL); + args.tls = regs->u_regs[UREG_I3]; #ifdef CONFIG_COMPAT if (test_thread_flag(TIF_32BIT)) { @@ -108,3 +119,16 @@ asmlinkage long sparc_clone(struct pt_regs *regs) return ret; } + +asmlinkage long sparc_clone3(struct pt_regs *regs) +{ + unsigned long sz; + struct clone_args __user *cl_args; + + synchronize_user_stack(); + + cl_args = (struct clone_args __user *)regs->u_regs[UREG_I0]; + sz = regs->u_regs[UREG_I1]; + + return sys_clone3(cl_args, sz); +} diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index 5a28c0e91bf1..dd8c6c02b0f1 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -247,6 +247,8 @@ clone_stackframe(struct sparc_stackf __user *dst, * Parent --> %o0 == childs pid, %o1 == 0 * Child --> %o0 == parents pid, %o1 == 1 * + * clone3() - Uses regular kernel return value conventions + * * NOTE: We have a separate fork kpsr/kwim because * the parent could change these values between * sys_fork invocation and when we reach here @@ -261,11 +263,11 @@ extern void ret_from_kernel_thread(void); int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { u64 clone_flags = args->flags; - unsigned long sp = args->stack; unsigned long tls = args->tls; struct thread_info *ti = task_thread_info(p); struct pt_regs *childregs, *regs = current_pt_regs(); char *new_stack; + unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP]; #ifndef CONFIG_SMP if(last_task_used_math == current) { @@ -350,13 +352,22 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) childregs->psr &= ~PSR_EF; clear_tsk_thread_flag(p, TIF_USEDFPU); #endif + /* Handle return value conventions */ + if (regs->u_regs[UREG_G1] == __NR_clone3) { + /* clone3() - use regular kernel return value convention */ + + /* Set the return value for the child. */ + childregs->u_regs[UREG_I0] = 0; + } else { + /* clone()/fork() - use SunOS return value convention */ - /* Set the return value for the child. */ - childregs->u_regs[UREG_I0] = current->pid; - childregs->u_regs[UREG_I1] = 1; + /* Set the return value for the child. */ + childregs->u_regs[UREG_I0] = current->pid; + childregs->u_regs[UREG_I1] = 1; - /* Set the return value for the parent. */ - regs->u_regs[UREG_I1] = 0; + /* Set the return value for the parent. */ + regs->u_regs[UREG_I1] = 0; + } if (clone_flags & CLONE_SETTLS) childregs->u_regs[UREG_G7] = tls; diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 25781923788a..e889da8e4835 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -564,17 +564,19 @@ barf: * under SunOS are nothing short of bletcherous: * Parent --> %o0 == childs pid, %o1 == 0 * Child --> %o0 == parents pid, %o1 == 1 + * + * clone3() - Uses regular kernel return value conventions */ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) { u64 clone_flags = args->flags; - unsigned long sp = args->stack; unsigned long tls = args->tls; struct thread_info *t = task_thread_info(p); struct pt_regs *regs = current_pt_regs(); struct sparc_stackf *parent_sf; unsigned long child_stack_sz; char *child_trap_frame; + unsigned long sp = args->stack ? args->stack : regs->u_regs[UREG_FP]; /* Calculate offset to stack_frame & pt_regs */ child_stack_sz = (STACKFRAME_SZ + TRACEREG_SZ); @@ -616,12 +618,25 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) if (t->utraps) t->utraps[0]++; - /* Set the return value for the child. */ - t->kregs->u_regs[UREG_I0] = current->pid; - t->kregs->u_regs[UREG_I1] = 1; + /* Handle return value conventions */ + if (regs->u_regs[UREG_G1] == __NR_clone3) { + /* clone3() - use regular kernel return value convention */ + + /* Set the return value for the child. */ + t->kregs->u_regs[UREG_I0] = 0; + + /* Clear g1 to indicate user thread */ + t->kregs->u_regs[UREG_G1] = 0; + } else { + /* clone()/fork() - use SunOS return value convention */ + + /* Set the return value for the child. */ + t->kregs->u_regs[UREG_I0] = current->pid; + t->kregs->u_regs[UREG_I1] = 1; - /* Set the second return value for the parent. */ - regs->u_regs[UREG_I1] = 0; + /* Set the second return value for the parent. */ + regs->u_regs[UREG_I1] = 0; + } if (clone_flags & CLONE_SETTLS) t->kregs->u_regs[UREG_G7] = tls; diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S index 0e8ab0602c36..96fe8763d70c 100644 --- a/arch/sparc/kernel/syscalls.S +++ b/arch/sparc/kernel/syscalls.S @@ -103,6 +103,12 @@ sys_clone: ba,pt %xcc, sparc_clone add %sp, PTREGS_OFF, %o0 + .align 32 +__sys_clone3: + flushw + ba,pt %xcc, sparc_clone3 + add %sp, PTREGS_OFF, %o0 + .globl ret_from_fork ret_from_fork: /* Clear current_thread_info()->new_child. */ @@ -113,6 +119,8 @@ ret_from_fork: brnz,pt %o0, ret_sys_call ldx [%g6 + TI_FLAGS], %l0 ldx [%sp + PTREGS_OFF + PT_V9_G1], %l1 + brz,pt %l1, ret_sys_call + nop call %l1 ldx [%sp + PTREGS_OFF + PT_V9_G2], %o0 ba,pt %xcc, ret_sys_call diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl index 39aa26b6a50b..c0307bb09892 100644 --- a/arch/sparc/kernel/syscalls/syscall.tbl +++ b/arch/sparc/kernel/syscalls/syscall.tbl @@ -480,7 +480,7 @@ 432 common fsmount sys_fsmount 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open -# 435 reserved for clone3 +435 common clone3 __sys_clone3 436 common close_range sys_close_range 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd diff --git a/arch/sparc/kernel/vio.c b/arch/sparc/kernel/vio.c index 1a1a9d6b8f2e..8c7dd72ef334 100644 --- a/arch/sparc/kernel/vio.c +++ b/arch/sparc/kernel/vio.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/string.h> #include <linux/irq.h> #include <linux/export.h> #include <linux/init.h> @@ -378,8 +379,7 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, * the parent doesn't require the MD node info. */ if (node_name != NULL) { - (void) snprintf(vdev->node_name, VIO_MAX_NAME_LEN, "%s", - node_name); + strscpy(vdev->node_name, node_name); err = mdesc_get_node_info(hp, mp, node_name, &vdev->md_node_info); diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index df9f7c444c39..ba19d23d4040 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -358,30 +358,24 @@ static void __init pud_huge_patch(void) bool __init arch_hugetlb_valid_size(unsigned long size) { unsigned int hugepage_shift = ilog2(size); - unsigned short hv_pgsz_idx; unsigned int hv_pgsz_mask; switch (hugepage_shift) { case HPAGE_16GB_SHIFT: hv_pgsz_mask = HV_PGSZ_MASK_16GB; - hv_pgsz_idx = HV_PGSZ_IDX_16GB; pud_huge_patch(); break; case HPAGE_2GB_SHIFT: hv_pgsz_mask = HV_PGSZ_MASK_2GB; - hv_pgsz_idx = HV_PGSZ_IDX_2GB; break; case HPAGE_256MB_SHIFT: hv_pgsz_mask = HV_PGSZ_MASK_256MB; - hv_pgsz_idx = HV_PGSZ_IDX_256MB; break; case HPAGE_SHIFT: hv_pgsz_mask = HV_PGSZ_MASK_4MB; - hv_pgsz_idx = HV_PGSZ_IDX_4MB; break; case HPAGE_64K_SHIFT: hv_pgsz_mask = HV_PGSZ_MASK_64K; - hv_pgsz_idx = HV_PGSZ_IDX_64K; break; default: hv_pgsz_mask = 0; |
