|
@@ -0,0 +1,180 @@
|
|
|
+/*
|
|
|
+ * This file contains various random system calls that
|
|
|
+ * have a non-standard calling sequence on the Linux/Meta
|
|
|
+ * platform.
|
|
|
+ */
|
|
|
+
|
|
|
+#include <linux/errno.h>
|
|
|
+#include <linux/sched.h>
|
|
|
+#include <linux/mm.h>
|
|
|
+#include <linux/syscalls.h>
|
|
|
+#include <linux/mman.h>
|
|
|
+#include <linux/file.h>
|
|
|
+#include <linux/fs.h>
|
|
|
+#include <linux/uaccess.h>
|
|
|
+#include <linux/unistd.h>
|
|
|
+#include <asm/cacheflush.h>
|
|
|
+#include <asm/core_reg.h>
|
|
|
+#include <asm/global_lock.h>
|
|
|
+#include <asm/switch.h>
|
|
|
+#include <asm/syscall.h>
|
|
|
+#include <asm/syscalls.h>
|
|
|
+#include <asm/user_gateway.h>
|
|
|
+
|
|
|
+#define merge_64(hi, lo) ((((unsigned long long)(hi)) << 32) + \
|
|
|
+ ((lo) & 0xffffffffUL))
|
|
|
+
|
|
|
+int metag_mmap_check(unsigned long addr, unsigned long len,
|
|
|
+ unsigned long flags)
|
|
|
+{
|
|
|
+ /* We can't have people trying to write to the bottom of the
|
|
|
+ * memory map, there are mysterious unspecified things there that
|
|
|
+ * we don't want people trampling on.
|
|
|
+ */
|
|
|
+ if ((flags & MAP_FIXED) && (addr < TASK_UNMAPPED_BASE))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
|
|
|
+ unsigned long prot, unsigned long flags,
|
|
|
+ unsigned long fd, unsigned long pgoff)
|
|
|
+{
|
|
|
+ /* The shift for mmap2 is constant, regardless of PAGE_SIZE setting. */
|
|
|
+ if (pgoff & ((1 << (PAGE_SHIFT - 12)) - 1))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pgoff >>= PAGE_SHIFT - 12;
|
|
|
+
|
|
|
+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage int sys_metag_setglobalbit(char __user *addr, int mask)
|
|
|
+{
|
|
|
+ char tmp;
|
|
|
+ int ret = 0;
|
|
|
+ unsigned int flags;
|
|
|
+
|
|
|
+ if (!((__force unsigned int)addr >= LINCORE_BASE))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ __global_lock2(flags);
|
|
|
+
|
|
|
+ metag_data_cache_flush((__force void *)addr, sizeof(mask));
|
|
|
+
|
|
|
+ ret = __get_user(tmp, addr);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+ tmp |= mask;
|
|
|
+ ret = __put_user(tmp, addr);
|
|
|
+
|
|
|
+ metag_data_cache_flush((__force void *)addr, sizeof(mask));
|
|
|
+
|
|
|
+out:
|
|
|
+ __global_unlock2(flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+#define TXDEFR_FPU_MASK ((0x1f << 16) | 0x1f)
|
|
|
+
|
|
|
+asmlinkage void sys_metag_set_fpu_flags(unsigned int flags)
|
|
|
+{
|
|
|
+ unsigned int temp;
|
|
|
+
|
|
|
+ flags &= TXDEFR_FPU_MASK;
|
|
|
+
|
|
|
+ temp = __core_reg_get(TXDEFR);
|
|
|
+ temp &= ~TXDEFR_FPU_MASK;
|
|
|
+ temp |= flags;
|
|
|
+ __core_reg_set(TXDEFR, temp);
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage int sys_metag_set_tls(void __user *ptr)
|
|
|
+{
|
|
|
+ current->thread.tls_ptr = ptr;
|
|
|
+ set_gateway_tls(ptr);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage void *sys_metag_get_tls(void)
|
|
|
+{
|
|
|
+ return (__force void *)current->thread.tls_ptr;
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage long sys_truncate64_metag(const char __user *path, unsigned long lo,
|
|
|
+ unsigned long hi)
|
|
|
+{
|
|
|
+ return sys_truncate64(path, merge_64(hi, lo));
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage long sys_ftruncate64_metag(unsigned int fd, unsigned long lo,
|
|
|
+ unsigned long hi)
|
|
|
+{
|
|
|
+ return sys_ftruncate64(fd, merge_64(hi, lo));
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage long sys_fadvise64_64_metag(int fd, unsigned long offs_lo,
|
|
|
+ unsigned long offs_hi,
|
|
|
+ unsigned long len_lo,
|
|
|
+ unsigned long len_hi, int advice)
|
|
|
+{
|
|
|
+ return sys_fadvise64_64(fd, merge_64(offs_hi, offs_lo),
|
|
|
+ merge_64(len_hi, len_lo), advice);
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage long sys_readahead_metag(int fd, unsigned long lo, unsigned long hi,
|
|
|
+ size_t count)
|
|
|
+{
|
|
|
+ return sys_readahead(fd, merge_64(hi, lo), count);
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage ssize_t sys_pread64_metag(unsigned long fd, char __user *buf,
|
|
|
+ size_t count, unsigned long lo,
|
|
|
+ unsigned long hi)
|
|
|
+{
|
|
|
+ return sys_pread64(fd, buf, count, merge_64(hi, lo));
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage ssize_t sys_pwrite64_metag(unsigned long fd, char __user *buf,
|
|
|
+ size_t count, unsigned long lo,
|
|
|
+ unsigned long hi)
|
|
|
+{
|
|
|
+ return sys_pwrite64(fd, buf, count, merge_64(hi, lo));
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage long sys_sync_file_range_metag(int fd, unsigned long offs_lo,
|
|
|
+ unsigned long offs_hi,
|
|
|
+ unsigned long len_lo,
|
|
|
+ unsigned long len_hi,
|
|
|
+ unsigned int flags)
|
|
|
+{
|
|
|
+ return sys_sync_file_range(fd, merge_64(offs_hi, offs_lo),
|
|
|
+ merge_64(len_hi, len_lo), flags);
|
|
|
+}
|
|
|
+
|
|
|
+/* Provide the actual syscall number to call mapping. */
|
|
|
+#undef __SYSCALL
|
|
|
+#define __SYSCALL(nr, call) [nr] = (call),
|
|
|
+
|
|
|
+/*
|
|
|
+ * We need wrappers for anything with unaligned 64bit arguments
|
|
|
+ */
|
|
|
+#define sys_truncate64 sys_truncate64_metag
|
|
|
+#define sys_ftruncate64 sys_ftruncate64_metag
|
|
|
+#define sys_fadvise64_64 sys_fadvise64_64_metag
|
|
|
+#define sys_readahead sys_readahead_metag
|
|
|
+#define sys_pread64 sys_pread64_metag
|
|
|
+#define sys_pwrite64 sys_pwrite64_metag
|
|
|
+#define sys_sync_file_range sys_sync_file_range_metag
|
|
|
+
|
|
|
+/*
|
|
|
+ * Note that we can't include <linux/unistd.h> here since the header
|
|
|
+ * guard will defeat us; <asm/unistd.h> checks for __SYSCALL as well.
|
|
|
+ */
|
|
|
+const void *sys_call_table[__NR_syscalls] = {
|
|
|
+ [0 ... __NR_syscalls-1] = sys_ni_syscall,
|
|
|
+#include <asm/unistd.h>
|
|
|
+};
|