sys_sparc_32.c 5.23 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2
/* linux/arch/sparc/kernel/sys_sparc.c
Linus Torvalds's avatar
Linus Torvalds committed
3 4 5 6 7 8 9 10
 *
 * This file contains various random system calls that
 * have a non-standard calling sequence on the Linux/sparc
 * platform.
 */

#include <linux/errno.h>
#include <linux/types.h>
11
#include <linux/sched/signal.h>
12
#include <linux/sched/mm.h>
13
#include <linux/sched/debug.h>
Linus Torvalds's avatar
Linus Torvalds committed
14 15 16 17 18 19 20 21 22 23 24
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/syscalls.h>
#include <linux/mman.h>
#include <linux/utsname.h>
#include <linux/smp.h>
Adrian Bunk's avatar
Adrian Bunk committed
25
#include <linux/ipc.h>
Linus Torvalds's avatar
Linus Torvalds committed
26

27
#include <linux/uaccess.h>
28
#include <asm/unistd.h>
Linus Torvalds's avatar
Linus Torvalds committed
29

30 31
#include "systbls.h"

Linus Torvalds's avatar
Linus Torvalds committed
32 33 34 35 36
/* #define DEBUG_UNIMP_SYSCALL */

/* XXX Make this per-binary type, this way we can detect the type of
 * XXX a binary.  Every Sparc executable calls this very early on.
 */
37
SYSCALL_DEFINE0(getpagesize)
Linus Torvalds's avatar
Linus Torvalds committed
38 39 40 41 42 43
{
	return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */
}

unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
{
44
	struct vm_unmapped_area_info info;
Linus Torvalds's avatar
Linus Torvalds committed
45 46 47 48 49

	if (flags & MAP_FIXED) {
		/* We do not accept a shared mapping if it would violate
		 * cache aliasing constraints.
		 */
50 51
		if ((flags & MAP_SHARED) &&
		    ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
Linus Torvalds's avatar
Linus Torvalds committed
52 53 54 55 56 57 58 59 60 61
			return -EINVAL;
		return addr;
	}

	/* See asm-sparc/uaccess.h */
	if (len > TASK_SIZE - PAGE_SIZE)
		return -ENOMEM;
	if (!addr)
		addr = TASK_UNMAPPED_BASE;

62 63 64 65 66 67 68 69
	info.flags = 0;
	info.length = len;
	info.low_limit = addr;
	info.high_limit = TASK_SIZE;
	info.align_mask = (flags & MAP_SHARED) ?
		(PAGE_MASK & (SHMLBA - 1)) : 0;
	info.align_offset = pgoff << PAGE_SHIFT;
	return vm_unmapped_area(&info);
Linus Torvalds's avatar
Linus Torvalds committed
70 71 72 73 74 75
}

/*
 * sys_pipe() is the normal C calling standard for creating
 * a pipe. It's not the way unix traditionally does this, though.
 */
76
SYSCALL_DEFINE0(sparc_pipe)
Linus Torvalds's avatar
Linus Torvalds committed
77 78 79 80
{
	int fd[2];
	int error;

Ulrich Drepper's avatar
Ulrich Drepper committed
81
	error = do_pipe_flags(fd, 0);
Linus Torvalds's avatar
Linus Torvalds committed
82 83
	if (error)
		goto out;
84
	current_pt_regs()->u_regs[UREG_I1] = fd[1];
Linus Torvalds's avatar
Linus Torvalds committed
85 86 87 88 89
	error = fd[0];
out:
	return error;
}

90
int sparc_mmap_check(unsigned long addr, unsigned long len)
91 92 93 94 95 96 97 98
{
	/* See asm-sparc/uaccess.h */
	if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE)
		return -EINVAL;

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
99 100
/* Linux version of mmap */

101 102 103
SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
	unsigned long, prot, unsigned long, flags, unsigned long, fd,
	unsigned long, pgoff)
Linus Torvalds's avatar
Linus Torvalds committed
104 105 106
{
	/* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
	   we have. */
107 108
	return ksys_mmap_pgoff(addr, len, prot, flags, fd,
			       pgoff >> (PAGE_SHIFT - 12));
Linus Torvalds's avatar
Linus Torvalds committed
109 110
}

111 112 113
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
	unsigned long, prot, unsigned long, flags, unsigned long, fd,
	unsigned long, off)
