NetBSD/sys/compat/irix/irix_syssgi.c
chs e07f0b9362 eliminate uvm_useracc() in favor of checking the return value of
copyin() or copyout().

uvm_useracc() tells us whether the mapping permissions allow access to
the desired part of an address space, and many callers assume that
this is the same as knowing whether an attempt to access that part of
the address space will succeed.  however, access to user space can
fail for reasons other than insufficient permission, most notably that
paging in any non-resident data can fail due to i/o errors.  most of
the callers of uvm_useracc() make the above incorrect assumption.  the
rest are all misguided optimizations, which optimize for the case
where an operation will fail.  we'd rather optimize for operations
succeeding, in which case we should just attempt the access and handle
failures due to insufficient permissions the same way we handle i/o
errors.  since there appear to be no good uses of uvm_useracc(), we'll
just remove it.
2003-11-13 03:09:28 +00:00

578 lines
15 KiB
C

/* $NetBSD: irix_syssgi.c,v 1.38 2003/11/13 03:09:29 chs Exp $ */
/*-
* Copyright (c) 2001-2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Emmanuel Dreyfus.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: irix_syssgi.c,v 1.38 2003/11/13 03:09:29 chs Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ddb.h"
#endif
#ifndef ELFSIZE
#define ELFSIZE 32
#endif
/* round up and down to page boundaries. Borrowed from sys/kern/exec_elf32.c */
#define ELF_ROUND(a, b) (((a) + (b) - 1) & ~((b) - 1))
#define ELF_TRUNC(a, b) ((a) & ~((b) - 1))
#include <sys/types.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/filedesc.h>
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/resourcevar.h>
#include <sys/sysctl.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#include <sys/mount.h>
#include <sys/sa.h>
#include <sys/syscallargs.h>
#include <uvm/uvm_extern.h>
#include <compat/common/compat_util.h>
#include <compat/svr4/svr4_types.h>
#include <compat/irix/irix_types.h>
#include <compat/irix/irix_signal.h>
#include <compat/irix/irix_exec.h>
#include <compat/irix/irix_prctl.h>
#include <compat/irix/irix_syscall.h>
#include <compat/irix/irix_syscallargs.h>
#include <compat/irix/irix_syssgi.h>
/* In sys/kern/exec_elf32.c */
void ELFNAME(load_psection)(struct exec_vmcmd_set *, struct vnode *,
const Elf_Phdr *, Elf_Addr *, u_long *, int *, int);
static int irix_syssgi_mapelf __P((int, Elf_Phdr *, int,
struct proc *, register_t *));
static int irix_syssgi_sysconf __P((int name, struct lwp *, register_t *));
static int irix_syssgi_pathconf __P((char *, int, struct lwp *, register_t *));
int
irix_sys_syssgi(l, v, retval)
struct lwp *l;
void *v;
register_t *retval;
{
struct irix_sys_syssgi_args /* {
syscallarg(int) request;
syscallarg(void *) arg1;
syscallarg(void *) arg2;
syscallarg(void *) arg3;
syscallarg(void *) arg4;
syscallarg(void *) arg5;
} */ *uap = v;
struct proc *p = l->l_proc;
int request = SCARG(uap, request);
void *arg1, *arg2, *arg3;
#ifdef DEBUG_IRIX
printf("irix_sys_syssgi(): request = %d\n", request);
#endif
switch(request) {
case IRIX_SGI_SYSID: /* Get HostID */
*retval = (register_t)hostid;
break;
case IRIX_SGI_SETGROUPS: { /* setgroups(2) */
struct sys_setgroups_args cup;
SCARG(&cup, gidsetsize) = (int)SCARG(uap, arg1);
SCARG(&cup, gidset) = (gid_t *)SCARG(uap, arg2);
return (sys_setgroups(l, &cup, retval));
break;
}
case IRIX_SGI_GETGROUPS: { /* getgroups(2) */
struct sys_getgroups_args cup;
SCARG(&cup, gidsetsize) = (int)SCARG(uap, arg1);
SCARG(&cup, gidset) = (gid_t *)SCARG(uap, arg2);
return (sys_getgroups(l, &cup, retval));
break;
}
case IRIX_SGI_SETSID: /* Set session ID: setsid(2) */
return (sys_setsid(l, NULL, retval));
break;
case IRIX_SGI_GETSID: { /* Get session ID: getsid(2) */
struct sys_getsid_args cup;
SCARG(&cup, pid) = (pid_t)SCARG(uap, arg1);
return (sys_getsid(l, &cup, retval));
break;
}
case IRIX_SGI_GETPGID: {/* Get parent process GID: getpgid(2) */
struct sys_getpgid_args cup;
SCARG(&cup, pid) = (pid_t)SCARG(uap, arg1);
return (sys_getpgid(l, &cup, retval));
break;
}
case IRIX_SGI_SETPGID: {/* Get parent process GID: setpgid(2) */
struct sys_setpgid_args cup;
SCARG(&cup, pid) = (pid_t)SCARG(uap, arg1);
SCARG(&cup, pgid) = (pid_t)SCARG(uap, arg2);
return (sys_setpgid(l, &cup, retval));
break;
}
case IRIX_SGI_PATHCONF: /* Get file limits: pathconf(3) */
return irix_syssgi_pathconf((char *)SCARG(uap, arg1),
(int)SCARG(uap, arg2), l, retval);
break;
case IRIX_SGI_RUSAGE: { /* BSD getrusage(2) */
struct sys_getrusage_args cup;
SCARG(&cup, who) = (int)SCARG(uap, arg1);
SCARG(&cup, rusage) = (struct rusage *)SCARG(uap, arg2);
return sys_getrusage(l, &cup, retval);
break;
}
case IRIX_SGI_NUM_MODULES: /* <sys/systeminfo.h> get_num_modules() */
*retval = 1;
return 0;
break;
case IRIX_SGI_MODULE_INFO: { /* <sys/systeminfo.h> get_module_info() */
int module_num = (int)SCARG(uap, arg1);
struct irix_module_info_s *imip = SCARG(uap, arg2);
int mss = (int)SCARG(uap, arg3);
struct irix_module_info_s imi;
char *idx;
if (module_num != 0)
return EINVAL;
imi.serial_num = (u_int64_t)hostid;
imi.mod_num = 0;
(void)snprintf(imi.serial_str, IRIX_MAX_SERIAL_SIZE,
"0800%08x", (u_int32_t)hostid);
/* Convert to upper case */
for (idx = imi.serial_str; *idx; idx++)
if (*idx >= 'a' && *idx <= 'f')
*idx += ('A' - 'a');
/* Don't copyout irrelevant data on user request */
if (mss > sizeof(struct irix_module_info_s))
mss = sizeof(struct irix_module_info_s);
return copyout(&imi, imip, mss);
break;
}
case IRIX_SGI_RDNAME: { /* Read Processes' name */
struct proc *tp;
arg1 = SCARG(uap, arg1); /* PID of the process */
arg2 = SCARG(uap, arg2); /* Address of user buffer */
arg3 = SCARG(uap, arg3); /* Length of user buffer */
tp = pfind((pid_t)arg1);
if (tp == NULL || \
tp->p_psstr == NULL || \
tp->p_psstr->ps_argvstr == NULL || \
tp->p_psstr->ps_argvstr[0] == NULL)
return 0;
*retval = (register_t)copyout(tp->p_psstr->ps_argvstr[0],
(void *)arg2, (size_t)arg3);
break;
}
case IRIX_SGI_TUNE: /* Tune system variables */
case IRIX_SGI_IDBG: /* Kernel debugging */
case IRIX_SGI_INVENT: /* Get system inventory */
case IRIX_SGI_SETLED: /* Turn on/off LEDs */
case IRIX_SGI_SETNVRAM: /* Sets a NVRAM variable value */
case IRIX_SGI_GETNVRAM: /* Gets a NVRAM variable value */
return EINVAL;
break;
case IRIX_SGI_ELFMAP: /* Maps an ELF image */
arg1 = SCARG(uap, arg1); /* file descriptor */
arg2 = SCARG(uap, arg2); /* ptr to ELF program header array */
arg3 = SCARG(uap, arg3); /* array's length */
return irix_syssgi_mapelf((int)arg1, (Elf_Phdr *)arg2,
(int)arg3, p, retval);
break;
case IRIX_SGI_USE_FP_BCOPY: /* bcopy and bzero can use FPU or not */
/*
* Our kernel does not use FPU, hence we do nothing.
*/
break;
case IRIX_SGI_TOSSTSAVE: /* Kill saved pregions */
/*
* Our kernel does not seem to save such "pregions",
* therefore we do not have to do anything.
*/
break;
case IRIX_SGI_SYSCONF: /* POSIX sysconf */
arg1 = SCARG(uap, arg1); /* system variable name */
return irix_syssgi_sysconf((int)arg1, l, retval);
break;
case IRIX_SGI_SATCTL: /* control audit stream */
case IRIX_SGI_RXEV_GET: /* Trusted IRIX call */
/* Undocumented (?) and unimplemented */
return 0;
break;
case IRIX_SGI_FDHI: /* getdtablehi(3): get higher open fd + 1 */
*retval = (register_t)(p->p_fd->fd_lastfile + 1);
return 0;
break;
default:
printf("Warning: call to unimplemented syssgi() command %d\n",
request);
return EINVAL;
break;
}
return 0;
}
static int
irix_syssgi_mapelf(fd, ph, count, p, retval)
int fd;
Elf_Phdr *ph;
int count;
struct proc *p;
register_t *retval;
{
Elf_Phdr *kph;
Elf_Phdr *pht;
int error = 0;
int i,j;
int prot;
int flags;
u_long size;
Elf_Addr uaddr;
Elf_Addr reloc_offset;
struct file *fp;
struct filedesc *fdp;
struct exec_vmcmd_set vcset;
struct exec_vmcmd *base_vcp = NULL;
struct vnode *vp;
struct vm_map_entry *ret;
struct exec_vmcmd *vcp;
int need_relocation;
vcset.evs_cnt = 0;
vcset.evs_used = 0;
kph = (Elf_Phdr *)malloc(sizeof(Elf_Phdr) * count, M_TEMP, M_WAITOK);
error = copyin(ph, kph, sizeof(Elf_Phdr) * count);
if (error)
goto bad;
pht = kph;
need_relocation = 0;
for (i = 0; i < count; i++) {
/* Check that each ELF sections is loadable */
if (pht->p_type != PT_LOAD) {
error = ENOEXEC;
goto bad;
}
/*
* Check that the section load addresses are increasing
* with the section in the program header array. We do
* not support any other situation.
*/
if (pht->p_vaddr < kph->p_vaddr) {
#ifdef DEBUG_IRIX
printf("mapelf: unsupported psection order\n");
#endif
error = EINVAL;
goto bad;
}
/*
* Check that the default load addresses are free.
* If not, we will have to perform a relocation
*/
ret = uvm_map_findspace(&p->p_vmspace->vm_map,
pht->p_vaddr, pht->p_memsz, (vaddr_t *)(void *)&uaddr,
NULL, 0, 0, UVM_FLAG_FIXED);
if (ret == NULL)
need_relocation = 1;
pht++;
}
/*
* Perform a relocation
*/
if (need_relocation) {
/*
* compute the size needed by the section union. This
* assumes that the section load addresses are increasing.
* (And also that the sections are not overlapping)
*/
pht--;
size = ELF_ROUND((pht->p_vaddr + pht->p_memsz), pht->p_align) -
ELF_TRUNC(kph->p_vaddr, kph->p_align);
/* Find a free place for the sections */
ret = uvm_map_findspace(&p->p_vmspace->vm_map,
IRIX_MAPELF_RELOCATE, size, (vaddr_t *)(void *)&uaddr,
NULL, 0, kph->p_align, 0);
if (ret == NULL) {
error = ENOMEM;
goto bad;
}
/*
* Relocate the sections, all with the same offset.
*/
reloc_offset = uaddr - kph->p_vaddr;
pht = kph;
for (i = 0; i < count; i++) {
#ifdef DEBUG_IRIX
printf("mapelf: relocating section %d from %p to %p\n",
i, (void *)pht->p_vaddr,
(void *)(pht->p_vaddr + reloc_offset));
#endif
pht->p_vaddr += reloc_offset;
pht++;
}
}
/* Find the file's vnode */
fdp = p->p_fd;
fp = fd_getfile(fdp, fd);
if (fp == NULL) {
error = EBADF;
goto bad;
}
FILE_USE(fp);
vp = (struct vnode *)fp->f_data;
error = vn_marktext(vp);
if (error)
goto bad_unuse;
/*
* Load the sections
*/
pht = kph;
for (i = 0; i < count; i++) {
#ifdef DEBUG_IRIX
printf("mapelf: loading section %d (len 0x%08lx) at %p\n",
i, (long)pht->p_memsz, (void *)pht->p_vaddr);
#endif
/* Build the vmcmds for loading the section */
kill_vmcmds(&vcset);
uaddr = pht->p_vaddr;
size = 0;
prot = 0;
flags = VMCMD_BASE;
ELFNAME(load_psection)(&vcset, vp, pht, &uaddr,
&size, &prot, flags);
/* Execute the vmcmds */
for (j = 0; j < vcset.evs_used && !error; j++) {
vcp = &vcset.evs_cmds[j];
if (vcp->ev_flags & VMCMD_RELATIVE) {
if (base_vcp == NULL)
panic("irix_syssgi_mapelf(): bad vmcmd base");
vcp->ev_addr += base_vcp->ev_addr;
}
IRIX_VM_SYNC(p, error = (*vcp->ev_proc)(p, vcp));
if (error)
goto bad_unuse;
}
pht++;
}
*retval = (register_t)kph->p_vaddr;
bad_unuse:
FILE_UNUSE(fp, p);
bad:
free(kph, M_TEMP);
return error;
}
static int
irix_syssgi_sysconf(name, l, retval)
int name;
struct lwp *l;
register_t *retval;
{
struct proc *p = l->l_proc;
int error = 0;
int mib[2], value;
int len = sizeof(value);
struct sys___sysctl_args cup;
caddr_t sg = stackgap_init(p, 0);
switch (name) {
case IRIX_SC_ARG_MAX:
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
break;
case IRIX_SC_CHILD_MAX:
*retval = (register_t)p->p_rlimit[RLIMIT_NPROC].rlim_cur;
return 0;
break;
case IRIX_SC_CLK_TCK:
*retval = hz;
return 0;
break;
case IRIX_SC_NGROUPS_MAX:
mib[0] = CTL_KERN;
mib[1] = KERN_NGROUPS;
break;
case IRIX_SC_OPEN_MAX:
*retval = (register_t)p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
return 0;
break;
case IRIX_SC_JOB_CONTROL:
mib[0] = CTL_KERN;
mib[1] = KERN_JOB_CONTROL;
break;
case IRIX_SC_SAVED_IDS:
mib[0] = CTL_KERN;
mib[1] = KERN_SAVED_IDS;
break;
case IRIX_SC_IP_SECOPTS:/* IP security options */
/* Trusted IRIX capabilities are unsupported */
case IRIX_SC_ACL: /* ACcess Lists */
case IRIX_SC_AUDIT: /* Audit */
case IRIX_SC_INF: /* Information labels */
case IRIX_SC_MAC: /* Mandatory Access Control */
case IRIX_SC_CAP: /* Capabilities */
*retval = 0;
return 0;
break;
case IRIX_SC_PAGESIZE:
mib[0] = CTL_HW;
mib[1] = HW_PAGESIZE;
break;
case IRIX_SC_PASS_MAX:
case IRIX_SC_VERSION:
default:
printf("Warning: syssgi(SYSCONF) unsupported variable %d\n",
name);
return EINVAL;
break;
}
SCARG(&cup, name) = stackgap_alloc(p, &sg, sizeof(mib));
if ((error = copyout(&mib, SCARG(&cup, name), sizeof(mib))) != 0)
return error;
SCARG(&cup, namelen) = sizeof(mib);
SCARG(&cup, old) = stackgap_alloc(p, &sg, sizeof(value));
if ((copyout(&value, SCARG(&cup, old), sizeof(value))) != 0)
return error;
SCARG(&cup, oldlenp) = stackgap_alloc(p, &sg, sizeof(len));
if ((copyout(&len, SCARG(&cup, oldlenp), sizeof(len))) != 0)
return error;
SCARG(&cup, new) = NULL;
SCARG(&cup, newlen) = 0;
return sys___sysctl(l, &cup, retval);
}
static int
irix_syssgi_pathconf(path, name, l, retval)
char *path;
int name;
struct lwp *l;
register_t *retval;
{
struct sys_pathconf_args cup;
int bname;
switch (name) {
case IRIX_PC_LINK_MAX:
case IRIX_PC_MAX_CANON:
case IRIX_PC_MAX_INPUT:
case IRIX_PC_NAME_MAX:
case IRIX_PC_PATH_MAX:
case IRIX_PC_PIPE_BUF:
case IRIX_PC_CHOWN_RESTRICTED:
case IRIX_PC_NO_TRUNC:
case IRIX_PC_VDISABLE:
case IRIX_PC_SYNC_IO:
bname = name;
break;
case IRIX_PC_FILESIZEBITS:
bname = _PC_FILESIZEBITS;
break;
case IRIX_PC_PRIO_IO:
case IRIX_PC_ASYNC_IO:
case IRIX_PC_ABI_ASYNC_IO:
case IRIX_PC_ABI_AIO_XFER_MAX:
default:
printf("Warning: unimplemented IRIX pathconf() command %d\n",
name);
*retval = 0;
return 0;
break;
}
SCARG(&cup, path) = path;
SCARG(&cup, name) = bname;
return sys_pathconf(l, &cup, retval);
}