summaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/sysmips.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/sysmips.c')
-rw-r--r--arch/mips/kernel/sysmips.c110
1 files changed, 67 insertions, 43 deletions
diff --git a/arch/mips/kernel/sysmips.c b/arch/mips/kernel/sysmips.c
index d15aaa4dd..4aff0bc61 100644
--- a/arch/mips/kernel/sysmips.c
+++ b/arch/mips/kernel/sysmips.c
@@ -15,10 +15,9 @@
#include <linux/utsname.h>
#include <asm/cachectl.h>
-#include <asm/cache.h>
-#include <asm/ipc.h>
-#include <asm/uaccess.h>
+#include <asm/pgtable.h>
#include <asm/sysmips.h>
+#include <asm/uaccess.h>
static inline size_t
strnlen_user(const char *s, size_t count)
@@ -26,12 +25,35 @@ strnlen_user(const char *s, size_t count)
return strnlen(s, count);
}
+/*
+ * How long a hostname can we get from user space?
+ * -EFAULT if invalid area or too long
+ * 0 if ok
+ * >0 EFAULT after xx bytes
+ */
+static inline int
+get_max_hostname(unsigned long address)
+{
+ struct vm_area_struct * vma;
+
+ vma = find_vma(current->mm, address);
+ if (!vma || vma->vm_start > address || !(vma->vm_flags & VM_READ))
+ return -EFAULT;
+ address = vma->vm_end - address;
+ if (address > PAGE_SIZE)
+ return 0;
+ if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
+ (vma->vm_next->vm_flags & VM_READ))
+ return 0;
+ return address;
+}
+
asmlinkage int
sys_sysmips(int cmd, int arg1, int arg2, int arg3)
{
int *p;
char *name;
- int flags, tmp, len, retval;
+ int flags, tmp, len, retval = -EINVAL;
switch(cmd)
{
@@ -39,70 +61,39 @@ sys_sysmips(int cmd, int arg1, int arg2, int arg3)
if (!suser())
return -EPERM;
name = (char *) arg1;
+ len = get_max_hostname((unsigned long)name);
+ if (retval < 0)
+ return len;
len = strnlen_user(name, retval);
- if (len < 0)
- retval = len;
- break;
if (len == 0 || len > __NEW_UTS_LEN)
- retval = -EINVAL;
- break;
+ return -EINVAL;
copy_from_user(system_utsname.nodename, name, len);
system_utsname.nodename[len] = '\0';
return 0;
-
case MIPS_ATOMIC_SET:
- /* This is broken in case of page faults and SMP ...
- Risc/OS fauls after maximum 20 tries with EAGAIN. */
p = (int *) arg1;
retval = verify_area(VERIFY_WRITE, p, sizeof(*p));
- if (retval)
- return retval;
+ if(retval)
+ return -EINVAL;
save_flags(flags);
cli();
retval = *p;
*p = arg2;
restore_flags(flags);
- break;
-
+ return retval;
case MIPS_FIXADE:
tmp = current->tss.mflags & ~3;
current->tss.mflags = tmp | (arg1 & 3);
retval = 0;
break;
-
case FLUSH_CACHE:
- cacheflush(0, ~0, CF_BCACHE|CF_ALL);
- break;
-
- case MIPS_RDNVRAM:
- retval = -EIO;
- break;
-
- default:
- retval = -EINVAL;
+ flush_cache_all();
break;
}
return retval;
}
-asmlinkage int
-sys_cacheflush(void *addr, int nbytes, int cache)
-{
- unsigned int rw;
- int ok;
-
- if ((cache & ~(DCACHE | ICACHE)) != 0)
- return -EINVAL;
- rw = (cache & DCACHE) ? VERIFY_WRITE : VERIFY_READ;
- if (!access_ok(rw, addr, nbytes))
- return -EFAULT;
-
- cacheflush((unsigned long)addr, (unsigned long)nbytes, cache|CF_ALL);
-
- return 0;
-}
-
/*
* No implemented yet ...
*/
@@ -111,3 +102,36 @@ sys_cachectl(char *addr, int nbytes, int op)
{
return -ENOSYS;
}
+
+/* For emulation of various binary types, and their shared libs,
+ * we need this.
+ */
+
+extern int do_open_namei(const char *pathname, int flag, int mode,
+ struct inode **res_inode, struct inode *base);
+
+/* Only one at this time. */
+#define IRIX32_EMUL "/usr/gnemul/irix"
+
+int open_namei(const char *pathname, int flag, int mode,
+ struct inode **res_inode, struct inode *base)
+{
+ if(!base && (current->personality == PER_IRIX32) &&
+ *pathname == '/') {
+ struct inode *emul_ino;
+ const char *p = pathname;
+ char *emul_path = IRIX32_EMUL;
+ int v;
+
+ while (*p == '/')
+ p++;
+
+ if(do_open_namei (emul_path, flag, mode, &emul_ino, NULL) >= 0 &&
+ emul_ino) {
+ v = do_open_namei (p, flag, mode, res_inode, emul_ino);
+ if(v >= 0)
+ return v;
+ }
+ }
+ return do_open_namei (pathname, flag, mode, res_inode, base);
+}