Deleted Added
full compact
linux_misc.c (12130) linux_misc.c (12458)
1/*-
2 * Copyright (c) 1994-1995 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
1/*-
2 * Copyright (c) 1994-1995 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $Id: linux_misc.c,v 1.2 1995/10/04 07:08:04 julian Exp $
28 * $Id: linux_misc.c,v 1.3 1995/11/06 12:52:24 davidg Exp $
29 */
30
29 */
30
31#include <i386/linux/linux.h>
32#include <sys/param.h>
33#include <sys/systm.h>
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/sysproto.h>
34#include <sys/kernel.h>
34#include <sys/exec.h>
35#include <sys/mman.h>
36#include <sys/proc.h>
37#include <sys/dirent.h>
38#include <sys/file.h>
39#include <sys/filedesc.h>
40#include <sys/ioctl.h>
41#include <sys/imgact_aout.h>
42#include <sys/mount.h>
43#include <sys/namei.h>
44#include <sys/resource.h>
45#include <sys/resourcevar.h>
46#include <sys/stat.h>
35#include <sys/exec.h>
36#include <sys/mman.h>
37#include <sys/proc.h>
38#include <sys/dirent.h>
39#include <sys/file.h>
40#include <sys/filedesc.h>
41#include <sys/ioctl.h>
42#include <sys/imgact_aout.h>
43#include <sys/mount.h>
44#include <sys/namei.h>
45#include <sys/resource.h>
46#include <sys/resourcevar.h>
47#include <sys/stat.h>
47#include <sys/time.h>
48#include <sys/sysctl.h>
48#include <sys/times.h>
49#include <sys/utsname.h>
50#include <sys/vnode.h>
51#include <sys/wait.h>
52
49#include <sys/times.h>
50#include <sys/utsname.h>
51#include <sys/vnode.h>
52#include <sys/wait.h>
53
54#include <vm/vm_kern.h>
55
53#include <machine/cpu.h>
54#include <machine/psl.h>
56#include <machine/cpu.h>
57#include <machine/psl.h>
55#include <machine/reg.h>
56
58
57#include <vm/vm.h>
58#include <vm/vm_kern.h>
59#include <i386/linux/linux.h>
60#include <i386/linux/sysproto.h>
59
61
60
61struct linux_alarm_args {
62 unsigned int secs;
63};
64
65int
66linux_alarm(struct proc *p, struct linux_alarm_args *args, int *retval)
67{
62struct linux_alarm_args {
63 unsigned int secs;
64};
65
66int
67linux_alarm(struct proc *p, struct linux_alarm_args *args, int *retval)
68{
68 extern struct timeval time;
69 struct itimerval it, old_it;
70 int s;
71
72#ifdef DEBUG
73 printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs);
74#endif
75 it.it_value.tv_sec = (long)args->secs;
76 it.it_value.tv_usec = 0;
77 it.it_interval.tv_sec = 0;
78 it.it_interval.tv_usec = 0;
79 s = splclock();
80 old_it = p->p_realtimer;
81 if (timerisset(&old_it.it_value))
82 if (timercmp(&old_it.it_value, &time, <))
83 timerclear(&old_it.it_value);
84 else
85 timevalsub(&old_it.it_value, &time);
86 splx(s);
87 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval))
88 return EINVAL;
89 s = splclock();
90 untimeout(realitexpire, (caddr_t)p);
91 if (timerisset(&it.it_value)) {
92 timevaladd(&it.it_value, &time);
93 timeout(realitexpire, (caddr_t)p, hzto(&it.it_value));
94 }
95 p->p_realtimer = it;
96 splx(s);
97 if (old_it.it_value.tv_usec)
98 old_it.it_value.tv_sec++;
99 *retval = old_it.it_value.tv_sec;
100 return 0;
101}
102
103struct linux_brk_args {
104 linux_caddr_t dsend;
105};
106
107int
108linux_brk(struct proc *p, struct linux_brk_args *args, int *retval)
109{
110#if 0
111 struct vmspace *vm = p->p_vmspace;
112 vm_offset_t new, old;
113 int error;
69 struct itimerval it, old_it;
70 int s;
71
72#ifdef DEBUG
73 printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs);
74#endif
75 it.it_value.tv_sec = (long)args->secs;
76 it.it_value.tv_usec = 0;
77 it.it_interval.tv_sec = 0;
78 it.it_interval.tv_usec = 0;
79 s = splclock();
80 old_it = p->p_realtimer;
81 if (timerisset(&old_it.it_value))
82 if (timercmp(&old_it.it_value, &time, <))
83 timerclear(&old_it.it_value);
84 else
85 timevalsub(&old_it.it_value, &time);
86 splx(s);
87 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval))
88 return EINVAL;
89 s = splclock();
90 untimeout(realitexpire, (caddr_t)p);
91 if (timerisset(&it.it_value)) {
92 timevaladd(&it.it_value, &time);
93 timeout(realitexpire, (caddr_t)p, hzto(&it.it_value));
94 }
95 p->p_realtimer = it;
96 splx(s);
97 if (old_it.it_value.tv_usec)
98 old_it.it_value.tv_sec++;
99 *retval = old_it.it_value.tv_sec;
100 return 0;
101}
102
103struct linux_brk_args {
104 linux_caddr_t dsend;
105};
106
107int
108linux_brk(struct proc *p, struct linux_brk_args *args, int *retval)
109{
110#if 0
111 struct vmspace *vm = p->p_vmspace;
112 vm_offset_t new, old;
113 int error;
114 extern int swap_pager_full;
115
116 if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
117 return EINVAL;
118 if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
119 > p->p_rlimit[RLIMIT_DATA].rlim_cur)
120 return ENOMEM;
121
122 old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
123 new = round_page((vm_offset_t)args->dsend);
124 *retval = old;
125 if ((new-old) > 0) {
126 if (swap_pager_full)
127 return ENOMEM;
128 error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE);
129 if (error)
130 return error;
131 vm->vm_dsize += btoc((new-old));
132 *retval = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
133 }
134 return 0;
135#else
136 struct vmspace *vm = p->p_vmspace;
137 vm_offset_t new, old;
138 struct obreak_args {
139 vm_offset_t newsize;
140 } tmp;
141
142#ifdef DEBUG
143 printf("Linux-emul(%d): brk(%08x)\n", p->p_pid, args->dsend);
144#endif
145 old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
146 new = (vm_offset_t)args->dsend;
147 tmp.newsize = new;
148 if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp, retval))
149 retval[0] = (int)new;
150 else
151 retval[0] = (int)old;
152
153 return 0;
154#endif
155}
156
157struct linux_uselib_args {
158 char *library;
159};
160
161int
162linux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval)
163{
164 struct nameidata ni;
165 struct vnode *vp;
166 struct exec *a_out = 0;
167 struct vattr attr;
168 unsigned long vmaddr, virtual_offset, file_offset;
169 unsigned long buffer, bss_size;
170 char *ptr;
171 char path[MAXPATHLEN];
172 const char *prefix = "/compat/linux";
173 size_t sz, len;
174 int error;
175
176#ifdef DEBUG
177 printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library);
178#endif
179
180 for (ptr = path; (*ptr = *prefix) != '\0'; ptr++, prefix++) ;
181 sz = MAXPATHLEN - (ptr - path);
182 if (error = copyinstr(args->library, ptr, sz, &len))
183 return error;
184 if (*ptr != '/')
185 return EINVAL;
186
187#ifdef DEBUG
188 printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, path);
189#endif
190
191 NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p);
192 if (error = namei(&ni))
193 return error;
194
195 vp = ni.ni_vp;
196 if (vp == NULL)
197 return ENOEXEC;
198
199 if (vp->v_writecount) {
200 VOP_UNLOCK(vp);
201 return ETXTBSY;
202 }
203
204 if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p)) {
205 VOP_UNLOCK(vp);
206 return error;
207 }
208
209 if ((vp->v_mount->mnt_flag & MNT_NOEXEC)
210 || ((attr.va_mode & 0111) == 0)
211 || (attr.va_type != VREG)) {
212 VOP_UNLOCK(vp);
213 return ENOEXEC;
214 }
215
216 if (attr.va_size == 0) {
217 VOP_UNLOCK(vp);
218 return ENOEXEC;
219 }
220
221 if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) {
222 VOP_UNLOCK(vp);
223 return error;
224 }
225
226 if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) {
227 VOP_UNLOCK(vp);
228 return error;
229 }
230
231 VOP_UNLOCK(vp); /* lock no longer needed */
232
233 error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, 1024,
234 VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
235 if (error)
236 return (error);
237
238 /*
239 * Is it a Linux binary ?
240 */
241 if (((a_out->a_magic >> 16) & 0xff) != 0x64)
242 return ENOEXEC;
243
244 /*
245 * Set file/virtual offset based on a.out variant.
246 */
247 switch ((int)(a_out->a_magic & 0xffff)) {
248 case 0413: /* ZMAGIC */
249 virtual_offset = 0;
250 file_offset = 1024;
251 break;
252 case 0314: /* QMAGIC */
253 virtual_offset = 4096;
254 file_offset = 0;
255 break;
256 default:
257 return ENOEXEC;
258 }
259
260 vp->v_flag |= VTEXT;
261 bss_size = round_page(a_out->a_bss);
262 /*
263 * Check if file_offset page aligned,.
264 * Currently we cannot handle misalinged file offsets,
265 * and so we read in the entire image (what a waste).
266 */
267 if (file_offset & PGOFSET) {
268#ifdef DEBUG
269printf("uselib: Non page aligned binary %d\n", file_offset);
270#endif
271 /*
272 * Map text+data read/write/execute
273 */
274 vmaddr = virtual_offset + round_page(a_out->a_entry);
275 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
276 round_page(a_out->a_text + a_out->a_data), FALSE);
277 if (error)
278 return error;
279
280 error = vm_mmap(kernel_map, &buffer,
281 round_page(a_out->a_text + a_out->a_data + file_offset),
282 VM_PROT_READ, VM_PROT_READ, MAP_FILE,
283 (caddr_t)vp, trunc_page(file_offset));
284 if (error)
285 return error;
286
287 error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr,
288 a_out->a_text + a_out->a_data);
289 if (error)
290 return error;
291
292 vm_map_remove(kernel_map, trunc_page(vmaddr),
293 round_page(a_out->a_text + a_out->a_data + file_offset));
294
295 error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr,
296 round_page(a_out->a_text + a_out->a_data),
297 VM_PROT_ALL, TRUE);
298 if (error)
299 return error;
300 }
301 else {
302#ifdef DEBUG
303printf("uselib: Page aligned binary %d\n", file_offset);
304#endif
305 vmaddr = virtual_offset + round_page(a_out->a_entry);
306 error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
307 a_out->a_text + a_out->a_data,
308 VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
309 (caddr_t)vp, file_offset);
310 if (error)
311 return (error);
312 }
313#ifdef DEBUG
314printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
315#endif
316 if (bss_size != 0) {
317 vmaddr = virtual_offset + round_page(a_out->a_entry) +
318 round_page(a_out->a_text + a_out->a_data);
319 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
320 bss_size, FALSE);
321 if (error)
322 return error;
323 error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, bss_size,
324 VM_PROT_ALL, TRUE);
325 if (error)
326 return error;
327 }
328 return 0;
329}
330
331struct linux_select_args {
332 void *ptr;
333};
334
335int
336linux_select(struct proc *p, struct linux_select_args *args, int *retval)
337{
338 struct {
339 int nfds;
340 fd_set *readfds;
341 fd_set *writefds;
342 fd_set *exceptfds;
343 struct timeval *timeout;
344 } linux_args;
345 struct {
346 unsigned int nd;
347 fd_set *in;
348 fd_set *ou;
349 fd_set *ex;
350 struct timeval *tv;
351 } bsd_args;
352 int error;
353
354 if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
355 sizeof(linux_args))))
356 return error;
357#ifdef DEBUG
358 printf("Linux-emul(%d): select(%d, %d, %d, %d, %d)\n",
359 p->p_pid, linux_args.nfds, linux_args.readfds,
360 linux_args.writefds, linux_args.exceptfds,
361 linux_args.timeout);
362#endif
363 bsd_args.nd = linux_args.nfds;
364 bsd_args.in = linux_args.readfds;
365 bsd_args.ou = linux_args.writefds;
366 bsd_args.ex = linux_args.exceptfds;
367 bsd_args.tv = linux_args.timeout;
368 return select(p, &bsd_args, retval);
369}
370
371struct linux_getpgid_args {
372 int pid;
373};
374
375int
376linux_getpgid(struct proc *p, struct linux_getpgid_args *args, int *retval)
377{
378 struct proc *curproc;
379
380#ifdef DEBUG
381 printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid);
382#endif
383 if (args->pid != p->p_pid) {
384 if (!(curproc = pfind(args->pid)))
385 return ESRCH;
386 }
387 else
388 curproc = p;
389 *retval = curproc->p_pgid;
390 return 0;
391}
392
393int
394linux_fork(struct proc *p, void *args, int *retval)
395{
396 int error;
397
398#ifdef DEBUG
399 printf("Linux-emul(%d): fork()\n", p->p_pid);
400#endif
401 if (error = fork(p, args, retval))
402 return error;
403 if (retval[1] == 1)
404 retval[0] = 0;
405 return 0;
406}
407
408struct linux_mmap_args {
409 void *ptr;
410};
411
412int
413linux_mmap(struct proc *p, struct linux_mmap_args *args, int *retval)
414{
415 struct {
416 linux_caddr_t addr;
417 int len;
418 int prot;
419 int flags;
420 int fd;
421 int pos;
422 } linux_args;
423 struct {
424 caddr_t addr;
425 size_t len;
426 int prot;
427 int flags;
428 int fd;
429 long pad;
430 off_t pos;
431 } bsd_args;
432 int error;
433
434 if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
435 sizeof(linux_args))))
436 return error;
437#ifdef DEBUG
438 printf("Linux-emul(%d): mmap(%08x, %d, %d, %08x, %d, %d)\n",
439 p->p_pid, linux_args.addr, linux_args.len, linux_args.prot,
440 linux_args.flags, linux_args.fd, linux_args.pos);
441#endif
442 bsd_args.flags = 0;
443 if (linux_args.flags & LINUX_MAP_SHARED)
444 bsd_args.flags |= MAP_SHARED;
445 if (linux_args.flags & LINUX_MAP_PRIVATE)
446 bsd_args.flags |= MAP_PRIVATE;
447 if (linux_args.flags & LINUX_MAP_FIXED)
448 bsd_args.flags |= MAP_FIXED;
449 if (linux_args.flags & LINUX_MAP_ANON)
450 bsd_args.flags |= MAP_ANON;
451 bsd_args.addr = linux_args.addr;
452 bsd_args.len = linux_args.len;
453 bsd_args.prot = linux_args.prot;
454 bsd_args.fd = linux_args.fd;
455 bsd_args.pos = linux_args.pos;
456 bsd_args.pad = 0;
457 return mmap(p, &bsd_args, retval);
458}
459
460struct linux_pipe_args {
461 int *pipefds;
462};
463
464int
465linux_pipe(struct proc *p, struct linux_pipe_args *args, int *retval)
466{
467 int error;
468
469#ifdef DEBUG
470 printf("Linux-emul(%d): pipe(*)\n", p->p_pid);
471#endif
472 if (error = pipe(p, 0, retval))
473 return error;
474 if (error = copyout(retval, args->pipefds, 2*sizeof(int)))
475 return error;
476 *retval = 0;
477 return 0;
478}
479
480struct linux_time_args {
481 linux_time_t *tm;
482};
483
484int
485linux_time(struct proc *p, struct linux_time_args *args, int *retval)
486{
487 struct timeval tv;
488 linux_time_t tm;
489 int error;
490
491#ifdef DEBUG
492 printf("Linux-emul(%d): time(*)\n", p->p_pid);
493#endif
494 microtime(&tv);
495 tm = tv.tv_sec;
496 if (error = copyout(&tm, args->tm, sizeof(linux_time_t)))
497 return error;
498 *retval = tv.tv_sec;
499 return 0;
500}
501
502struct linux_tms {
503 long tms_utime;
504 long tms_stime;
505 long tms_cutime;
506 long tms_cstime;
507};
508
509struct linux_tms_args {
510 char *buf;
511};
512
513int
514linux_times(struct proc *p, struct linux_tms_args *args, int *retval)
515{
114
115 if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr)
116 return EINVAL;
117 if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr)
118 > p->p_rlimit[RLIMIT_DATA].rlim_cur)
119 return ENOMEM;
120
121 old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize);
122 new = round_page((vm_offset_t)args->dsend);
123 *retval = old;
124 if ((new-old) > 0) {
125 if (swap_pager_full)
126 return ENOMEM;
127 error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE);
128 if (error)
129 return error;
130 vm->vm_dsize += btoc((new-old));
131 *retval = (int)(vm->vm_daddr + ctob(vm->vm_dsize));
132 }
133 return 0;
134#else
135 struct vmspace *vm = p->p_vmspace;
136 vm_offset_t new, old;
137 struct obreak_args {
138 vm_offset_t newsize;
139 } tmp;
140
141#ifdef DEBUG
142 printf("Linux-emul(%d): brk(%08x)\n", p->p_pid, args->dsend);
143#endif
144 old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize);
145 new = (vm_offset_t)args->dsend;
146 tmp.newsize = new;
147 if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp, retval))
148 retval[0] = (int)new;
149 else
150 retval[0] = (int)old;
151
152 return 0;
153#endif
154}
155
156struct linux_uselib_args {
157 char *library;
158};
159
160int
161linux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval)
162{
163 struct nameidata ni;
164 struct vnode *vp;
165 struct exec *a_out = 0;
166 struct vattr attr;
167 unsigned long vmaddr, virtual_offset, file_offset;
168 unsigned long buffer, bss_size;
169 char *ptr;
170 char path[MAXPATHLEN];
171 const char *prefix = "/compat/linux";
172 size_t sz, len;
173 int error;
174
175#ifdef DEBUG
176 printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library);
177#endif
178
179 for (ptr = path; (*ptr = *prefix) != '\0'; ptr++, prefix++) ;
180 sz = MAXPATHLEN - (ptr - path);
181 if (error = copyinstr(args->library, ptr, sz, &len))
182 return error;
183 if (*ptr != '/')
184 return EINVAL;
185
186#ifdef DEBUG
187 printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, path);
188#endif
189
190 NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p);
191 if (error = namei(&ni))
192 return error;
193
194 vp = ni.ni_vp;
195 if (vp == NULL)
196 return ENOEXEC;
197
198 if (vp->v_writecount) {
199 VOP_UNLOCK(vp);
200 return ETXTBSY;
201 }
202
203 if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p)) {
204 VOP_UNLOCK(vp);
205 return error;
206 }
207
208 if ((vp->v_mount->mnt_flag & MNT_NOEXEC)
209 || ((attr.va_mode & 0111) == 0)
210 || (attr.va_type != VREG)) {
211 VOP_UNLOCK(vp);
212 return ENOEXEC;
213 }
214
215 if (attr.va_size == 0) {
216 VOP_UNLOCK(vp);
217 return ENOEXEC;
218 }
219
220 if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) {
221 VOP_UNLOCK(vp);
222 return error;
223 }
224
225 if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p)) {
226 VOP_UNLOCK(vp);
227 return error;
228 }
229
230 VOP_UNLOCK(vp); /* lock no longer needed */
231
232 error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, 1024,
233 VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, 0);
234 if (error)
235 return (error);
236
237 /*
238 * Is it a Linux binary ?
239 */
240 if (((a_out->a_magic >> 16) & 0xff) != 0x64)
241 return ENOEXEC;
242
243 /*
244 * Set file/virtual offset based on a.out variant.
245 */
246 switch ((int)(a_out->a_magic & 0xffff)) {
247 case 0413: /* ZMAGIC */
248 virtual_offset = 0;
249 file_offset = 1024;
250 break;
251 case 0314: /* QMAGIC */
252 virtual_offset = 4096;
253 file_offset = 0;
254 break;
255 default:
256 return ENOEXEC;
257 }
258
259 vp->v_flag |= VTEXT;
260 bss_size = round_page(a_out->a_bss);
261 /*
262 * Check if file_offset page aligned,.
263 * Currently we cannot handle misalinged file offsets,
264 * and so we read in the entire image (what a waste).
265 */
266 if (file_offset & PGOFSET) {
267#ifdef DEBUG
268printf("uselib: Non page aligned binary %d\n", file_offset);
269#endif
270 /*
271 * Map text+data read/write/execute
272 */
273 vmaddr = virtual_offset + round_page(a_out->a_entry);
274 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
275 round_page(a_out->a_text + a_out->a_data), FALSE);
276 if (error)
277 return error;
278
279 error = vm_mmap(kernel_map, &buffer,
280 round_page(a_out->a_text + a_out->a_data + file_offset),
281 VM_PROT_READ, VM_PROT_READ, MAP_FILE,
282 (caddr_t)vp, trunc_page(file_offset));
283 if (error)
284 return error;
285
286 error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr,
287 a_out->a_text + a_out->a_data);
288 if (error)
289 return error;
290
291 vm_map_remove(kernel_map, trunc_page(vmaddr),
292 round_page(a_out->a_text + a_out->a_data + file_offset));
293
294 error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr,
295 round_page(a_out->a_text + a_out->a_data),
296 VM_PROT_ALL, TRUE);
297 if (error)
298 return error;
299 }
300 else {
301#ifdef DEBUG
302printf("uselib: Page aligned binary %d\n", file_offset);
303#endif
304 vmaddr = virtual_offset + round_page(a_out->a_entry);
305 error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr,
306 a_out->a_text + a_out->a_data,
307 VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED,
308 (caddr_t)vp, file_offset);
309 if (error)
310 return (error);
311 }
312#ifdef DEBUG
313printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]);
314#endif
315 if (bss_size != 0) {
316 vmaddr = virtual_offset + round_page(a_out->a_entry) +
317 round_page(a_out->a_text + a_out->a_data);
318 error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr,
319 bss_size, FALSE);
320 if (error)
321 return error;
322 error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, bss_size,
323 VM_PROT_ALL, TRUE);
324 if (error)
325 return error;
326 }
327 return 0;
328}
329
330struct linux_select_args {
331 void *ptr;
332};
333
334int
335linux_select(struct proc *p, struct linux_select_args *args, int *retval)
336{
337 struct {
338 int nfds;
339 fd_set *readfds;
340 fd_set *writefds;
341 fd_set *exceptfds;
342 struct timeval *timeout;
343 } linux_args;
344 struct {
345 unsigned int nd;
346 fd_set *in;
347 fd_set *ou;
348 fd_set *ex;
349 struct timeval *tv;
350 } bsd_args;
351 int error;
352
353 if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
354 sizeof(linux_args))))
355 return error;
356#ifdef DEBUG
357 printf("Linux-emul(%d): select(%d, %d, %d, %d, %d)\n",
358 p->p_pid, linux_args.nfds, linux_args.readfds,
359 linux_args.writefds, linux_args.exceptfds,
360 linux_args.timeout);
361#endif
362 bsd_args.nd = linux_args.nfds;
363 bsd_args.in = linux_args.readfds;
364 bsd_args.ou = linux_args.writefds;
365 bsd_args.ex = linux_args.exceptfds;
366 bsd_args.tv = linux_args.timeout;
367 return select(p, &bsd_args, retval);
368}
369
370struct linux_getpgid_args {
371 int pid;
372};
373
374int
375linux_getpgid(struct proc *p, struct linux_getpgid_args *args, int *retval)
376{
377 struct proc *curproc;
378
379#ifdef DEBUG
380 printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid);
381#endif
382 if (args->pid != p->p_pid) {
383 if (!(curproc = pfind(args->pid)))
384 return ESRCH;
385 }
386 else
387 curproc = p;
388 *retval = curproc->p_pgid;
389 return 0;
390}
391
392int
393linux_fork(struct proc *p, void *args, int *retval)
394{
395 int error;
396
397#ifdef DEBUG
398 printf("Linux-emul(%d): fork()\n", p->p_pid);
399#endif
400 if (error = fork(p, args, retval))
401 return error;
402 if (retval[1] == 1)
403 retval[0] = 0;
404 return 0;
405}
406
407struct linux_mmap_args {
408 void *ptr;
409};
410
411int
412linux_mmap(struct proc *p, struct linux_mmap_args *args, int *retval)
413{
414 struct {
415 linux_caddr_t addr;
416 int len;
417 int prot;
418 int flags;
419 int fd;
420 int pos;
421 } linux_args;
422 struct {
423 caddr_t addr;
424 size_t len;
425 int prot;
426 int flags;
427 int fd;
428 long pad;
429 off_t pos;
430 } bsd_args;
431 int error;
432
433 if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args,
434 sizeof(linux_args))))
435 return error;
436#ifdef DEBUG
437 printf("Linux-emul(%d): mmap(%08x, %d, %d, %08x, %d, %d)\n",
438 p->p_pid, linux_args.addr, linux_args.len, linux_args.prot,
439 linux_args.flags, linux_args.fd, linux_args.pos);
440#endif
441 bsd_args.flags = 0;
442 if (linux_args.flags & LINUX_MAP_SHARED)
443 bsd_args.flags |= MAP_SHARED;
444 if (linux_args.flags & LINUX_MAP_PRIVATE)
445 bsd_args.flags |= MAP_PRIVATE;
446 if (linux_args.flags & LINUX_MAP_FIXED)
447 bsd_args.flags |= MAP_FIXED;
448 if (linux_args.flags & LINUX_MAP_ANON)
449 bsd_args.flags |= MAP_ANON;
450 bsd_args.addr = linux_args.addr;
451 bsd_args.len = linux_args.len;
452 bsd_args.prot = linux_args.prot;
453 bsd_args.fd = linux_args.fd;
454 bsd_args.pos = linux_args.pos;
455 bsd_args.pad = 0;
456 return mmap(p, &bsd_args, retval);
457}
458
459struct linux_pipe_args {
460 int *pipefds;
461};
462
463int
464linux_pipe(struct proc *p, struct linux_pipe_args *args, int *retval)
465{
466 int error;
467
468#ifdef DEBUG
469 printf("Linux-emul(%d): pipe(*)\n", p->p_pid);
470#endif
471 if (error = pipe(p, 0, retval))
472 return error;
473 if (error = copyout(retval, args->pipefds, 2*sizeof(int)))
474 return error;
475 *retval = 0;
476 return 0;
477}
478
479struct linux_time_args {
480 linux_time_t *tm;
481};
482
483int
484linux_time(struct proc *p, struct linux_time_args *args, int *retval)
485{
486 struct timeval tv;
487 linux_time_t tm;
488 int error;
489
490#ifdef DEBUG
491 printf("Linux-emul(%d): time(*)\n", p->p_pid);
492#endif
493 microtime(&tv);
494 tm = tv.tv_sec;
495 if (error = copyout(&tm, args->tm, sizeof(linux_time_t)))
496 return error;
497 *retval = tv.tv_sec;
498 return 0;
499}
500
501struct linux_tms {
502 long tms_utime;
503 long tms_stime;
504 long tms_cutime;
505 long tms_cstime;
506};
507
508struct linux_tms_args {
509 char *buf;
510};
511
512int
513linux_times(struct proc *p, struct linux_tms_args *args, int *retval)
514{
516 extern int hz;
517 struct timeval tv;
518 struct linux_tms tms;
519
520#ifdef DEBUG
521 printf("Linux-emul(%d): times(*)\n", p->p_pid);
522#endif
523 tms.tms_utime = p->p_uticks;
524 tms.tms_stime = p->p_sticks;
525 tms.tms_cutime = p->p_stats->p_cru.ru_utime.tv_sec * hz +
526 ((p->p_stats->p_cru.ru_utime.tv_usec * hz)/1000000);
527 tms.tms_cstime = p->p_stats->p_cru.ru_stime.tv_sec * hz +
528 ((p->p_stats->p_cru.ru_stime.tv_usec * hz)/1000000);
529 microtime(&tv);
530 *retval = tv.tv_sec * hz + (tv.tv_usec * hz)/1000000;
531 return (copyout((caddr_t)&tms, (caddr_t)args->buf,
532 sizeof(struct linux_tms)));
533}
534
535struct linux_newuname_t {
536 char sysname[65];
537 char nodename[65];
538 char release[65];
539 char version[65];
540 char machine[65];
541 char domainname[65];
542};
543
544struct linux_newuname_args {
545 char *buf;
546};
547
548int
549linux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval)
550{
551 struct linux_newuname_t linux_newuname;
515 struct timeval tv;
516 struct linux_tms tms;
517
518#ifdef DEBUG
519 printf("Linux-emul(%d): times(*)\n", p->p_pid);
520#endif
521 tms.tms_utime = p->p_uticks;
522 tms.tms_stime = p->p_sticks;
523 tms.tms_cutime = p->p_stats->p_cru.ru_utime.tv_sec * hz +
524 ((p->p_stats->p_cru.ru_utime.tv_usec * hz)/1000000);
525 tms.tms_cstime = p->p_stats->p_cru.ru_stime.tv_sec * hz +
526 ((p->p_stats->p_cru.ru_stime.tv_usec * hz)/1000000);
527 microtime(&tv);
528 *retval = tv.tv_sec * hz + (tv.tv_usec * hz)/1000000;
529 return (copyout((caddr_t)&tms, (caddr_t)args->buf,
530 sizeof(struct linux_tms)));
531}
532
533struct linux_newuname_t {
534 char sysname[65];
535 char nodename[65];
536 char release[65];
537 char version[65];
538 char machine[65];
539 char domainname[65];
540};
541
542struct linux_newuname_args {
543 char *buf;
544};
545
546int
547linux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval)
548{
549 struct linux_newuname_t linux_newuname;
552 extern char ostype[], osrelease[], machine[];
553 extern char hostname[], domainname[];
554
555#ifdef DEBUG
556 printf("Linux-emul(%d): newuname(*)\n", p->p_pid);
557#endif
558 bzero(&linux_newuname, sizeof(struct linux_newuname_args));
559 strncpy(linux_newuname.sysname, ostype, 64);
560 strncpy(linux_newuname.nodename, hostname, 64);
561 strncpy(linux_newuname.release, osrelease, 64);
562 strncpy(linux_newuname.version, version, 64);
563 strncpy(linux_newuname.machine, machine, 64);
564 strncpy(linux_newuname.domainname, domainname, 64);
565 return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf,
566 sizeof(struct linux_newuname_t)));
567}
568
569struct linux_utime_args {
570 char *fname;
571 linux_time_t *timeptr;
572};
573
574int
575linux_utime(struct proc *p, struct linux_utime_args *args, int *retval)
576{
577 struct bsd_utimes_args {
578 char *fname;
579 struct timeval *tptr;
580 } bsdutimes;
581 struct timeval tv;
582
583#ifdef DEBUG
584 printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname);
585#endif
586 tv.tv_sec = (long)args->timeptr;
587 tv.tv_usec = 0;
588 bsdutimes.tptr = &tv;
589 bsdutimes.fname = args->fname;
590 return utimes(p, &bsdutimes, retval);
591}
592
593struct linux_waitpid_args {
594 int pid;
595 int *status;
596 int options;
597};
598
599int
600linux_waitpid(struct proc *p, struct linux_waitpid_args *args, int *retval)
601{
602 struct wait4_args {
603 int pid;
604 int *status;
605 int options;
606 struct rusage *rusage;
607 int compat;
608 } tmp;
609 int error, tmpstat;
610
611#ifdef DEBUG
612 printf("Linux-emul(%d): waitpid(%d, *, %d)\n",
613 p->p_pid, args->pid, args->options);
614#endif
615 tmp.pid = args->pid;
616 tmp.status = args->status;
617 tmp.options = args->options;
618 tmp.rusage = NULL;
619 tmp.compat = 0;
620
621 if (error = wait4(p, &tmp, retval))
622 return error;
623 if (error = copyin(args->status, &tmpstat, sizeof(int)))
624 return error;
625 if (WIFSIGNALED(tmpstat))
626 tmpstat = (tmpstat & 0xffffff80) |
627 bsd_to_linux_signal[WTERMSIG(tmpstat)];
628 else if (WIFSTOPPED(tmpstat))
629 tmpstat = (tmpstat & 0xffff00ff) |
630 (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
631 return copyout(&tmpstat, args->status, sizeof(int));
632}
633
634struct linux_wait4_args {
635 int pid;
636 int *status;
637 int options;
638 struct rusage *rusage;
639};
640
641int
642linux_wait4(struct proc *p, struct linux_wait4_args *args, int *retval)
643{
644 struct wait4_args {
645 int pid;
646 int *status;
647 int options;
648 struct rusage *rusage;
649 int compat;
650 } tmp;
651 int error, tmpstat;
652
653#ifdef DEBUG
654 printf("Linux-emul(%d): wait4(%d, *, %d, *)\n",
655 p->p_pid, args->pid, args->options);
656#endif
657 tmp.pid = args->pid;
658 tmp.status = args->status;
659 tmp.options = args->options;
660 tmp.rusage = args->rusage;
661 tmp.compat = 0;
662
663 if (error = wait4(p, &tmp, retval))
664 return error;
665 if (error = copyin(args->status, &tmpstat, sizeof(int)))
666 return error;
667 if (WIFSIGNALED(tmpstat))
668 tmpstat = (tmpstat & 0xffffff80) |
669 bsd_to_linux_signal[WTERMSIG(tmpstat)];
670 else if (WIFSTOPPED(tmpstat))
671 tmpstat = (tmpstat & 0xffff00ff) |
672 (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
673 return copyout(&tmpstat, args->status, sizeof(int));
674}
550
551#ifdef DEBUG
552 printf("Linux-emul(%d): newuname(*)\n", p->p_pid);
553#endif
554 bzero(&linux_newuname, sizeof(struct linux_newuname_args));
555 strncpy(linux_newuname.sysname, ostype, 64);
556 strncpy(linux_newuname.nodename, hostname, 64);
557 strncpy(linux_newuname.release, osrelease, 64);
558 strncpy(linux_newuname.version, version, 64);
559 strncpy(linux_newuname.machine, machine, 64);
560 strncpy(linux_newuname.domainname, domainname, 64);
561 return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf,
562 sizeof(struct linux_newuname_t)));
563}
564
565struct linux_utime_args {
566 char *fname;
567 linux_time_t *timeptr;
568};
569
570int
571linux_utime(struct proc *p, struct linux_utime_args *args, int *retval)
572{
573 struct bsd_utimes_args {
574 char *fname;
575 struct timeval *tptr;
576 } bsdutimes;
577 struct timeval tv;
578
579#ifdef DEBUG
580 printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname);
581#endif
582 tv.tv_sec = (long)args->timeptr;
583 tv.tv_usec = 0;
584 bsdutimes.tptr = &tv;
585 bsdutimes.fname = args->fname;
586 return utimes(p, &bsdutimes, retval);
587}
588
589struct linux_waitpid_args {
590 int pid;
591 int *status;
592 int options;
593};
594
595int
596linux_waitpid(struct proc *p, struct linux_waitpid_args *args, int *retval)
597{
598 struct wait4_args {
599 int pid;
600 int *status;
601 int options;
602 struct rusage *rusage;
603 int compat;
604 } tmp;
605 int error, tmpstat;
606
607#ifdef DEBUG
608 printf("Linux-emul(%d): waitpid(%d, *, %d)\n",
609 p->p_pid, args->pid, args->options);
610#endif
611 tmp.pid = args->pid;
612 tmp.status = args->status;
613 tmp.options = args->options;
614 tmp.rusage = NULL;
615 tmp.compat = 0;
616
617 if (error = wait4(p, &tmp, retval))
618 return error;
619 if (error = copyin(args->status, &tmpstat, sizeof(int)))
620 return error;
621 if (WIFSIGNALED(tmpstat))
622 tmpstat = (tmpstat & 0xffffff80) |
623 bsd_to_linux_signal[WTERMSIG(tmpstat)];
624 else if (WIFSTOPPED(tmpstat))
625 tmpstat = (tmpstat & 0xffff00ff) |
626 (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
627 return copyout(&tmpstat, args->status, sizeof(int));
628}
629
630struct linux_wait4_args {
631 int pid;
632 int *status;
633 int options;
634 struct rusage *rusage;
635};
636
637int
638linux_wait4(struct proc *p, struct linux_wait4_args *args, int *retval)
639{
640 struct wait4_args {
641 int pid;
642 int *status;
643 int options;
644 struct rusage *rusage;
645 int compat;
646 } tmp;
647 int error, tmpstat;
648
649#ifdef DEBUG
650 printf("Linux-emul(%d): wait4(%d, *, %d, *)\n",
651 p->p_pid, args->pid, args->options);
652#endif
653 tmp.pid = args->pid;
654 tmp.status = args->status;
655 tmp.options = args->options;
656 tmp.rusage = args->rusage;
657 tmp.compat = 0;
658
659 if (error = wait4(p, &tmp, retval))
660 return error;
661 if (error = copyin(args->status, &tmpstat, sizeof(int)))
662 return error;
663 if (WIFSIGNALED(tmpstat))
664 tmpstat = (tmpstat & 0xffffff80) |
665 bsd_to_linux_signal[WTERMSIG(tmpstat)];
666 else if (WIFSTOPPED(tmpstat))
667 tmpstat = (tmpstat & 0xffff00ff) |
668 (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8);
669 return copyout(&tmpstat, args->status, sizeof(int));
670}