162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* linux/arch/sparc64/kernel/sys_sparc.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This file contains various random system calls that 562306a36Sopenharmony_ci * have a non-standard calling sequence on the Linux/sparc 662306a36Sopenharmony_ci * platform. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/types.h> 1162306a36Sopenharmony_ci#include <linux/sched/signal.h> 1262306a36Sopenharmony_ci#include <linux/sched/mm.h> 1362306a36Sopenharmony_ci#include <linux/sched/debug.h> 1462306a36Sopenharmony_ci#include <linux/fs.h> 1562306a36Sopenharmony_ci#include <linux/file.h> 1662306a36Sopenharmony_ci#include <linux/mm.h> 1762306a36Sopenharmony_ci#include <linux/sem.h> 1862306a36Sopenharmony_ci#include <linux/msg.h> 1962306a36Sopenharmony_ci#include <linux/shm.h> 2062306a36Sopenharmony_ci#include <linux/stat.h> 2162306a36Sopenharmony_ci#include <linux/mman.h> 2262306a36Sopenharmony_ci#include <linux/utsname.h> 2362306a36Sopenharmony_ci#include <linux/smp.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/syscalls.h> 2662306a36Sopenharmony_ci#include <linux/ipc.h> 2762306a36Sopenharmony_ci#include <linux/personality.h> 2862306a36Sopenharmony_ci#include <linux/random.h> 2962306a36Sopenharmony_ci#include <linux/export.h> 3062306a36Sopenharmony_ci#include <linux/context_tracking.h> 3162306a36Sopenharmony_ci#include <linux/timex.h> 3262306a36Sopenharmony_ci#include <linux/uaccess.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <asm/utrap.h> 3562306a36Sopenharmony_ci#include <asm/unistd.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "entry.h" 3862306a36Sopenharmony_ci#include "kernel.h" 3962306a36Sopenharmony_ci#include "systbls.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* #define DEBUG_UNIMP_SYSCALL */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciSYSCALL_DEFINE0(getpagesize) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci return PAGE_SIZE; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* Does addr --> addr+len fall within 4GB of the VA-space hole or 4962306a36Sopenharmony_ci * overflow past the end of the 64-bit address space? 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistatic inline int invalid_64bit_range(unsigned long addr, unsigned long len) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci unsigned long va_exclude_start, va_exclude_end; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci va_exclude_start = VA_EXCLUDE_START; 5662306a36Sopenharmony_ci va_exclude_end = VA_EXCLUDE_END; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (unlikely(len >= va_exclude_start)) 5962306a36Sopenharmony_ci return 1; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (unlikely((addr + len) < addr)) 6262306a36Sopenharmony_ci return 1; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (unlikely((addr >= va_exclude_start && addr < va_exclude_end) || 6562306a36Sopenharmony_ci ((addr + len) >= va_exclude_start && 6662306a36Sopenharmony_ci (addr + len) < va_exclude_end))) 6762306a36Sopenharmony_ci return 1; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* These functions differ from the default implementations in 7362306a36Sopenharmony_ci * mm/mmap.c in two ways: 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * 1) For file backed MAP_SHARED mmap()'s we D-cache color align, 7662306a36Sopenharmony_ci * for fixed such mappings we just validate what the user gave us. 7762306a36Sopenharmony_ci * 2) For 64-bit tasks we avoid mapping anything within 4GB of 7862306a36Sopenharmony_ci * the spitfire/niagara VA-hole. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic inline unsigned long COLOR_ALIGN(unsigned long addr, 8262306a36Sopenharmony_ci unsigned long pgoff) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci unsigned long base = (addr+SHMLBA-1)&~(SHMLBA-1); 8562306a36Sopenharmony_ci unsigned long off = (pgoff<<PAGE_SHIFT) & (SHMLBA-1); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return base + off; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciunsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct mm_struct *mm = current->mm; 9362306a36Sopenharmony_ci struct vm_area_struct * vma; 9462306a36Sopenharmony_ci unsigned long task_size = TASK_SIZE; 9562306a36Sopenharmony_ci int do_color_align; 9662306a36Sopenharmony_ci struct vm_unmapped_area_info info; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (flags & MAP_FIXED) { 9962306a36Sopenharmony_ci /* We do not accept a shared mapping if it would violate 10062306a36Sopenharmony_ci * cache aliasing constraints. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci if ((flags & MAP_SHARED) && 10362306a36Sopenharmony_ci ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) 10462306a36Sopenharmony_ci return -EINVAL; 10562306a36Sopenharmony_ci return addr; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (test_thread_flag(TIF_32BIT)) 10962306a36Sopenharmony_ci task_size = STACK_TOP32; 11062306a36Sopenharmony_ci if (unlikely(len > task_size || len >= VA_EXCLUDE_START)) 11162306a36Sopenharmony_ci return -ENOMEM; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci do_color_align = 0; 11462306a36Sopenharmony_ci if (filp || (flags & MAP_SHARED)) 11562306a36Sopenharmony_ci do_color_align = 1; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (addr) { 11862306a36Sopenharmony_ci if (do_color_align) 11962306a36Sopenharmony_ci addr = COLOR_ALIGN(addr, pgoff); 12062306a36Sopenharmony_ci else 12162306a36Sopenharmony_ci addr = PAGE_ALIGN(addr); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci vma = find_vma(mm, addr); 12462306a36Sopenharmony_ci if (task_size - len >= addr && 12562306a36Sopenharmony_ci (!vma || addr + len <= vm_start_gap(vma))) 12662306a36Sopenharmony_ci return addr; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci info.flags = 0; 13062306a36Sopenharmony_ci info.length = len; 13162306a36Sopenharmony_ci info.low_limit = TASK_UNMAPPED_BASE; 13262306a36Sopenharmony_ci info.high_limit = min(task_size, VA_EXCLUDE_START); 13362306a36Sopenharmony_ci info.align_mask = do_color_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; 13462306a36Sopenharmony_ci info.align_offset = pgoff << PAGE_SHIFT; 13562306a36Sopenharmony_ci addr = vm_unmapped_area(&info); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if ((addr & ~PAGE_MASK) && task_size > VA_EXCLUDE_END) { 13862306a36Sopenharmony_ci VM_BUG_ON(addr != -ENOMEM); 13962306a36Sopenharmony_ci info.low_limit = VA_EXCLUDE_END; 14062306a36Sopenharmony_ci info.high_limit = task_size; 14162306a36Sopenharmony_ci addr = vm_unmapped_area(&info); 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return addr; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciunsigned long 14862306a36Sopenharmony_ciarch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, 14962306a36Sopenharmony_ci const unsigned long len, const unsigned long pgoff, 15062306a36Sopenharmony_ci const unsigned long flags) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct vm_area_struct *vma; 15362306a36Sopenharmony_ci struct mm_struct *mm = current->mm; 15462306a36Sopenharmony_ci unsigned long task_size = STACK_TOP32; 15562306a36Sopenharmony_ci unsigned long addr = addr0; 15662306a36Sopenharmony_ci int do_color_align; 15762306a36Sopenharmony_ci struct vm_unmapped_area_info info; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* This should only ever run for 32-bit processes. */ 16062306a36Sopenharmony_ci BUG_ON(!test_thread_flag(TIF_32BIT)); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (flags & MAP_FIXED) { 16362306a36Sopenharmony_ci /* We do not accept a shared mapping if it would violate 16462306a36Sopenharmony_ci * cache aliasing constraints. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci if ((flags & MAP_SHARED) && 16762306a36Sopenharmony_ci ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) 16862306a36Sopenharmony_ci return -EINVAL; 16962306a36Sopenharmony_ci return addr; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (unlikely(len > task_size)) 17362306a36Sopenharmony_ci return -ENOMEM; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci do_color_align = 0; 17662306a36Sopenharmony_ci if (filp || (flags & MAP_SHARED)) 17762306a36Sopenharmony_ci do_color_align = 1; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* requesting a specific address */ 18062306a36Sopenharmony_ci if (addr) { 18162306a36Sopenharmony_ci if (do_color_align) 18262306a36Sopenharmony_ci addr = COLOR_ALIGN(addr, pgoff); 18362306a36Sopenharmony_ci else 18462306a36Sopenharmony_ci addr = PAGE_ALIGN(addr); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci vma = find_vma(mm, addr); 18762306a36Sopenharmony_ci if (task_size - len >= addr && 18862306a36Sopenharmony_ci (!vma || addr + len <= vm_start_gap(vma))) 18962306a36Sopenharmony_ci return addr; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci info.flags = VM_UNMAPPED_AREA_TOPDOWN; 19362306a36Sopenharmony_ci info.length = len; 19462306a36Sopenharmony_ci info.low_limit = PAGE_SIZE; 19562306a36Sopenharmony_ci info.high_limit = mm->mmap_base; 19662306a36Sopenharmony_ci info.align_mask = do_color_align ? (PAGE_MASK & (SHMLBA - 1)) : 0; 19762306a36Sopenharmony_ci info.align_offset = pgoff << PAGE_SHIFT; 19862306a36Sopenharmony_ci addr = vm_unmapped_area(&info); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * A failed mmap() very likely causes application failure, 20262306a36Sopenharmony_ci * so fall back to the bottom-up function here. This scenario 20362306a36Sopenharmony_ci * can happen with large stack limits and large mmap() 20462306a36Sopenharmony_ci * allocations. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci if (addr & ~PAGE_MASK) { 20762306a36Sopenharmony_ci VM_BUG_ON(addr != -ENOMEM); 20862306a36Sopenharmony_ci info.flags = 0; 20962306a36Sopenharmony_ci info.low_limit = TASK_UNMAPPED_BASE; 21062306a36Sopenharmony_ci info.high_limit = STACK_TOP32; 21162306a36Sopenharmony_ci addr = vm_unmapped_area(&info); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return addr; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* Try to align mapping such that we align it as much as possible. */ 21862306a36Sopenharmony_ciunsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci unsigned long align_goal, addr = -ENOMEM; 22162306a36Sopenharmony_ci unsigned long (*get_area)(struct file *, unsigned long, 22262306a36Sopenharmony_ci unsigned long, unsigned long, unsigned long); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci get_area = current->mm->get_unmapped_area; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (flags & MAP_FIXED) { 22762306a36Sopenharmony_ci /* Ok, don't mess with it. */ 22862306a36Sopenharmony_ci return get_area(NULL, orig_addr, len, pgoff, flags); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci flags &= ~MAP_SHARED; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci align_goal = PAGE_SIZE; 23362306a36Sopenharmony_ci if (len >= (4UL * 1024 * 1024)) 23462306a36Sopenharmony_ci align_goal = (4UL * 1024 * 1024); 23562306a36Sopenharmony_ci else if (len >= (512UL * 1024)) 23662306a36Sopenharmony_ci align_goal = (512UL * 1024); 23762306a36Sopenharmony_ci else if (len >= (64UL * 1024)) 23862306a36Sopenharmony_ci align_goal = (64UL * 1024); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci do { 24162306a36Sopenharmony_ci addr = get_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); 24262306a36Sopenharmony_ci if (!(addr & ~PAGE_MASK)) { 24362306a36Sopenharmony_ci addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL); 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (align_goal == (4UL * 1024 * 1024)) 24862306a36Sopenharmony_ci align_goal = (512UL * 1024); 24962306a36Sopenharmony_ci else if (align_goal == (512UL * 1024)) 25062306a36Sopenharmony_ci align_goal = (64UL * 1024); 25162306a36Sopenharmony_ci else 25262306a36Sopenharmony_ci align_goal = PAGE_SIZE; 25362306a36Sopenharmony_ci } while ((addr & ~PAGE_MASK) && align_goal > PAGE_SIZE); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Mapping is smaller than 64K or larger areas could not 25662306a36Sopenharmony_ci * be obtained. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci if (addr & ~PAGE_MASK) 25962306a36Sopenharmony_ci addr = get_area(NULL, orig_addr, len, pgoff, flags); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return addr; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ciEXPORT_SYMBOL(get_fb_unmapped_area); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci/* Essentially the same as PowerPC. */ 26662306a36Sopenharmony_cistatic unsigned long mmap_rnd(void) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci unsigned long rnd = 0UL; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (current->flags & PF_RANDOMIZE) { 27162306a36Sopenharmony_ci unsigned long val = get_random_long(); 27262306a36Sopenharmony_ci if (test_thread_flag(TIF_32BIT)) 27362306a36Sopenharmony_ci rnd = (val % (1UL << (23UL-PAGE_SHIFT))); 27462306a36Sopenharmony_ci else 27562306a36Sopenharmony_ci rnd = (val % (1UL << (30UL-PAGE_SHIFT))); 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci return rnd << PAGE_SHIFT; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_civoid arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci unsigned long random_factor = mmap_rnd(); 28362306a36Sopenharmony_ci unsigned long gap; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* 28662306a36Sopenharmony_ci * Fall back to the standard layout if the personality 28762306a36Sopenharmony_ci * bit is set, or if the expected stack growth is unlimited: 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci gap = rlim_stack->rlim_cur; 29062306a36Sopenharmony_ci if (!test_thread_flag(TIF_32BIT) || 29162306a36Sopenharmony_ci (current->personality & ADDR_COMPAT_LAYOUT) || 29262306a36Sopenharmony_ci gap == RLIM_INFINITY || 29362306a36Sopenharmony_ci sysctl_legacy_va_layout) { 29462306a36Sopenharmony_ci mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; 29562306a36Sopenharmony_ci mm->get_unmapped_area = arch_get_unmapped_area; 29662306a36Sopenharmony_ci } else { 29762306a36Sopenharmony_ci /* We know it's 32-bit */ 29862306a36Sopenharmony_ci unsigned long task_size = STACK_TOP32; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (gap < 128 * 1024 * 1024) 30162306a36Sopenharmony_ci gap = 128 * 1024 * 1024; 30262306a36Sopenharmony_ci if (gap > (task_size / 6 * 5)) 30362306a36Sopenharmony_ci gap = (task_size / 6 * 5); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci mm->mmap_base = PAGE_ALIGN(task_size - gap - random_factor); 30662306a36Sopenharmony_ci mm->get_unmapped_area = arch_get_unmapped_area_topdown; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* 31162306a36Sopenharmony_ci * sys_pipe() is the normal C calling standard for creating 31262306a36Sopenharmony_ci * a pipe. It's not the way unix traditionally does this, though. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ciSYSCALL_DEFINE0(sparc_pipe) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci int fd[2]; 31762306a36Sopenharmony_ci int error; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci error = do_pipe_flags(fd, 0); 32062306a36Sopenharmony_ci if (error) 32162306a36Sopenharmony_ci goto out; 32262306a36Sopenharmony_ci current_pt_regs()->u_regs[UREG_I1] = fd[1]; 32362306a36Sopenharmony_ci error = fd[0]; 32462306a36Sopenharmony_ciout: 32562306a36Sopenharmony_ci return error; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci/* 32962306a36Sopenharmony_ci * sys_ipc() is the de-multiplexer for the SysV IPC calls.. 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * This is really horribly ugly. 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ciSYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second, 33562306a36Sopenharmony_ci unsigned long, third, void __user *, ptr, long, fifth) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci long err; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_SYSVIPC)) 34062306a36Sopenharmony_ci return -ENOSYS; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* No need for backward compatibility. We can start fresh... */ 34362306a36Sopenharmony_ci if (call <= SEMTIMEDOP) { 34462306a36Sopenharmony_ci switch (call) { 34562306a36Sopenharmony_ci case SEMOP: 34662306a36Sopenharmony_ci err = ksys_semtimedop(first, ptr, 34762306a36Sopenharmony_ci (unsigned int)second, NULL); 34862306a36Sopenharmony_ci goto out; 34962306a36Sopenharmony_ci case SEMTIMEDOP: 35062306a36Sopenharmony_ci err = ksys_semtimedop(first, ptr, (unsigned int)second, 35162306a36Sopenharmony_ci (const struct __kernel_timespec __user *) 35262306a36Sopenharmony_ci (unsigned long) fifth); 35362306a36Sopenharmony_ci goto out; 35462306a36Sopenharmony_ci case SEMGET: 35562306a36Sopenharmony_ci err = ksys_semget(first, (int)second, (int)third); 35662306a36Sopenharmony_ci goto out; 35762306a36Sopenharmony_ci case SEMCTL: { 35862306a36Sopenharmony_ci err = ksys_old_semctl(first, second, 35962306a36Sopenharmony_ci (int)third | IPC_64, 36062306a36Sopenharmony_ci (unsigned long) ptr); 36162306a36Sopenharmony_ci goto out; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci default: 36462306a36Sopenharmony_ci err = -ENOSYS; 36562306a36Sopenharmony_ci goto out; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci if (call <= MSGCTL) { 36962306a36Sopenharmony_ci switch (call) { 37062306a36Sopenharmony_ci case MSGSND: 37162306a36Sopenharmony_ci err = ksys_msgsnd(first, ptr, (size_t)second, 37262306a36Sopenharmony_ci (int)third); 37362306a36Sopenharmony_ci goto out; 37462306a36Sopenharmony_ci case MSGRCV: 37562306a36Sopenharmony_ci err = ksys_msgrcv(first, ptr, (size_t)second, fifth, 37662306a36Sopenharmony_ci (int)third); 37762306a36Sopenharmony_ci goto out; 37862306a36Sopenharmony_ci case MSGGET: 37962306a36Sopenharmony_ci err = ksys_msgget((key_t)first, (int)second); 38062306a36Sopenharmony_ci goto out; 38162306a36Sopenharmony_ci case MSGCTL: 38262306a36Sopenharmony_ci err = ksys_old_msgctl(first, (int)second | IPC_64, ptr); 38362306a36Sopenharmony_ci goto out; 38462306a36Sopenharmony_ci default: 38562306a36Sopenharmony_ci err = -ENOSYS; 38662306a36Sopenharmony_ci goto out; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci if (call <= SHMCTL) { 39062306a36Sopenharmony_ci switch (call) { 39162306a36Sopenharmony_ci case SHMAT: { 39262306a36Sopenharmony_ci ulong raddr; 39362306a36Sopenharmony_ci err = do_shmat(first, ptr, (int)second, &raddr, SHMLBA); 39462306a36Sopenharmony_ci if (!err) { 39562306a36Sopenharmony_ci if (put_user(raddr, 39662306a36Sopenharmony_ci (ulong __user *) third)) 39762306a36Sopenharmony_ci err = -EFAULT; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci goto out; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci case SHMDT: 40262306a36Sopenharmony_ci err = ksys_shmdt(ptr); 40362306a36Sopenharmony_ci goto out; 40462306a36Sopenharmony_ci case SHMGET: 40562306a36Sopenharmony_ci err = ksys_shmget(first, (size_t)second, (int)third); 40662306a36Sopenharmony_ci goto out; 40762306a36Sopenharmony_ci case SHMCTL: 40862306a36Sopenharmony_ci err = ksys_old_shmctl(first, (int)second | IPC_64, ptr); 40962306a36Sopenharmony_ci goto out; 41062306a36Sopenharmony_ci default: 41162306a36Sopenharmony_ci err = -ENOSYS; 41262306a36Sopenharmony_ci goto out; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci } else { 41562306a36Sopenharmony_ci err = -ENOSYS; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ciout: 41862306a36Sopenharmony_ci return err; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ciSYSCALL_DEFINE1(sparc64_personality, unsigned long, personality) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci long ret; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (personality(current->personality) == PER_LINUX32 && 42662306a36Sopenharmony_ci personality(personality) == PER_LINUX) 42762306a36Sopenharmony_ci personality |= PER_LINUX32; 42862306a36Sopenharmony_ci ret = sys_personality(personality); 42962306a36Sopenharmony_ci if (personality(ret) == PER_LINUX32) 43062306a36Sopenharmony_ci ret &= ~PER_LINUX32; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return ret; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ciint sparc_mmap_check(unsigned long addr, unsigned long len) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci if (test_thread_flag(TIF_32BIT)) { 43862306a36Sopenharmony_ci if (len >= STACK_TOP32) 43962306a36Sopenharmony_ci return -EINVAL; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (addr > STACK_TOP32 - len) 44262306a36Sopenharmony_ci return -EINVAL; 44362306a36Sopenharmony_ci } else { 44462306a36Sopenharmony_ci if (len >= VA_EXCLUDE_START) 44562306a36Sopenharmony_ci return -EINVAL; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (invalid_64bit_range(addr, len)) 44862306a36Sopenharmony_ci return -EINVAL; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci return 0; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/* Linux version of mmap */ 45562306a36Sopenharmony_ciSYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, 45662306a36Sopenharmony_ci unsigned long, prot, unsigned long, flags, unsigned long, fd, 45762306a36Sopenharmony_ci unsigned long, off) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci unsigned long retval = -EINVAL; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if ((off + PAGE_ALIGN(len)) < off) 46262306a36Sopenharmony_ci goto out; 46362306a36Sopenharmony_ci if (off & ~PAGE_MASK) 46462306a36Sopenharmony_ci goto out; 46562306a36Sopenharmony_ci retval = ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); 46662306a36Sopenharmony_ciout: 46762306a36Sopenharmony_ci return retval; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ciSYSCALL_DEFINE2(64_munmap, unsigned long, addr, size_t, len) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci if (invalid_64bit_range(addr, len)) 47362306a36Sopenharmony_ci return -EINVAL; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return vm_munmap(addr, len); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciSYSCALL_DEFINE5(64_mremap, unsigned long, addr, unsigned long, old_len, 47962306a36Sopenharmony_ci unsigned long, new_len, unsigned long, flags, 48062306a36Sopenharmony_ci unsigned long, new_addr) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci if (test_thread_flag(TIF_32BIT)) 48362306a36Sopenharmony_ci return -EINVAL; 48462306a36Sopenharmony_ci return sys_mremap(addr, old_len, new_len, flags, new_addr); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ciSYSCALL_DEFINE0(nis_syscall) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci static int count; 49062306a36Sopenharmony_ci struct pt_regs *regs = current_pt_regs(); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Don't make the system unusable, if someone goes stuck */ 49362306a36Sopenharmony_ci if (count++ > 5) 49462306a36Sopenharmony_ci return -ENOSYS; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]); 49762306a36Sopenharmony_ci#ifdef DEBUG_UNIMP_SYSCALL 49862306a36Sopenharmony_ci show_regs (regs); 49962306a36Sopenharmony_ci#endif 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return -ENOSYS; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/* #define DEBUG_SPARC_BREAKPOINT */ 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ciasmlinkage void sparc_breakpoint(struct pt_regs *regs) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci enum ctx_state prev_state = exception_enter(); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (test_thread_flag(TIF_32BIT)) { 51162306a36Sopenharmony_ci regs->tpc &= 0xffffffff; 51262306a36Sopenharmony_ci regs->tnpc &= 0xffffffff; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci#ifdef DEBUG_SPARC_BREAKPOINT 51562306a36Sopenharmony_ci printk ("TRAP: Entering kernel PC=%lx, nPC=%lx\n", regs->tpc, regs->tnpc); 51662306a36Sopenharmony_ci#endif 51762306a36Sopenharmony_ci force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->tpc); 51862306a36Sopenharmony_ci#ifdef DEBUG_SPARC_BREAKPOINT 51962306a36Sopenharmony_ci printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc); 52062306a36Sopenharmony_ci#endif 52162306a36Sopenharmony_ci exception_exit(prev_state); 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ciSYSCALL_DEFINE2(getdomainname, char __user *, name, int, len) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci int nlen, err; 52762306a36Sopenharmony_ci char tmp[__NEW_UTS_LEN + 1]; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (len < 0) 53062306a36Sopenharmony_ci return -EINVAL; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci down_read(&uts_sem); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci nlen = strlen(utsname()->domainname) + 1; 53562306a36Sopenharmony_ci err = -EINVAL; 53662306a36Sopenharmony_ci if (nlen > len) 53762306a36Sopenharmony_ci goto out_unlock; 53862306a36Sopenharmony_ci memcpy(tmp, utsname()->domainname, nlen); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci up_read(&uts_sem); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (copy_to_user(name, tmp, nlen)) 54362306a36Sopenharmony_ci return -EFAULT; 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ciout_unlock: 54762306a36Sopenharmony_ci up_read(&uts_sem); 54862306a36Sopenharmony_ci return err; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ciSYSCALL_DEFINE1(sparc_adjtimex, struct __kernel_timex __user *, txc_p) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct __kernel_timex txc; 55462306a36Sopenharmony_ci struct __kernel_old_timeval *tv = (void *)&txc.time; 55562306a36Sopenharmony_ci int ret; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* Copy the user data space into the kernel copy 55862306a36Sopenharmony_ci * structure. But bear in mind that the structures 55962306a36Sopenharmony_ci * may change 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci if (copy_from_user(&txc, txc_p, sizeof(txc))) 56262306a36Sopenharmony_ci return -EFAULT; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* 56562306a36Sopenharmony_ci * override for sparc64 specific timeval type: tv_usec 56662306a36Sopenharmony_ci * is 32 bit wide instead of 64-bit in __kernel_timex 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_ci txc.time.tv_usec = tv->tv_usec; 56962306a36Sopenharmony_ci ret = do_adjtimex(&txc); 57062306a36Sopenharmony_ci tv->tv_usec = txc.time.tv_usec; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return copy_to_user(txc_p, &txc, sizeof(txc)) ? -EFAULT : ret; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ciSYSCALL_DEFINE2(sparc_clock_adjtime, const clockid_t, which_clock, 57662306a36Sopenharmony_ci struct __kernel_timex __user *, txc_p) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct __kernel_timex txc; 57962306a36Sopenharmony_ci struct __kernel_old_timeval *tv = (void *)&txc.time; 58062306a36Sopenharmony_ci int ret; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_POSIX_TIMERS)) { 58362306a36Sopenharmony_ci pr_err_once("process %d (%s) attempted a POSIX timer syscall " 58462306a36Sopenharmony_ci "while CONFIG_POSIX_TIMERS is not set\n", 58562306a36Sopenharmony_ci current->pid, current->comm); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return -ENOSYS; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* Copy the user data space into the kernel copy 59162306a36Sopenharmony_ci * structure. But bear in mind that the structures 59262306a36Sopenharmony_ci * may change 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci if (copy_from_user(&txc, txc_p, sizeof(txc))) 59562306a36Sopenharmony_ci return -EFAULT; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* 59862306a36Sopenharmony_ci * override for sparc64 specific timeval type: tv_usec 59962306a36Sopenharmony_ci * is 32 bit wide instead of 64-bit in __kernel_timex 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ci txc.time.tv_usec = tv->tv_usec; 60262306a36Sopenharmony_ci ret = do_clock_adjtime(which_clock, &txc); 60362306a36Sopenharmony_ci tv->tv_usec = txc.time.tv_usec; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return copy_to_user(txc_p, &txc, sizeof(txc)) ? -EFAULT : ret; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ciSYSCALL_DEFINE5(utrap_install, utrap_entry_t, type, 60962306a36Sopenharmony_ci utrap_handler_t, new_p, utrap_handler_t, new_d, 61062306a36Sopenharmony_ci utrap_handler_t __user *, old_p, 61162306a36Sopenharmony_ci utrap_handler_t __user *, old_d) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31) 61462306a36Sopenharmony_ci return -EINVAL; 61562306a36Sopenharmony_ci if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) { 61662306a36Sopenharmony_ci if (old_p) { 61762306a36Sopenharmony_ci if (!current_thread_info()->utraps) { 61862306a36Sopenharmony_ci if (put_user(NULL, old_p)) 61962306a36Sopenharmony_ci return -EFAULT; 62062306a36Sopenharmony_ci } else { 62162306a36Sopenharmony_ci if (put_user((utrap_handler_t)(current_thread_info()->utraps[type]), old_p)) 62262306a36Sopenharmony_ci return -EFAULT; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci if (old_d) { 62662306a36Sopenharmony_ci if (put_user(NULL, old_d)) 62762306a36Sopenharmony_ci return -EFAULT; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci return 0; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci if (!current_thread_info()->utraps) { 63262306a36Sopenharmony_ci current_thread_info()->utraps = 63362306a36Sopenharmony_ci kcalloc(UT_TRAP_INSTRUCTION_31 + 1, sizeof(long), 63462306a36Sopenharmony_ci GFP_KERNEL); 63562306a36Sopenharmony_ci if (!current_thread_info()->utraps) 63662306a36Sopenharmony_ci return -ENOMEM; 63762306a36Sopenharmony_ci current_thread_info()->utraps[0] = 1; 63862306a36Sopenharmony_ci } else { 63962306a36Sopenharmony_ci if ((utrap_handler_t)current_thread_info()->utraps[type] != new_p && 64062306a36Sopenharmony_ci current_thread_info()->utraps[0] > 1) { 64162306a36Sopenharmony_ci unsigned long *p = current_thread_info()->utraps; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci current_thread_info()->utraps = 64462306a36Sopenharmony_ci kmalloc_array(UT_TRAP_INSTRUCTION_31 + 1, 64562306a36Sopenharmony_ci sizeof(long), 64662306a36Sopenharmony_ci GFP_KERNEL); 64762306a36Sopenharmony_ci if (!current_thread_info()->utraps) { 64862306a36Sopenharmony_ci current_thread_info()->utraps = p; 64962306a36Sopenharmony_ci return -ENOMEM; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci p[0]--; 65262306a36Sopenharmony_ci current_thread_info()->utraps[0] = 1; 65362306a36Sopenharmony_ci memcpy(current_thread_info()->utraps+1, p+1, 65462306a36Sopenharmony_ci UT_TRAP_INSTRUCTION_31*sizeof(long)); 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci if (old_p) { 65862306a36Sopenharmony_ci if (put_user((utrap_handler_t)(current_thread_info()->utraps[type]), old_p)) 65962306a36Sopenharmony_ci return -EFAULT; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci if (old_d) { 66262306a36Sopenharmony_ci if (put_user(NULL, old_d)) 66362306a36Sopenharmony_ci return -EFAULT; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci current_thread_info()->utraps[type] = (long)new_p; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ciSYSCALL_DEFINE1(memory_ordering, unsigned long, model) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct pt_regs *regs = current_pt_regs(); 67362306a36Sopenharmony_ci if (model >= 3) 67462306a36Sopenharmony_ci return -EINVAL; 67562306a36Sopenharmony_ci regs->tstate = (regs->tstate & ~TSTATE_MM) | (model << 14); 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ciSYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, 68062306a36Sopenharmony_ci struct sigaction __user *, oact, void __user *, restorer, 68162306a36Sopenharmony_ci size_t, sigsetsize) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct k_sigaction new_ka, old_ka; 68462306a36Sopenharmony_ci int ret; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* XXX: Don't preclude handling different sized sigset_t's. */ 68762306a36Sopenharmony_ci if (sigsetsize != sizeof(sigset_t)) 68862306a36Sopenharmony_ci return -EINVAL; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (act) { 69162306a36Sopenharmony_ci new_ka.ka_restorer = restorer; 69262306a36Sopenharmony_ci if (copy_from_user(&new_ka.sa, act, sizeof(*act))) 69362306a36Sopenharmony_ci return -EFAULT; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (!ret && oact) { 69962306a36Sopenharmony_ci if (copy_to_user(oact, &old_ka.sa, sizeof(*oact))) 70062306a36Sopenharmony_ci return -EFAULT; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return ret; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ciSYSCALL_DEFINE0(kern_features) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci return KERN_FEATURE_MIXED_MODE_STACK; 70962306a36Sopenharmony_ci} 710