1 /*
2  * sys_parisc32.c: Conversion between 32bit and 64bit native syscalls.
3  *
4  * Copyright (C) 2000-2001 Hewlett Packard Company
5  * Copyright (C) 2000 John Marvin
6  * Copyright (C) 2001 Matthew Wilcox
7  *
8  * These routines maintain argument size conversion between 32bit and 64bit
9  * environment. Based heavily on sys_ia32.c and sys_sparc32.c.
10  */
11 
12 #include <linux/compat.h>
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/fs.h>
16 #include <linux/mm.h>
17 #include <linux/file.h>
18 #include <linux/signal.h>
19 #include <linux/resource.h>
20 #include <linux/times.h>
21 #include <linux/time.h>
22 #include <linux/smp.h>
23 #include <linux/sem.h>
24 #include <linux/msg.h>
25 #include <linux/shm.h>
26 #include <linux/slab.h>
27 #include <linux/uio.h>
28 #include <linux/ncp_fs.h>
29 #include <linux/poll.h>
30 #include <linux/personality.h>
31 #include <linux/stat.h>
32 #include <linux/highmem.h>
33 #include <linux/highuid.h>
34 #include <linux/mman.h>
35 #include <linux/binfmts.h>
36 #include <linux/namei.h>
37 #include <linux/vfs.h>
38 #include <linux/ptrace.h>
39 #include <linux/swap.h>
40 #include <linux/syscalls.h>
41 
42 #include <asm/types.h>
43 #include <asm/uaccess.h>
44 #include <asm/mmu_context.h>
45 
46 #include "sys32.h"
47 
48 #undef DEBUG
49 
50 #ifdef DEBUG
51 #define DBG(x)	printk x
52 #else
53 #define DBG(x)
54 #endif
55 
56 asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
57 	int r22, int r21, int r20)
58 {
59     printk(KERN_ERR "%s(%d): Unimplemented 32 on 64 syscall #%d!\n",
60     	current->comm, current->pid, r20);
61     return -ENOSYS;
62 }
63 
64 struct msgbuf32 {
65     int mtype;
66     char mtext[1];
67 };
68 
69 asmlinkage long sys32_msgsnd(int msqid,
70 				struct msgbuf32 __user *umsgp32,
71 				size_t msgsz, int msgflg)
72 {
73 	struct msgbuf *mb;
74 	struct msgbuf32 mb32;
75 	int err;
76 
77 	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
78 		return -ENOMEM;
79 
80 	err = get_user(mb32.mtype, &umsgp32->mtype);
81 	mb->mtype = mb32.mtype;
82 	err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz);
83 
84 	if (err)
85 		err = -EFAULT;
86 	else
87 		KERNEL_SYSCALL(err, sys_msgsnd, msqid, (struct msgbuf __user *)mb, msgsz, msgflg);
88 
89 	kfree(mb);
90 	return err;
91 }
92 
93 asmlinkage long sys32_msgrcv(int msqid,
94 				struct msgbuf32 __user *umsgp32,
95 				size_t msgsz, long msgtyp, int msgflg)
96 {
97 	struct msgbuf *mb;
98 	struct msgbuf32 mb32;
99 	int err, len;
100 
101 	if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL)
102 		return -ENOMEM;
103 
104 	KERNEL_SYSCALL(err, sys_msgrcv, msqid, (struct msgbuf __user *)mb, msgsz, msgtyp, msgflg);
105 
106 	if (err >= 0) {
107 		len = err;
108 		mb32.mtype = mb->mtype;
109 		err = put_user(mb32.mtype, &umsgp32->mtype);
110 		err |= copy_to_user(&umsgp32->mtext, mb->mtext, len);
111 		if (err)
112 			err = -EFAULT;
113 		else
114 			err = len;
115 	}
116 
117 	kfree(mb);
118 	return err;
119 }
120 
121 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
122 {
123         mm_segment_t old_fs = get_fs();
124         int ret;
125         off_t of;
126 
127         if (offset && get_user(of, offset))
128                 return -EFAULT;
129 
130         set_fs(KERNEL_DS);
131         ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
132         set_fs(old_fs);
133 
134         if (offset && put_user(of, offset))
135                 return -EFAULT;
136 
137         return ret;
138 }
139 
140 asmlinkage int sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count)
141 {
142 	mm_segment_t old_fs = get_fs();
143 	int ret;
144 	loff_t lof;
145 
146 	if (offset && get_user(lof, offset))
147 		return -EFAULT;
148 
149 	set_fs(KERNEL_DS);
150 	ret = sys_sendfile64(out_fd, in_fd, offset ? (loff_t __user *)&lof : NULL, count);
151 	set_fs(old_fs);
152 
153 	if (offset && put_user(lof, offset))
154 		return -EFAULT;
155 
156 	return ret;
157 }
158 
159 
160 /* lseek() needs a wrapper because 'offset' can be negative, but the top
161  * half of the argument has been zeroed by syscall.S.
162  */
163 
164 asmlinkage int sys32_lseek(unsigned int fd, int offset, unsigned int origin)
165 {
166 	return sys_lseek(fd, offset, origin);
167 }
168 
169 asmlinkage long sys32_semctl(int semid, int semnum, int cmd, union semun arg)
170 {
171         union semun u;
172 
173         if (cmd == SETVAL) {
174                 /* Ugh.  arg is a union of int,ptr,ptr,ptr, so is 8 bytes.
175                  * The int should be in the first 4, but our argument
176                  * frobbing has left it in the last 4.
177                  */
178                 u.val = *((int *)&arg + 1);
179                 return sys_semctl (semid, semnum, cmd, u);
180 	}
181 	return sys_semctl (semid, semnum, cmd, arg);
182 }
183 
184 long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
185 			  size_t len)
186 {
187 	return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
188 				  buf, len);
189 }
190 
191 asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
192 				u32 lenhi, u32 lenlo)
193 {
194         return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
195                              ((loff_t)lenhi << 32) | lenlo);
196 }
197 
198 asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi,
199 					 u32 mask_lo, int fd,
200 					 const char __user *pathname)
201 {
202 	return sys_fanotify_mark(fan_fd, flags, ((u64)mask_hi << 32) | mask_lo,
203 				 fd, pathname);
204 }
205