Exposed SPARC iobus to userspace
[akaros.git] / kern / arch / sparc / syscalls.c
1 #include <string.h>
2 #include <process.h>
3 #include <kmalloc.h>
4 #include <ros/error.h>
5 #include <pmap.h>
6 #include <mm.h>
7 #include <arch/frontend.h>
8 #include <syscall.h>
9
10 void* user_memdup(struct proc* p, const void* va, int len)
11 {
12         void* kva = NULL;
13         if(len < 0 || (kva = kmalloc(len,0)) == NULL)
14                 return ERR_PTR(-ENOMEM);
15         if(memcpy_from_user(p,kva,va,len))
16         {
17                 kfree(kva);
18                 return ERR_PTR(-EINVAL);
19         }
20
21         return kva;
22 }
23
24 static void* user_memdup_errno(struct proc* p, const void* va, int len)
25 {
26         void* kva = user_memdup(p,va,len);
27         if(IS_ERR(kva))
28         {
29                 set_errno(current_tf,-PTR_ERR(kva));
30                 return NULL;
31         }
32         return kva;
33 }
34
35 static void user_memdup_free(struct proc* p, void* va)
36 {
37         kfree(va);
38 }
39
40 char* user_strdup(struct proc* p, const char* va0, int max)
41 {
42         max++;
43         char* kbuf = (char*)kmalloc(PGSIZE,0);
44         if(kbuf == NULL)
45                 return ERR_PTR(-ENOMEM);
46
47         int pos = 0, len = 0;
48         const char* va = va0;
49         while(max > 0 && len == 0)
50         {
51                 int thislen = MIN(PGSIZE-(intptr_t)va%PGSIZE,max);
52                 if(memcpy_from_user(p,kbuf,va,thislen))
53                 {
54                         kfree(kbuf);
55                         return ERR_PTR(-EINVAL);
56                 }
57
58                 const char* nullterm = memchr(kbuf,0,thislen);
59                 if(nullterm)
60                         len = pos+(nullterm-kbuf)+1;
61
62                 pos += thislen;
63                 va += thislen;
64                 max -= thislen;
65         }
66
67         kfree(kbuf);
68         return len ? user_memdup(p,va0,len) : ERR_PTR(-EINVAL);
69 }
70
71 static char* user_strdup_errno(struct proc* p, const char* va, int max)
72 {
73         void* kva = user_strdup(p,va,max);
74         if(IS_ERR(kva))
75         {
76                 set_errno(current_tf,-PTR_ERR(kva));
77                 return NULL;
78         }
79         return kva;
80 }
81
82 static int memcpy_to_user_errno(struct proc* p, void* dst, const void* src,
83                                 int len)
84 {
85         if(memcpy_to_user(p,dst,src,len))
86         {
87                 set_errno(current_tf,EINVAL);
88                 return -1;
89         }
90         return 0;
91 }
92
93 static void* kmalloc_errno(int len)
94 {
95         void* kva = NULL;
96         if(len < 0 || (kva = kmalloc(len,0)) == NULL)
97                 set_errno(current_tf,ENOMEM);
98         return kva;
99 }
100
101 int user_frontend_syscall_errno(struct proc* p, int n, int a0, int a1, int a2, int a3)
102 {
103         int errno, ret = frontend_syscall(p->pid,n,a0,a1,a2,a3,&errno);
104         if(errno && p)
105                 set_errno(current_tf,errno);
106         return ret;
107 }
108 #define fe(which,a0,a1,a2,a3) \
109         user_frontend_syscall_errno(p,RAMP_SYSCALL_##which,\
110                            (int)(a0),(int)(a1),(int)(a2),(int)(a3))
111
112 intreg_t sys_write(struct proc* p, int fd, const void* buf, int len)
113 {
114         void* kbuf = user_memdup_errno(p,buf,len);
115         if(kbuf == NULL)
116                 return -1;
117         int ret = fe(write,fd,PADDR(kbuf),len,0);
118         user_memdup_free(p,kbuf);
119         return ret;
120 }
121
122 intreg_t sys_read(struct proc* p, int fd, void* buf, int len)
123 {
124         void* kbuf = kmalloc_errno(len);
125         if(kbuf == NULL)
126                 return -1;
127         int ret = fe(read,fd,PADDR(kbuf),len,0);
128         if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,len))
129                 ret = -1;
130         user_memdup_free(p,kbuf);
131         return ret;
132 }
133
134 intreg_t sys_pwrite(struct proc* p, int fd, const void* buf, int len, int offset)
135 {
136         void* kbuf = user_memdup_errno(p,buf,len);
137         if(kbuf == NULL)
138                 return -1;
139         int ret = fe(pwrite,fd,PADDR(kbuf),len,offset);
140         user_memdup_free(p,kbuf);
141         return ret;
142 }
143
144 error_t read_page(struct proc* p, int fd, physaddr_t pa, int pgoff)
145 {
146         int errno;
147         int ret = frontend_syscall(p->pid,RAMP_SYSCALL_pread,fd,
148                                 pa,PGSIZE,pgoff*PGSIZE,&errno);
149
150         if(ret >= 0)
151                 memset(KADDR(pa)+ret,0,PGSIZE-ret);
152         return ret;
153 }
154
155 intreg_t sys_pread(struct proc* p, int fd, void* buf, int len, int offset)
156 {
157         void* kbuf = kmalloc_errno(len);
158         if(kbuf == NULL)
159                 return -1;
160         int ret = fe(pread,fd,PADDR(kbuf),len,offset);
161         if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,len))
162                 ret = -1;
163         user_memdup_free(p,kbuf);
164         return ret;
165 }
166
167 error_t open_file(struct proc* p, const char* path, int oflag, int mode)
168 {
169         int errno;
170         return frontend_syscall(p->pid,RAMP_SYSCALL_open,PADDR(path),
171                                 oflag,mode,0,&errno);
172 }
173
174 error_t close_file(struct proc* p, int fd)
175 {
176         int errno;
177         return frontend_syscall(p->pid,RAMP_SYSCALL_close,fd,0,0,0,&errno);
178 }
179
180 intreg_t sys_open(struct proc* p, const char* path, int oflag, int mode)
181 {
182         char* fn = user_strdup_errno(p,path,PGSIZE);
183         if(fn == NULL)
184                 return -1;
185         int ret = fe(open,PADDR(fn),oflag,mode,0);
186         user_memdup_free(p,fn);
187         return ret;
188 }
189 intreg_t sys_close(struct proc* p, int fd)
190 {
191         return fe(close,fd,0,0,0);
192 }
193
194 #define NEWLIB_STAT_SIZE 64
195 intreg_t sys_fstat(struct proc* p, int fd, void* buf)
196 {
197         int kbuf[NEWLIB_STAT_SIZE/sizeof(int)];
198         int ret = fe(fstat,fd,PADDR(kbuf),0,0);
199         if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,NEWLIB_STAT_SIZE))
200                 ret = -1;
201         return ret;
202 }
203
204 intreg_t sys_stat(struct proc* p, const char* path, void* buf)
205 {
206         int kbuf[NEWLIB_STAT_SIZE/sizeof(int)];
207         char* fn = user_strdup_errno(p,path,PGSIZE);
208         if(fn == NULL)
209                 return -1;
210
211         int ret = fe(stat,PADDR(fn),PADDR(kbuf),0,0);
212         if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,NEWLIB_STAT_SIZE))
213                 ret = -1;
214
215         user_memdup_free(p,fn);
216         return ret;
217 }
218
219 intreg_t sys_lstat(struct proc* p, const char* path, void* buf)
220 {
221         int kbuf[NEWLIB_STAT_SIZE/sizeof(int)];
222         char* fn = user_strdup_errno(p,path,PGSIZE);
223         if(fn == NULL)
224                 return -1;
225
226         int ret = fe(lstat,PADDR(fn),PADDR(kbuf),0,0);
227         if(ret != -1 && memcpy_to_user_errno(p,buf,kbuf,NEWLIB_STAT_SIZE))
228                 ret = -1;
229
230         user_memdup_free(p,fn);
231         return ret;
232 }
233
234 intreg_t sys_fcntl(struct proc* p, int fd, int cmd, int arg)
235 {
236         return fe(fcntl,fd,cmd,arg,0);
237 }
238
239 intreg_t sys_access(struct proc* p, const char* path, int type)
240 {
241         char* fn = user_strdup_errno(p,path,PGSIZE);
242         if(fn == NULL)
243                 return -1;
244         int ret = fe(access,PADDR(fn),type,0,0);
245         user_memdup_free(p,fn);
246         return ret;
247 }
248
249 intreg_t sys_umask(struct proc* p, int mask)
250 {
251         return fe(umask,mask,0,0,0);
252 }
253
254 intreg_t sys_chmod(struct proc* p, const char* path, int mode)
255 {
256         char* fn = user_strdup_errno(p,path,PGSIZE);
257         if(fn == NULL)
258                 return -1;
259         int ret = fe(chmod,PADDR(fn),mode,0,0);
260         user_memdup_free(p,fn);
261         return ret;
262 }
263
264 intreg_t sys_lseek(struct proc* p, int fd, int offset, int whence)
265 {
266         return fe(lseek,fd,offset,whence,0);
267 }
268
269 intreg_t sys_link(struct proc* p, const char* _old, const char* _new)
270 {
271         char* oldpath = user_strdup_errno(p,_old,PGSIZE);
272         if(oldpath == NULL)
273                 return -1;
274
275         char* newpath = user_strdup_errno(p,_new,PGSIZE);
276         if(newpath == NULL)
277         {
278                 user_memdup_free(p,oldpath);
279                 return -1;
280         }
281
282         int ret = fe(link,PADDR(oldpath),PADDR(newpath),0,0);
283         user_memdup_free(p,oldpath);
284         user_memdup_free(p,newpath);
285         return ret;
286 }
287
288 intreg_t sys_unlink(struct proc* p, const char* path)
289 {
290         char* fn = user_strdup_errno(p,path,PGSIZE);
291         if(fn == NULL)
292                 return -1;
293         int ret = fe(unlink,PADDR(fn),0,0,0);
294         user_memdup_free(p,fn);
295         return ret;
296 }
297
298 intreg_t sys_chdir(struct proc* p, const char* path)
299 {
300         char* fn = user_strdup_errno(p,path,PGSIZE);
301         if(fn == NULL)
302                 return -1;
303         int ret = fe(chdir,PADDR(fn),0,0,0);
304         user_memdup_free(p,fn);
305         return ret;
306 }
307
308 intreg_t sys_getcwd(struct proc* p, char* pwd, int size)
309 {
310         void* kbuf = kmalloc_errno(size);
311         if(kbuf == NULL)
312                 return -1;
313         int ret = fe(read,PADDR(kbuf),size,0,0);
314         if(ret != -1 && memcpy_to_user_errno(p,pwd,kbuf,strnlen(kbuf,size)))
315                 ret = -1;
316         user_memdup_free(p,kbuf);
317         return ret;
318 }
319
320 intreg_t sys_gettimeofday(struct proc* p, int* buf)
321 {
322         static spinlock_t gtod_lock = SPINLOCK_INITIALIZER;
323         static int t0 = 0;
324
325         spin_lock(&gtod_lock);
326         if(t0 == 0)
327                 t0 = fe(time,0,0,0,0);
328         spin_unlock(&gtod_lock);
329
330         long long dt = read_tsc();
331         int kbuf[2] = {t0+dt/system_timing.tsc_freq,
332             (dt%system_timing.tsc_freq)*1000000/system_timing.tsc_freq};
333
334         return memcpy_to_user_errno(p,buf,kbuf,sizeof(kbuf));
335 }
336
337 #define SIZEOF_STRUCT_TERMIOS 60
338 intreg_t sys_tcgetattr(struct proc* p, int fd, void* termios_p)
339 {
340         int kbuf[SIZEOF_STRUCT_TERMIOS/sizeof(int)];
341         int ret = fe(tcgetattr,fd,PADDR(kbuf),0,0);
342         if(ret != -1 && memcpy_to_user_errno(p,termios_p,kbuf,SIZEOF_STRUCT_TERMIOS))
343                 ret = -1;
344         return ret;
345 }
346
347 intreg_t sys_tcsetattr(struct proc* p, int fd, int optional_actions, const void* termios_p)
348 {
349         void* kbuf = user_memdup_errno(p,termios_p,SIZEOF_STRUCT_TERMIOS);
350         if(kbuf == NULL)
351                 return -1;
352         int ret = fe(tcsetattr,fd,optional_actions,PADDR(kbuf),0);
353         user_memdup_free(p,kbuf);
354         return ret;
355 }
356