aboutsummaryrefslogtreecommitdiff
path: root/arch/metag/kernel/sys_metag.c
blob: efe833a452f752fc9c549b0d49e3d103bd881b92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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>
};