Linus Torvalds's avatar
Linus Torvalds committed
114
{
Al Viro's avatar
Al Viro committed
115
	/* no alignment check? */
116
	return ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
Linus Torvalds's avatar
Linus Torvalds committed
117 118
}

119 120 121
SYSCALL_DEFINE5(sparc_remap_file_pages, unsigned long, start, unsigned long, size,
			   unsigned long, prot, unsigned long, pgoff,
			   unsigned long, flags)
Linus Torvalds's avatar
Linus Torvalds committed
122 123 124 125 126 127 128 129
{
	/* This works on an existing mmap so we don't need to validate
	 * the range as that was done at the original mmap call.
	 */
	return sys_remap_file_pages(start, size, prot,
				    (pgoff >> (PAGE_SHIFT - 12)), flags);
}

130
SYSCALL_DEFINE0(nis_syscall)
Linus Torvalds's avatar
Linus Torvalds committed
131 132
{
	static int count = 0;
133
	struct pt_regs *regs = current_pt_regs();
Linus Torvalds's avatar
Linus Torvalds committed
134 135 136 137

	if (count++ > 5)
		return -ENOSYS;
	printk ("%s[%d]: Unimplemented SPARC system call %d\n",
138
		current->comm, task_pid_nr(current), (int)regs->u_regs[1]);
Linus Torvalds's avatar
Linus Torvalds committed
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
#ifdef DEBUG_UNIMP_SYSCALL	
	show_regs (regs);
#endif
	return -ENOSYS;
}

/* #define DEBUG_SPARC_BREAKPOINT */

asmlinkage void
sparc_breakpoint (struct pt_regs *regs)
{
	siginfo_t info;

#ifdef DEBUG_SPARC_BREAKPOINT
        printk ("TRAP: Entering kernel PC=%x, nPC=%x\n", regs->pc, regs->npc);
#endif
	info.si_signo = SIGTRAP;
	info.si_errno = 0;
	info.si_code = TRAP_BRKPT;
	info.si_addr = (void __user *)regs->pc;
	info.si_trapno = 0;
	force_sig_info(SIGTRAP, &info, current);

#ifdef DEBUG_SPARC_BREAKPOINT
	printk ("TRAP: Returning to space: PC=%x nPC=%x\n", regs->pc, regs->npc);
#endif
}

167 168 169
SYSCALL_DEFINE3(sparc_sigaction, int, sig,
		struct old_sigaction __user *,act,
		struct old_sigaction __user *,oact)
Linus Torvalds's avatar
Linus Torvalds committed
170
{
171
	WARN_ON_ONCE(sig >= 0);
172
	return sys_sigaction(-sig, act, oact);
Linus Torvalds's avatar
Linus Torvalds committed
173 174
}

175 176 177 178 179
SYSCALL_DEFINE5(rt_sigaction, int, sig,
		 const struct sigaction __user *, act,
		 struct sigaction __user *, oact,
		 void __user *, restorer,
		 size_t, sigsetsize)
Linus Torvalds's avatar
Linus Torvalds committed
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
{
	struct k_sigaction new_ka, old_ka;
	int ret;

	/* XXX: Don't preclude handling different sized sigset_t's.  */
	if (sigsetsize != sizeof(sigset_t))
		return -EINVAL;

	if (act) {
		new_ka.ka_restorer = restorer;
		if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
			return -EFAULT;
	}

	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);

	if (!ret && oact) {
		if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
			return -EFAULT;
	}

	return ret;
}

204
SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len)
Linus Torvalds's avatar
Linus Torvalds committed
205
{
206
 	int nlen, err;
Linus Torvalds's avatar
Linus Torvalds committed
207
 	
208
	if (len < 0)
209 210
		return -EINVAL;

Linus Torvalds's avatar
Linus Torvalds committed
211 212
 	down_read(&uts_sem);
 	
213
	nlen = strlen(utsname()->domainname) + 1;
214 215 216
	err = -EINVAL;
	if (nlen > len)
		goto out;
217 218

	err = -EFAULT;
219
	if (!copy_to_user(name, utsname()->domainname, nlen))
220 221
		err = 0;

222
out:
Linus Torvalds's avatar
Linus Torvalds committed
223 224 225
	up_read(&uts_sem);
	return err;
}