Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  S390 version
0004  *    Copyright IBM Corp. 1999, 2000
0005  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
0006  *               Thomas Spatzier (tspat@de.ibm.com)
0007  *
0008  *  Derived from "arch/i386/kernel/sys_i386.c"
0009  *
0010  *  This file contains various random system calls that
0011  *  have a non-standard calling sequence on the Linux/s390
0012  *  platform.
0013  */
0014 
0015 #include <linux/errno.h>
0016 #include <linux/sched.h>
0017 #include <linux/mm.h>
0018 #include <linux/fs.h>
0019 #include <linux/smp.h>
0020 #include <linux/sem.h>
0021 #include <linux/msg.h>
0022 #include <linux/shm.h>
0023 #include <linux/stat.h>
0024 #include <linux/syscalls.h>
0025 #include <linux/mman.h>
0026 #include <linux/file.h>
0027 #include <linux/utsname.h>
0028 #include <linux/personality.h>
0029 #include <linux/unistd.h>
0030 #include <linux/ipc.h>
0031 #include <linux/uaccess.h>
0032 #include <linux/string.h>
0033 #include <linux/thread_info.h>
0034 #include <linux/entry-common.h>
0035 
0036 #include <asm/ptrace.h>
0037 #include <asm/vtime.h>
0038 
0039 #include "entry.h"
0040 
0041 /*
0042  * Perform the mmap() system call. Linux for S/390 isn't able to handle more
0043  * than 5 system call parameters, so this system call uses a memory block
0044  * for parameter passing.
0045  */
0046 
0047 struct s390_mmap_arg_struct {
0048     unsigned long addr;
0049     unsigned long len;
0050     unsigned long prot;
0051     unsigned long flags;
0052     unsigned long fd;
0053     unsigned long offset;
0054 };
0055 
0056 SYSCALL_DEFINE1(mmap2, struct s390_mmap_arg_struct __user *, arg)
0057 {
0058     struct s390_mmap_arg_struct a;
0059     int error = -EFAULT;
0060 
0061     if (copy_from_user(&a, arg, sizeof(a)))
0062         goto out;
0063     error = ksys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
0064 out:
0065     return error;
0066 }
0067 
0068 #ifdef CONFIG_SYSVIPC
0069 /*
0070  * sys_ipc() is the de-multiplexer for the SysV IPC calls.
0071  */
0072 SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second,
0073         unsigned long, third, void __user *, ptr)
0074 {
0075     if (call >> 16)
0076         return -EINVAL;
0077     /* The s390 sys_ipc variant has only five parameters instead of six
0078      * like the generic variant. The only difference is the handling of
0079      * the SEMTIMEDOP subcall where on s390 the third parameter is used
0080      * as a pointer to a struct timespec where the generic variant uses
0081      * the fifth parameter.
0082      * Therefore we can call the generic variant by simply passing the
0083      * third parameter also as fifth parameter.
0084      */
0085     return ksys_ipc(call, first, second, third, ptr, third);
0086 }
0087 #endif /* CONFIG_SYSVIPC */
0088 
0089 SYSCALL_DEFINE1(s390_personality, unsigned int, personality)
0090 {
0091     unsigned int ret = current->personality;
0092 
0093     if (personality(current->personality) == PER_LINUX32 &&
0094         personality(personality) == PER_LINUX)
0095         personality |= PER_LINUX32;
0096 
0097     if (personality != 0xffffffff)
0098         set_personality(personality);
0099 
0100     if (personality(ret) == PER_LINUX32)
0101         ret &= ~PER_LINUX32;
0102 
0103     return ret;
0104 }
0105 
0106 SYSCALL_DEFINE0(ni_syscall)
0107 {
0108     return -ENOSYS;
0109 }
0110 
0111 static void do_syscall(struct pt_regs *regs)
0112 {
0113     unsigned long nr;
0114 
0115     nr = regs->int_code & 0xffff;
0116     if (!nr) {
0117         nr = regs->gprs[1] & 0xffff;
0118         regs->int_code &= ~0xffffUL;
0119         regs->int_code |= nr;
0120     }
0121 
0122     regs->gprs[2] = nr;
0123 
0124     if (nr == __NR_restart_syscall && !(current->restart_block.arch_data & 1)) {
0125         regs->psw.addr = current->restart_block.arch_data;
0126         current->restart_block.arch_data = 1;
0127     }
0128     nr = syscall_enter_from_user_mode_work(regs, nr);
0129 
0130     /*
0131      * In the s390 ptrace ABI, both the syscall number and the return value
0132      * use gpr2. However, userspace puts the syscall number either in the
0133      * svc instruction itself, or uses gpr1. To make at least skipping syscalls
0134      * work, the ptrace code sets PIF_SYSCALL_RET_SET, which is checked here
0135      * and if set, the syscall will be skipped.
0136      */
0137 
0138     if (unlikely(test_and_clear_pt_regs_flag(regs, PIF_SYSCALL_RET_SET)))
0139         goto out;
0140     regs->gprs[2] = -ENOSYS;
0141     if (likely(nr >= NR_syscalls))
0142         goto out;
0143     do {
0144         regs->gprs[2] = current->thread.sys_call_table[nr](regs);
0145     } while (test_and_clear_pt_regs_flag(regs, PIF_EXECVE_PGSTE_RESTART));
0146 out:
0147     syscall_exit_to_user_mode_work(regs);
0148 }
0149 
0150 void noinstr __do_syscall(struct pt_regs *regs, int per_trap)
0151 {
0152     add_random_kstack_offset();
0153     enter_from_user_mode(regs);
0154     regs->psw = S390_lowcore.svc_old_psw;
0155     regs->int_code = S390_lowcore.svc_int_code;
0156     update_timer_sys();
0157     if (static_branch_likely(&cpu_has_bear))
0158         current->thread.last_break = regs->last_break;
0159 
0160     local_irq_enable();
0161     regs->orig_gpr2 = regs->gprs[2];
0162 
0163     if (per_trap)
0164         set_thread_flag(TIF_PER_TRAP);
0165 
0166     regs->flags = 0;
0167     set_pt_regs_flag(regs, PIF_SYSCALL);
0168     do_syscall(regs);
0169     exit_to_user_mode();
0170 }