1 /* $NetBSD: irix_syssgi.c,v 1.48 2008/04/28 20:23:42 martin Exp $ */
2
3 /*-
4 * Copyright (c) 2001, 2002, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: irix_syssgi.c,v 1.48 2008/04/28 20:23:42 martin Exp $");
34
35 #if defined(_KERNEL_OPT)
36 #include "opt_ddb.h"
37 #endif
38
39 #ifndef ELFSIZE
40 #define ELFSIZE 32
41 #endif
42
43 /* round up and down to page boundaries. Borrowed from sys/kern/exec_elf32.c */
44 #define ELF_ROUND(a, b) (((a) + (b) - 1) & ~((b) - 1))
45 #define ELF_TRUNC(a, b) ((a) & ~((b) - 1))
46
47 #include <sys/types.h>
48 #include <sys/param.h>
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
51 #include <sys/systm.h>
52 #include <sys/filedesc.h>
53 #include <sys/buf.h>
54 #include <sys/vnode.h>
55 #include <sys/file.h>
56 #include <sys/resourcevar.h>
57 #include <sys/sysctl.h>
58 #include <sys/exec.h>
59 #include <sys/exec_elf.h>
60 #include <sys/mount.h>
61 #include <sys/syscallargs.h>
62
63 #include <uvm/uvm_extern.h>
64
65 #include <compat/common/compat_util.h>
66
67 #include <compat/svr4/svr4_types.h>
68
69 #include <compat/irix/irix_types.h>
70 #include <compat/irix/irix_signal.h>
71 #include <compat/irix/irix_exec.h>
72 #include <compat/irix/irix_prctl.h>
73 #include <compat/irix/irix_syscall.h>
74 #include <compat/irix/irix_syscallargs.h>
75 #include <compat/irix/irix_syssgi.h>
76
77 /* In sys/kern/exec_elf32.c */
78 void ELFNAME(load_psection)(struct exec_vmcmd_set *, struct vnode *,
79 const Elf_Phdr *, Elf_Addr *, u_long *, int *, int);
80
81 static int irix_syssgi_mapelf(int, Elf_Phdr *, int,
82 struct lwp *, register_t *);
83 static int irix_syssgi_sysconf(int name, struct lwp *, register_t *);
84 static int irix_syssgi_pathconf(char *, int, struct lwp *, register_t *);
85
86 int
87 irix_sys_syssgi(struct lwp *l, const struct irix_sys_syssgi_args *uap, register_t *retval)
88 {
89 /* {
90 syscallarg(int) request;
91 syscallarg(void *) arg1;
92 syscallarg(void *) arg2;
93 syscallarg(void *) arg3;
94 syscallarg(void *) arg4;
95 syscallarg(void *) arg5;
96 } */
97 struct proc *p = l->l_proc;
98 int request = SCARG(uap, request);
99 void *arg1, *arg2, *arg3;
100
101 #ifdef DEBUG_IRIX
102 printf("irix_sys_syssgi(): request = %d\n", request);
103 #endif
104 switch(request) {
105 case IRIX_SGI_SYSID: /* Get HostID */
106 *retval = (register_t)hostid;
107 break;
108
109 case IRIX_SGI_SETGROUPS: { /* setgroups(2) */
110 struct sys_setgroups_args cup;
111
112 SCARG(&cup, gidsetsize) = (int)SCARG(uap, arg1);
113 SCARG(&cup, gidset) = (gid_t *)SCARG(uap, arg2);
114 return (sys_setgroups(l, &cup, retval));
115 break;
116 }
117
118 case IRIX_SGI_GETGROUPS: { /* getgroups(2) */
119 struct sys_getgroups_args cup;
120
121 SCARG(&cup, gidsetsize) = (int)SCARG(uap, arg1);
122 SCARG(&cup, gidset) = (gid_t *)SCARG(uap, arg2);
123 return (sys_getgroups(l, &cup, retval));
124 break;
125 }
126
127 case IRIX_SGI_SETSID: /* Set session ID: setsid(2) */
128 return (sys_setsid(l, NULL, retval));
129 break;
130
131 case IRIX_SGI_GETSID: { /* Get session ID: getsid(2) */
132 struct sys_getsid_args cup;
133
134 SCARG(&cup, pid) = (pid_t)SCARG(uap, arg1);
135 return (sys_getsid(l, &cup, retval));
136 break;
137 }
138
139 case IRIX_SGI_GETPGID: {/* Get parent process GID: getpgid(2) */
140 struct sys_getpgid_args cup;
141
142 SCARG(&cup, pid) = (pid_t)SCARG(uap, arg1);
143 return (sys_getpgid(l, &cup, retval));
144 break;
145 }
146
147 case IRIX_SGI_SETPGID: {/* Get parent process GID: setpgid(2) */
148 struct sys_setpgid_args cup;
149
150 SCARG(&cup, pid) = (pid_t)SCARG(uap, arg1);
151 SCARG(&cup, pgid) = (pid_t)SCARG(uap, arg2);
152 return (sys_setpgid(l, &cup, retval));
153 break;
154 }
155
156 case IRIX_SGI_PATHCONF: /* Get file limits: pathconf(3) */
157 return irix_syssgi_pathconf((char *)SCARG(uap, arg1),
158 (int)SCARG(uap, arg2), l, retval);
159 break;
160
161 case IRIX_SGI_RUSAGE: { /* BSD getrusage(2) */
162 struct sys_getrusage_args cup;
163
164 SCARG(&cup, who) = (int)SCARG(uap, arg1);
165 SCARG(&cup, rusage) = (struct rusage *)SCARG(uap, arg2);
166 return sys_getrusage(l, &cup, retval);
167 break;
168 }
169
170 case IRIX_SGI_NUM_MODULES: /* <sys/systeminfo.h> get_num_modules() */
171 *retval = 1;
172 return 0;
173 break;
174
175 case IRIX_SGI_MODULE_INFO: { /* <sys/systeminfo.h> get_module_info() */
176 int module_num = (int)SCARG(uap, arg1);
177 struct irix_module_info_s *imip = SCARG(uap, arg2);
178 int mss = (int)SCARG(uap, arg3);
179 struct irix_module_info_s imi;
180 char *idx;
181
182 if (module_num != 0)
183 return EINVAL;
184
185 imi.serial_num = (u_int64_t)hostid;
186 imi.mod_num = 0;
187 (void)snprintf(imi.serial_str, IRIX_MAX_SERIAL_SIZE,
188 "0800%08x", (u_int32_t)hostid);
189
190 /* Convert to upper case */
191 for (idx = imi.serial_str; *idx; idx++)
192 if (*idx >= 'a' && *idx <= 'f')
193 *idx += ('A' - 'a');
194
195 /* Don't copyout irrelevant data on user request */
196 if (mss > sizeof(struct irix_module_info_s))
197 mss = sizeof(struct irix_module_info_s);
198
199 return copyout(&imi, imip, mss);
200 break;
201 }
202
203 case IRIX_SGI_RDNAME: { /* Read Processes' name */
204 struct proc *tp;
205
206 arg1 = SCARG(uap, arg1); /* PID of the process */
207 arg2 = SCARG(uap, arg2); /* Address of user buffer */
208 arg3 = SCARG(uap, arg3); /* Length of user buffer */
209 tp = pfind((pid_t)arg1);
210 if (tp == NULL || \
211 tp->p_psstr == NULL || \
212 tp->p_psstr->ps_argvstr == NULL || \
213 tp->p_psstr->ps_argvstr[0] == NULL)
214 return 0;
215
216 *retval = (register_t)copyout(tp->p_psstr->ps_argvstr[0],
217 (void *)arg2, (size_t)arg3);
218
219 break;
220 }
221 case IRIX_SGI_TUNE: /* Tune system variables */
222 case IRIX_SGI_IDBG: /* Kernel debugging */
223 case IRIX_SGI_INVENT: /* Get system inventory */
224 case IRIX_SGI_SETLED: /* Turn on/off LEDs */
225 case IRIX_SGI_SETNVRAM: /* Sets a NVRAM variable value */
226 case IRIX_SGI_GETNVRAM: /* Gets a NVRAM variable value */
227 return EINVAL;
228 break;
229
230 case IRIX_SGI_ELFMAP: /* Maps an ELF image */
231 arg1 = SCARG(uap, arg1); /* file descriptor */
232 arg2 = SCARG(uap, arg2); /* ptr to ELF program header array */
233 arg3 = SCARG(uap, arg3); /* array's length */
234 return irix_syssgi_mapelf((int)arg1, (Elf_Phdr *)arg2,
235 (int)arg3, l, retval);
236 break;
237
238 case IRIX_SGI_USE_FP_BCOPY: /* bcopy and bzero can use FPU or not */
239 /*
240 * Our kernel does not use FPU, hence we do nothing.
241 */
242 break;
243
244 case IRIX_SGI_TOSSTSAVE: /* Kill saved pregions */
245 /*
246 * Our kernel does not seem to save such "pregions",
247 * therefore we do not have to do anything.
248 */
249 break;
250
251 case IRIX_SGI_SYSCONF: /* POSIX sysconf */
252 arg1 = SCARG(uap, arg1); /* system variable name */
253 return irix_syssgi_sysconf((int)arg1, l, retval);
254 break;
255
256 case IRIX_SGI_SATCTL: /* control audit stream */
257 case IRIX_SGI_RXEV_GET: /* Trusted IRIX call */
258 /* Undocumented (?) and unimplemented */
259 return 0;
260 break;
261
262 case IRIX_SGI_FDHI: /* getdtablehi(3): get higher open fd + 1 */
263 *retval = (register_t)(p->p_fd->fd_lastfile + 1);
264 return 0;
265 break;
266
267 default:
268 printf("Warning: call to unimplemented syssgi() command %d\n",
269 request);
270 return EINVAL;
271 break;
272 }
273
274 return 0;
275 }
276
277 static int
278 irix_syssgi_mapelf(int fd, Elf_Phdr *ph, int count, struct lwp *l, register_t *retval)
279 {
280 Elf_Phdr *kph;
281 Elf_Phdr *pht;
282 int error = 0;
283 int i,j;
284 int prot;
285 int flags;
286 u_long size;
287 Elf_Addr uaddr;
288 Elf_Addr reloc_offset;
289 file_t *fp;
290 struct exec_vmcmd_set vcset;
291 struct exec_vmcmd *base_vcp = NULL;
292 struct vnode *vp;
293 struct vm_map_entry *ret;
294 struct exec_vmcmd *vcp;
295 int need_relocation;
296
297 vcset.evs_cnt = 0;
298 vcset.evs_used = 0;
299
300 kph = (Elf_Phdr *)malloc(sizeof(Elf_Phdr) * count, M_TEMP, M_WAITOK);
301 error = copyin(ph, kph, sizeof(Elf_Phdr) * count);
302 if (error)
303 goto bad;
304
305 pht = kph;
306 need_relocation = 0;
307 for (i = 0; i < count; i++) {
308 /* Check that each ELF sections is loadable */
309 if (pht->p_type != PT_LOAD) {
310 error = ENOEXEC;
311 goto bad;
312 }
313
314 /*
315 * Check that the section load addresses are increasing
316 * with the section in the program header array. We do
317 * not support any other situation.
318 */
319 if (pht->p_vaddr < kph->p_vaddr) {
320 #ifdef DEBUG_IRIX
321 printf("mapelf: unsupported psection order\n");
322 #endif
323 error = EINVAL;
324 goto bad;
325 }
326
327 /*
328 * Check that the default load addresses are free.
329 * If not, we will have to perform a relocation
330 */
331 ret = uvm_map_findspace(&l->l_proc->p_vmspace->vm_map,
332 pht->p_vaddr, pht->p_memsz, (vaddr_t *)(void *)&uaddr,
333 NULL, 0, 0, UVM_FLAG_FIXED);
334 if (ret == NULL)
335 need_relocation = 1;
336 pht++;
337 }
338
339 /*
340 * Perform a relocation
341 */
342 if (need_relocation) {
343 /*
344 * compute the size needed by the section union. This
345 * assumes that the section load addresses are increasing.
346 * (And also that the sections are not overlapping)
347 */
348 pht--;
349 size = ELF_ROUND((pht->p_vaddr + pht->p_memsz), pht->p_align) -
350 ELF_TRUNC(kph->p_vaddr, kph->p_align);
351
352 /* Find a free place for the sections */
353 ret = uvm_map_findspace(&l->l_proc->p_vmspace->vm_map,
354 IRIX_MAPELF_RELOCATE, size, (vaddr_t *)(void *)&uaddr,
355 NULL, 0, kph->p_align, 0);
356
357 if (ret == NULL) {
358 error = ENOMEM;
359 goto bad;
360 }
361
362 /*
363 * Relocate the sections, all with the same offset.
364 */
365 reloc_offset = uaddr - kph->p_vaddr;
366 pht = kph;
367 for (i = 0; i < count; i++) {
368 #ifdef DEBUG_IRIX
369 printf("mapelf: relocating section %d from %p to %p\n",
370 i, (void *)pht->p_vaddr,
371 (void *)(pht->p_vaddr + reloc_offset));
372 #endif
373 pht->p_vaddr += reloc_offset;
374 pht++;
375 }
376 }
377
378 /* Find the file's vnode */
379 fp = fd_getfile(fd);
380 if (fp == NULL) {
381 error = EBADF;
382 goto bad;
383 }
384 vp = fp->f_data;
385
386 error = vn_marktext(vp);
387 if (error)
388 goto bad_unuse;
389
390 /*
391 * Load the sections
392 */
393 pht = kph;
394 for (i = 0; i < count; i++) {
395 #ifdef DEBUG_IRIX
396 printf("mapelf: loading section %d (len 0x%08lx) at %p\n",
397 i, (long)pht->p_memsz, (void *)pht->p_vaddr);
398 #endif
399 /* Build the vmcmds for loading the section */
400 kill_vmcmds(&vcset);
401 uaddr = pht->p_vaddr;
402 size = 0;
403 prot = 0;
404 flags = VMCMD_BASE;
405
406 ELFNAME(load_psection)(&vcset, vp, pht, &uaddr,
407 &size, &prot, flags);
408
409 /* Execute the vmcmds */
410 for (j = 0; j < vcset.evs_used && !error; j++) {
411 vcp = &vcset.evs_cmds[j];
412 if (vcp->ev_flags & VMCMD_RELATIVE) {
413 if (base_vcp == NULL)
414 panic("irix_syssgi_mapelf(): bad vmcmd base");
415
416 vcp->ev_addr += base_vcp->ev_addr;
417 }
418 IRIX_VM_SYNC(l->l_proc, error = (*vcp->ev_proc)(l, vcp));
419 if (error)
420 goto bad_unuse;
421 }
422 pht++;
423 }
424
425 *retval = (register_t)kph->p_vaddr;
426
427 bad_unuse:
428 fd_putfile(fd);
429 bad:
430 free(kph, M_TEMP);
431 return error;
432 }
433
434
435
436 static int
437 irix_syssgi_sysconf(int name, struct lwp *l, register_t *retval)
438 {
439 struct proc *p = l->l_proc;
440 int error = 0;
441 int mib[2], value;
442 size_t len = sizeof(value);
443
444 switch (name) {
445 case IRIX_SC_ARG_MAX:
446 mib[0] = CTL_KERN;
447 mib[1] = KERN_ARGMAX;
448 break;
449 case IRIX_SC_CHILD_MAX:
450 *retval = (register_t)p->p_rlimit[RLIMIT_NPROC].rlim_cur;
451 return 0;
452 break;
453 case IRIX_SC_CLK_TCK:
454 *retval = hz;
455 return 0;
456 break;
457 case IRIX_SC_NGROUPS_MAX:
458 mib[0] = CTL_KERN;
459 mib[1] = KERN_NGROUPS;
460 break;
461 case IRIX_SC_OPEN_MAX:
462 *retval = (register_t)p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
463 return 0;
464 break;
465 case IRIX_SC_JOB_CONTROL:
466 mib[0] = CTL_KERN;
467 mib[1] = KERN_JOB_CONTROL;
468 break;
469 case IRIX_SC_SAVED_IDS:
470 mib[0] = CTL_KERN;
471 mib[1] = KERN_SAVED_IDS;
472 break;
473 case IRIX_SC_IP_SECOPTS:/* IP security options */
474 /* Trusted IRIX capabilities are unsupported */
475 case IRIX_SC_ACL: /* ACcess Lists */
476 case IRIX_SC_AUDIT: /* Audit */
477 case IRIX_SC_INF: /* Information labels */
478 case IRIX_SC_MAC: /* Mandatory Access Control */
479 case IRIX_SC_CAP: /* Capabilities */
480 *retval = 0;
481 return 0;
482 break;
483 case IRIX_SC_PAGESIZE:
484 mib[0] = CTL_HW;
485 mib[1] = HW_PAGESIZE;
486 break;
487
488 case IRIX_SC_PASS_MAX:
489 case IRIX_SC_VERSION:
490 default:
491 printf("Warning: syssgi(SYSCONF) unsupported variable %d\n",
492 name);
493 return EINVAL;
494 break;
495 }
496
497 /*
498 * calling into sysctl with superuser privs, but we don't mind
499 * 'cause we're only querying a value.
500 */
501 error = old_sysctl(&mib[0], 2, &value, &len, NULL, 0, NULL);
502 if (error == 0)
503 *retval = value;
504 return (error);
505 }
506
507 static int
508 irix_syssgi_pathconf(char *path, int name, struct lwp *l, register_t *retval)
509 {
510 struct sys_pathconf_args cup;
511 int bname;
512
513 switch (name) {
514 case IRIX_PC_LINK_MAX:
515 case IRIX_PC_MAX_CANON:
516 case IRIX_PC_MAX_INPUT:
517 case IRIX_PC_NAME_MAX:
518 case IRIX_PC_PATH_MAX:
519 case IRIX_PC_PIPE_BUF:
520 case IRIX_PC_CHOWN_RESTRICTED:
521 case IRIX_PC_NO_TRUNC:
522 case IRIX_PC_VDISABLE:
523 case IRIX_PC_SYNC_IO:
524 bname = name;
525 break;
526 case IRIX_PC_FILESIZEBITS:
527 bname = _PC_FILESIZEBITS;
528 break;
529 case IRIX_PC_PRIO_IO:
530 case IRIX_PC_ASYNC_IO:
531 case IRIX_PC_ABI_ASYNC_IO:
532 case IRIX_PC_ABI_AIO_XFER_MAX:
533 default:
534 printf("Warning: unimplemented IRIX pathconf() command %d\n",
535 name);
536 *retval = 0;
537 return 0;
538 break;
539 }
540 SCARG(&cup, path) = path;
541 SCARG(&cup, name) = bname;
542 return sys_pathconf(l, &cup, retval);
543 }
Cache object: 8ac31d59c24ef7f9b305c21c208d3448
|