Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 | 2 | /* |
30286ef6 | 3 | * Implementation of various system calls for Linux/PowerPC |
1da177e4 | 4 | * |
1da177e4 LT |
5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
6 | * | |
7 | * Derived from "arch/i386/kernel/sys_i386.c" | |
8 | * Adapted from the i386 version by Gary Thomas | |
9 | * Modified by Cort Dougan (cort@cs.nmt.edu) | |
10 | * and Paul Mackerras (paulus@cs.anu.edu.au). | |
11 | * | |
12 | * This file contains various random system calls that | |
13 | * have a non-standard calling sequence on the Linux/PPC | |
14 | * platform. | |
1da177e4 LT |
15 | */ |
16 | ||
17 | #include <linux/errno.h> | |
18 | #include <linux/sched.h> | |
19 | #include <linux/syscalls.h> | |
20 | #include <linux/mm.h> | |
4e950f6f | 21 | #include <linux/fs.h> |
1da177e4 | 22 | #include <linux/smp.h> |
1da177e4 LT |
23 | #include <linux/sem.h> |
24 | #include <linux/msg.h> | |
25 | #include <linux/shm.h> | |
26 | #include <linux/stat.h> | |
27 | #include <linux/mman.h> | |
28 | #include <linux/sys.h> | |
29 | #include <linux/ipc.h> | |
30 | #include <linux/utsname.h> | |
31 | #include <linux/file.h> | |
1da177e4 LT |
32 | #include <linux/personality.h> |
33 | ||
7c0f6ba6 | 34 | #include <linux/uaccess.h> |
a7f31841 | 35 | #include <asm/syscalls.h> |
1da177e4 LT |
36 | #include <asm/time.h> |
37 | #include <asm/unistd.h> | |
0545d543 | 38 | #include <asm/asm-prototypes.h> |
1da177e4 | 39 | |
9c355917 | 40 | static inline long do_mmap2(unsigned long addr, size_t len, |
30286ef6 PM |
41 | unsigned long prot, unsigned long flags, |
42 | unsigned long fd, unsigned long off, int shift) | |
1da177e4 | 43 | { |
9c355917 | 44 | long ret = -EINVAL; |
1da177e4 | 45 | |
9035cf9a | 46 | if (!arch_validate_prot(prot, addr)) |
ef3d3246 DK |
47 | goto out; |
48 | ||
30286ef6 PM |
49 | if (shift) { |
50 | if (off & ((1 << shift) - 1)) | |
51 | goto out; | |
52 | off >>= shift; | |
53 | } | |
30286ef6 | 54 | |
a90f590a | 55 | ret = ksys_mmap_pgoff(addr, len, prot, flags, fd, off); |
1da177e4 LT |
56 | out: |
57 | return ret; | |
58 | } | |
59 | ||
9c355917 BS |
60 | SYSCALL_DEFINE6(mmap2, unsigned long, addr, size_t, len, |
61 | unsigned long, prot, unsigned long, flags, | |
62 | unsigned long, fd, unsigned long, pgoff) | |
30286ef6 PM |
63 | { |
64 | return do_mmap2(addr, len, prot, flags, fd, pgoff, PAGE_SHIFT-12); | |
65 | } | |
66 | ||
9c355917 BS |
67 | SYSCALL_DEFINE6(mmap, unsigned long, addr, size_t, len, |
68 | unsigned long, prot, unsigned long, flags, | |
69 | unsigned long, fd, off_t, offset) | |
30286ef6 PM |
70 | { |
71 | return do_mmap2(addr, len, prot, flags, fd, offset, PAGE_SHIFT); | |
72 | } | |
73 | ||
74 | #ifdef CONFIG_PPC32 | |
75 | /* | |
76 | * Due to some executables calling the wrong select we sometimes | |
77 | * get wrong args. This determines how the args are being passed | |
78 | * (a single ptr to them all args passed) then calls | |
79 | * sys_select() with the appropriate args. -- Cort | |
80 | */ | |
81 | int | |
82 | ppc_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp) | |
83 | { | |
84 | if ( (unsigned long)n >= 4096 ) | |
85 | { | |
86 | unsigned long __user *buffer = (unsigned long __user *)n; | |
96d4f267 | 87 | if (!access_ok(buffer, 5*sizeof(unsigned long)) |
30286ef6 PM |
88 | || __get_user(n, buffer) |
89 | || __get_user(inp, ((fd_set __user * __user *)(buffer+1))) | |
90 | || __get_user(outp, ((fd_set __user * __user *)(buffer+2))) | |
91 | || __get_user(exp, ((fd_set __user * __user *)(buffer+3))) | |
92 | || __get_user(tvp, ((struct timeval __user * __user *)(buffer+4)))) | |
93 | return -EFAULT; | |
94 | } | |
95 | return sys_select(n, inp, outp, exp, tvp); | |
96 | } | |
97 | #endif | |
98 | ||
99 | #ifdef CONFIG_PPC64 | |
ce10d979 | 100 | long ppc64_personality(unsigned long personality) |
1da177e4 | 101 | { |
ce10d979 PM |
102 | long ret; |
103 | ||
104 | if (personality(current->personality) == PER_LINUX32 | |
7256a5d2 JK |
105 | && personality(personality) == PER_LINUX) |
106 | personality = (personality & ~PER_MASK) | PER_LINUX32; | |
ce10d979 | 107 | ret = sys_personality(personality); |
7256a5d2 JK |
108 | if (personality(ret) == PER_LINUX32) |
109 | ret = (ret & ~PER_MASK) | PER_LINUX; | |
ce10d979 | 110 | return ret; |
1da177e4 | 111 | } |
30286ef6 PM |
112 | #endif |
113 | ||
77f543cb PM |
114 | long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, |
115 | u32 len_high, u32 len_low) | |
116 | { | |
9d5b7c95 DB |
117 | return ksys_fadvise64_64(fd, (u64)offset_high << 32 | offset_low, |
118 | (u64)len_high << 32 | len_low, advice); | |
77f543cb | 119 | } |
529d235a | 120 | |
81dac817 | 121 | SYSCALL_DEFINE0(switch_endian) |
529d235a ME |
122 | { |
123 | struct thread_info *ti; | |
124 | ||
125 | current->thread.regs->msr ^= MSR_LE; | |
126 | ||
127 | /* | |
128 | * Set TIF_RESTOREALL so that r3 isn't clobbered on return to | |
129 | * userspace. That also has the effect of restoring the non-volatile | |
130 | * GPRs, so we saved them on the way in here. | |
131 | */ | |
132 | ti = current_thread_info(); | |
133 | ti->flags |= _TIF_RESTOREALL; | |
134 | ||
135 | return 0; | |
136 | } |