summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/sys_sparc32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/sys_sparc32.c')
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c440
1 files changed, 287 insertions, 153 deletions
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index caad42736..a5043b3ac 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.77 1998/03/29 10:10:50 davem Exp $
+/* $Id: sys_sparc32.c,v 1.90 1998/07/29 16:32:30 jj Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -58,27 +58,10 @@
*/
#define A(x) ((unsigned long)x)
-extern char * getname_quicklist;
-extern int getname_quickcount;
-extern struct semaphore getname_quicklock;
-
-/* Tuning: increase locality by reusing same pages again...
- * if getname_quicklist becomes too long on low memory machines, either a limit
- * should be added or after a number of cycles some pages should
- * be released again ...
- */
static inline char * get_page(void)
{
char * res;
- down(&getname_quicklock);
- res = getname_quicklist;
- if (res) {
- getname_quicklist = *(char**)res;
- getname_quickcount--;
- }
- else
- res = (char*)__get_free_page(GFP_KERNEL);
- up(&getname_quicklock);
+ res = (char *)__get_free_page(GFP_KERNEL);
return res;
}
@@ -845,9 +828,6 @@ asmlinkage long sys32_readv(int fd, u32 vector, u32 count)
ret = do_readv_writev32(VERIFY_WRITE, file,
(struct iovec32 *)A(vector), count);
- if (ret > 0)
- current->io_usage += ret;
-
out:
fput(file);
bad_file:
@@ -872,9 +852,6 @@ asmlinkage long sys32_writev(int fd, u32 vector, u32 count)
ret = do_readv_writev32(VERIFY_READ, file,
(struct iovec32 *)A(vector), count);
up(&file->f_dentry->d_inode->i_sem);
- if (ret > 0)
- current->io_usage += ret;
-
out:
fput(file);
bad_file:
@@ -1148,6 +1125,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x)
put_user(sec, &tvp->tv_sec);
put_user(usec, &tvp->tv_usec);
}
+ current->timeout = 0;
if (ret < 0)
goto out;
@@ -1247,27 +1225,6 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
return ret;
}
-extern asmlinkage int sys_xstat(int ver, char *filename, struct stat64 * statbuf);
-
-asmlinkage int sys32_xstat(int ver, u32 file, u32 statbuf)
-{
- switch (ver & __XSTAT_VER_MASK) {
- case __XSTAT_VER_1:
- switch (ver & __XSTAT_VER_TYPEMASK) {
- case __XSTAT_VER_XSTAT:
- return sys32_newstat(file, statbuf);
- case __XSTAT_VER_LXSTAT:
- return sys32_newlstat(file, statbuf);
- case __XSTAT_VER_FXSTAT:
- return sys32_newfstat(file, statbuf);
- }
- return -EINVAL;
- case __XSTAT_VER_2:
- return sys_xstat(ver, (char *)A(file), (struct stat64 *)A(statbuf));
- }
- return -EINVAL;
-}
-
extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
@@ -2662,7 +2619,8 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
if(!error) {
fprs_write(0);
- regs->fprs = 0;
+ current->tss.xfsr[0] = 0;
+ current->tss.fpsaved[0] = 0;
regs->tstate &= ~TSTATE_PEF;
}
out:
@@ -2703,119 +2661,274 @@ struct module_info32 {
s32 usecount;
};
-extern asmlinkage int sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret);
+/* Query various bits about modules. */
+
+extern long get_mod_name(const char *user_name, char **buf);
+extern void put_mod_name(char *buf);
+extern struct module *find_module(const char *name);
+extern struct module kernel_module;
-asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv)
+static int
+qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
{
- char *buff;
- mm_segment_t old_fs = get_fs();
- size_t val;
- int ret, i, j;
- unsigned long *p;
- char *usernam = NULL;
- int bufsiz = bufsize;
- struct module_info mi;
-
- switch (which) {
- case 0: return sys_query_module ((const char *)A(name_user), which, (char *)A(buf), (size_t)bufsize, (size_t *)A(retv));
- case QM_SYMBOLS:
- bufsiz <<= 1;
- case QM_MODULES:
- case QM_REFS:
- case QM_DEPS:
- if (name_user) {
- usernam = getname32 (name_user);
- ret = PTR_ERR(usernam);
- if (IS_ERR(usernam))
- return ret;
- }
- buff = kmalloc (bufsiz, GFP_KERNEL);
- if (!buff) {
- if (name_user) putname32 (usernam);
- return -ENOMEM;
+ struct module *mod;
+ size_t nmod, space, len;
+
+ nmod = space = 0;
+
+ for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) {
+ len = strlen(mod->name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, mod->name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(nmod, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ space += len;
+ while ((mod = mod->next) != &kernel_module)
+ space += strlen(mod->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static int
+qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t i, space, len;
+
+ if (mod == &kernel_module)
+ return -EINVAL;
+ if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
+ if (put_user(0, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+ space = 0;
+ for (i = 0; i < mod->ndeps; ++i) {
+ const char *dep_name = mod->deps[i].dep->name;
+
+ len = strlen(dep_name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, dep_name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(i, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ space += len;
+ while (++i < mod->ndeps)
+ space += strlen(mod->deps[i].dep->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static int
+qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t nrefs, space, len;
+ struct module_ref *ref;
+
+ if (mod == &kernel_module)
+ return -EINVAL;
+ if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
+ if (put_user(0, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+ space = 0;
+ for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) {
+ const char *ref_name = ref->ref->name;
+
+ len = strlen(ref_name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, ref_name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(nrefs, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ space += len;
+ while ((ref = ref->next_ref) != NULL)
+ space += strlen(ref->ref->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static inline int
+qm_symbols(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t i, space, len;
+ struct module_symbol *s;
+ char *strings;
+ unsigned *vals;
+
+ if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING)
+ if (put_user(0, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+ space = mod->nsyms * 2*sizeof(u32);
+
+ i = len = 0;
+ s = mod->syms;
+
+ if (space > bufsize)
+ goto calc_space_needed;
+
+ if (!access_ok(VERIFY_WRITE, buf, space))
+ return -EFAULT;
+
+ bufsize -= space;
+ vals = (unsigned *)buf;
+ strings = buf+space;
+
+ for (; i < mod->nsyms ; ++i, ++s, vals += 2) {
+ len = strlen(s->name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+
+ if (copy_to_user(strings, s->name, len)
+ || __put_user(s->value, vals+0)
+ || __put_user(space, vals+1))
+ return -EFAULT;
+
+ strings += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(i, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ for (; i < mod->nsyms; ++i, ++s)
+ space += strlen(s->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static inline int
+qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ int error = 0;
+
+ if (mod == &kernel_module)
+ return -EINVAL;
+
+ if (sizeof(struct module_info32) <= bufsize) {
+ struct module_info32 info;
+ info.addr = (unsigned long)mod;
+ info.size = mod->size;
+ info.flags = mod->flags;
+ info.usecount = (mod_member_present(mod, can_unload)
+ && mod->can_unload ? -1 : mod->usecount);
+
+ if (copy_to_user(buf, &info, sizeof(struct module_info32)))
+ return -EFAULT;
+ } else
+ error = -ENOSPC;
+
+ if (put_user(sizeof(struct module_info32), ret))
+ return -EFAULT;
+
+ return error;
+}
+
+asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 ret)
+{
+ struct module *mod;
+ int err;
+
+ lock_kernel();
+ if (name_user == 0)
+ mod = &kernel_module;
+ else {
+ long namelen;
+ char *name;
+
+ if ((namelen = get_mod_name((char *)A(name_user), &name)) < 0) {
+ err = namelen;
+ goto out;
}
-qmsym_toshort:
- set_fs (KERNEL_DS);
- ret = sys_query_module (usernam, which, buff, bufsiz, &val);
- set_fs (old_fs);
- if (which != QM_SYMBOLS) {
- if (ret == -ENOSPC || !ret) {
- if (put_user (val, (__kernel_size_t32 *)A(retv)))
- ret = -EFAULT;
- }
- if (!ret) {
- if (copy_to_user ((char *)A(buf), buff, bufsize))
- ret = -EFAULT;
- }
- } else {
- if (ret == -ENOSPC) {
- if (put_user (2 * val, (__kernel_size_t32 *)A(retv)))
- ret = -EFAULT;
- }
- p = (unsigned long *)buff;
- if (!ret) {
- if (put_user (val, (__kernel_size_t32 *)A(retv)))
- ret = -EFAULT;
- }
- if (!ret) {
- j = val * 8;
- for (i = 0; i < val; i++, p += 2) {
- if (bufsize < (2 * sizeof (u32))) {
- bufsiz = 0;
- goto qmsym_toshort;
- }
- if (put_user (p[0], (u32 *)A(buf)) ||
- __put_user (p[1] - j, (((u32 *)A(buf))+1))) {
- ret = -EFAULT;
- break;
- }
- bufsize -= (2 * sizeof (u32));
- buf += (2 * sizeof (u32));
- }
- }
- if (!ret && val) {
- char *strings = buff + ((unsigned long *)buff)[1];
- j = *(p - 1) - ((unsigned long *)buff)[1];
- j = j + strlen (strings + j) + 1;
- if (bufsize < j) {
- bufsiz = 0;
- goto qmsym_toshort;
- }
- if (copy_to_user ((char *)A(buf), strings, j))
- ret = -EFAULT;
- }
+ err = -ENOENT;
+ if (namelen == 0)
+ mod = &kernel_module;
+ else if ((mod = find_module(name)) == NULL) {
+ put_mod_name(name);
+ goto out;
}
- kfree (buff);
- if (name_user) putname32 (usernam);
- return ret;
+ put_mod_name(name);
+ }
+
+ switch (which)
+ {
+ case 0:
+ err = 0;
+ break;
+ case QM_MODULES:
+ err = qm_modules((char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
+ case QM_DEPS:
+ err = qm_deps(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
+ case QM_REFS:
+ err = qm_refs(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
+ case QM_SYMBOLS:
+ err = qm_symbols(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
case QM_INFO:
- if (name_user) {
- usernam = getname32 (name_user);
- ret = PTR_ERR(usernam);
- if (IS_ERR(usernam))
- return ret;
- }
- set_fs (KERNEL_DS);
- ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val);
- set_fs (old_fs);
- if (!ret) {
- if (put_user (sizeof (struct module_info32), (__kernel_size_t32 *)A(retv)))
- ret = -EFAULT;
- else if (bufsize < sizeof (struct module_info32))
- ret = -ENOSPC;
- }
- if (!ret) {
- if (put_user (mi.addr, &(((struct module_info32 *)A(buf))->addr)) ||
- __put_user (mi.size, &(((struct module_info32 *)A(buf))->size)) ||
- __put_user (mi.flags, &(((struct module_info32 *)A(buf))->flags)) ||
- __put_user (mi.usecount, &(((struct module_info32 *)A(buf))->usecount)))
- ret = -EFAULT;
- }
- if (name_user) putname32 (usernam);
- return ret;
+ err = qm_info(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+ break;
default:
- return -EINVAL;
+ err = -EINVAL;
+ break;
}
+out:
+ unlock_kernel();
+ return err;
}
struct kernel_sym32 {
@@ -3356,3 +3469,24 @@ asmlinkage int sys32_personality(unsigned long personality)
ret = PER_LINUX;
return ret;
}
+
+extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
+
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, u32 offset, s32 count)
+{
+ mm_segment_t old_fs = get_fs();
+ int ret;
+ off_t of;
+
+ if (offset && get_user(of, (__kernel_off_t32 *)A(offset)))
+ return -EFAULT;
+
+ set_fs(KERNEL_DS);
+ ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+ set_fs(old_fs);
+
+ if (!ret && offset && put_user(of, (__kernel_off_t32 *)A(offset)))
+ return -EFAULT;
+
+ return ret;
+}