summaryrefslogtreecommitdiff
path: root/arch/arm64/kernel/sys_ilp32.c
blob: 35d5ab570cdc2e5ffbcd27ddb50c10ff7e9bd074 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/*
 * AArch64- ILP32 specific system calls implementation
 *
 * Copyright (C) 2013 Cavium Inc.
 * Author: Andrew Pinski <apinski@cavium.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/export.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/syscalls.h>

/*
 * Wrappers to pass the pt_regs argument.
 */
asmlinkage long sys_rt_sigreturn_wrapper(void);
#define sys_rt_sigreturn sys_rt_sigreturn_wrapper

/*
 * Note places where mention unsigned long bitmaps, could
 * use the non compat version for little-endian but big-endian
 * has issues to do layout of the bits in the bitmaps.
 */

/* Using Compat syscalls where necessary */
#define sys_ioctl		compat_sys_ioctl
/* iovec */
#define sys_readv		compat_sys_readv
#define sys_writev		compat_sys_writev
#define sys_preadv		compat_sys_preadv64
#define sys_pwritev		compat_sys_pwritev64
#define sys_vmsplice		compat_sys_vmsplice
/* robust_list_head */
#define sys_set_robust_list	compat_sys_set_robust_list
#define sys_get_robust_list	compat_sys_get_robust_list

/* kexec_segment */
#define sys_kexec_load		compat_sys_kexec_load

/* Ptrace has some structures which are different between ILP32 and LP64 */
#define sys_ptrace		compat_sys_ptrace

/* struct msghdr */
#define sys_recvfrom		compat_sys_recvfrom
#define sys_recvmmsg		compat_sys_recvmmsg
#define sys_sendmmsg		compat_sys_sendmmsg
#define sys_sendmsg		compat_sys_sendmsg
#define sys_recvmsg		compat_sys_recvmsg

/*
 * Note the timeval is taken care by COMPAT_USE_64BIT_TIME
 * being true.
 */
#define sys_setsockopt		compat_sys_setsockopt
#define sys_getsockopt		compat_sys_getsockopt

/* Array of pointers */
#define sys_execve		compat_sys_execve
#define sys_move_pages		compat_sys_move_pages

/* iovec */
#define sys_process_vm_readv	compat_sys_process_vm_readv
#define sys_process_vm_writev	compat_sys_process_vm_writev

/*
 * The NFSv4 and ncpfs structures are depend on the long and
 * pointer sizes.
 */
#define sys_mount               compat_sys_mount

/* NUMA */
/* unsigned long bitmaps */
#define sys_get_mempolicy       compat_sys_get_mempolicy
#define sys_set_mempolicy       compat_sys_set_mempolicy
#define sys_mbind               compat_sys_mbind

/* array of pointers */
/* unsigned long bitmaps */
#define sys_migrate_pages       compat_sys_migrate_pages

/* Scheduler */
/* unsigned long bitmaps */
#define sys_sched_setaffinity   compat_sys_sched_setaffinity
#define sys_sched_getaffinity   compat_sys_sched_getaffinity

/* iov usage */
#define sys_keyctl              compat_sys_keyctl

/* aio */
/* Array of pointers (iocb's) */
#define sys_io_submit           compat_sys_io_submit

/* We need to make sure the pointer gets copied correctly. */
asmlinkage long ilp32_sys_mq_notify(mqd_t mqdes,
			const struct sigevent __user *u_notification)
{
	struct sigevent __user *p = NULL;

	if (u_notification) {
		struct sigevent n;

		p = compat_alloc_user_space(sizeof(*p));
		if (copy_from_user(&n, u_notification, sizeof(*p)))
			return -EFAULT;
		if (n.sigev_notify == SIGEV_THREAD)
			n.sigev_value.sival_ptr = compat_ptr((uintptr_t)n.sigev_value.sival_ptr);
		if (copy_to_user(p, &n, sizeof(*p)))
			return -EFAULT;
	}
	return sys_mq_notify(mqdes, p);
}

/*
 * sigevent contains sigval_t which is now 64bit always
 * but need special handling due to padding for SIGEV_THREAD.
 */
#define sys_mq_notify		ilp32_sys_mq_notify


/*
 * sigaltstack needs some special handling as the
 * padding for stack_t might not be non-zero.
 */
long ilp32_sys_sigaltstack(const stack_t __user *uss_ptr,
			   stack_t __user *uoss_ptr)
{
	stack_t uss, uoss;
	int ret;
	mm_segment_t seg;

	if (uss_ptr) {
		if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)))
			return -EFAULT;
		if (__get_user(uss.ss_sp, &uss_ptr->ss_sp) |
			__get_user(uss.ss_flags, &uss_ptr->ss_flags) |
			__get_user(uss.ss_size, &uss_ptr->ss_size))
			return -EFAULT;
		/* Zero extend the sp address and the size. */
		uss.ss_sp = (void *)(uintptr_t)(unsigned int)(uintptr_t)uss.ss_sp;
		uss.ss_size = (size_t)(unsigned int)uss.ss_size;
	}
	seg = get_fs();
	set_fs(KERNEL_DS);
	/*
	 * Note we need to use uoss as we have changed the segment to the
	 * kernel one so passing an user one around is wrong.
	 */
	ret = sys_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
			      (stack_t __force __user *) &uoss);
	set_fs(seg);
	if (ret >= 0 && uoss_ptr)  {
		if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_t)) ||
		    __put_user(uoss.ss_sp, &uoss_ptr->ss_sp) ||
		    __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
		    __put_user(uoss.ss_size, &uoss_ptr->ss_size))
			ret = -EFAULT;
	}
	return ret;
}

/*
 * sigaltstack needs some special handling as the padding
 * for stack_t might not be non-zero.
 */
#define sys_sigaltstack		ilp32_sys_sigaltstack

#include <asm-generic/syscalls.h>

#undef __SYSCALL
#define __SYSCALL(nr, sym)	[nr] = sym,

/*
 * The sys_call_ilp32_table array must be 4K aligned to be accessible from
 * kernel/entry.S.
 */
void *sys_call_ilp32_table[__NR_syscalls] __aligned(4096) = {
	[0 ... __NR_syscalls - 1] = sys_ni_syscall,
#include <asm/unistd.h>
};