Added more syscalls
[akaros.git] / user / parlib / src / sparc / newlib_backend.c
1 /* See COPYRIGHT for copyright information. */
2 /* Andrew Waterman <waterman@eecs.bekeley.edu> */
3
4 #include <sys/fcntl.h>
5 #include <stdio.h>
6 #include <arch/arch.h>
7 #include <arch/frontend.h>
8 #include <parlib.h>
9 #include <sys/stat.h>
10 #include <sys/unistd.h>
11 #include <sys/times.h>
12 #include <sys/wait.h>
13 #include <sys/time.h>
14 #include <debug.h>
15 #include <hart.h>
16 #include <utime.h>
17 #include <dirent.h>
18 #include <assert.h>
19 #include <stdlib.h>
20
21 // should kernel do V->P translation on these args?
22 #define IN0  1
23 #define IN1  2
24 #define IN2  4
25 #define OUT0 8
26 #define OUT1 16
27 #define OUT2 32
28
29 #define fe(n,x,y,z,trans) syscall(SYS_frontend,RAMP_SYSCALL_ ## n,(int)(x),(int)(y),(int)(z),trans)
30
31 #define getbuf(name,len) \
32         assert(len <= PGSIZE); \
33         char name##_blah[2*PGSIZE] __attribute__((aligned(8))); \
34         char* name = (char*)(((uint32_t)name##_blah+PGSIZE)/PGSIZE*PGSIZE)
35         
36 #define memcpy_if_off_page(ptr,len) \
37         assert(len <= PGSIZE); \
38         char buf##ptr[2*PGSIZE] __attribute__((aligned(8))); \
39         if((uint32_t)ptr % sizeof(uint32_t) != 0 || ((uint32_t)ptr)/PGSIZE != ((uint32_t)ptr+len)/PGSIZE) \
40         { \
41                 char* buf2##ptr = (char*)(((uint32_t)buf##ptr+PGSIZE)/PGSIZE*PGSIZE); \
42                 memcpy(buf2##ptr,ptr,len); \
43                 ptr = buf2##ptr; \
44         }
45
46 #define strcpy_if_off_page(ptr,len) \
47         assert(len <= PGSIZE); \
48         char buf##ptr[2*PGSIZE] __attribute__((aligned(8))); \
49         if((uint32_t)ptr % sizeof(uint32_t) != 0 || ((uint32_t)ptr)/PGSIZE != ((uint32_t)ptr+len)/PGSIZE) \
50         { \
51                 char* buf2##ptr = (char*)(((uint32_t)buf##ptr+PGSIZE)/PGSIZE*PGSIZE); \
52                 strcpy(buf2##ptr,ptr); \
53                 ptr = buf2##ptr; \
54         }
55
56 #define buf_if_off_page(ptr,len) \
57         assert(len <= PGSIZE); \
58         char buf##ptr [2*PGSIZE] __attribute__((aligned(8))); \
59         char* buf2##ptr = (char*)(((uint32_t)buf##ptr+PGSIZE)/PGSIZE*PGSIZE); \
60         void* old##ptr = ptr; \
61         if((uint32_t)ptr % sizeof(uint32_t) != 0 || ((uint32_t)ptr)/PGSIZE != ((uint32_t)ptr+len)/PGSIZE) \
62         { \
63                 ptr = (typeof(ptr))(buf2##ptr); \
64         }
65
66 #define copyout_if_off_page(ptr,len) \
67         if((uint32_t)(old##ptr) % sizeof(uint32_t) != 0 || ((uint32_t)(old##ptr))/PGSIZE != ((uint32_t)(old##ptr)+len)/PGSIZE) \
68         { \
69                 memcpy(old##ptr,buf2##ptr,len); \
70         }
71
72 /* Return the vcoreid, which is set in entry.S right before calling libmain.
73  * This should only be used in libmain() and main(), before any code that might
74  * use a register.  It just returns eax. */
75 uint32_t newcore(void)
76 {
77         return hart_self();
78 }
79
80 mode_t
81 umask (mode_t mask)
82 {
83         return fe(umask,mask,0,0,0);
84 }
85
86 int
87 chmod (const char *name, mode_t mode)
88 {
89         int len = strlen(name)+1;
90         if(len > RAMP_MAXPATH)
91                 return -1;
92
93         strcpy_if_off_page(name,RAMP_MAXPATH);
94         return fe(chmod,name,mode,0,IN0);
95 }
96
97 int
98 access (const char *name, int mode)
99 {
100         int len = strlen(name)+1;
101         if(len > RAMP_MAXPATH)
102                 return -1;
103
104         strcpy_if_off_page(name,RAMP_MAXPATH);
105         return fe(access,name,mode,0,IN0);
106 }
107
108 char *
109 getwd (char *pwd)
110 {
111         buf_if_off_page(pwd,RAMP_MAXPATH);
112         int32_t ret = fe(getcwd,pwd,RAMP_MAXPATH,0,OUT0);
113         copyout_if_off_page(pwd,RAMP_MAXPATH);
114         return (char*)ret;
115 }
116
117 long int
118 pathconf (const char *pathname, int name)
119 {
120         int len = strlen(pathname)+1;
121         if(len > RAMP_MAXPATH)
122                 return -1;
123
124         assert(0);
125 }
126
127 int
128 utime (const char *name, const struct utimbuf *buf)
129 {
130         assert(sizeof(time_t) == sizeof(int));
131         time_t actime = buf == NULL ? time(NULL) : buf->actime;
132         time_t modtime = buf == NULL ? actime : buf->modtime;
133
134         int len = strlen(name)+1;
135         if(len > RAMP_MAXPATH)
136                 return -1;
137         strcpy_if_off_page(name,RAMP_MAXPATH);
138
139         return fe(utime,name,actime,modtime,IN0);
140 }
141
142 uid_t
143 getuid()
144 {
145         return 0;
146 }
147
148 uid_t
149 geteuid()
150 {
151         return 0;
152 }
153
154 gid_t
155 getgid()
156 {
157         return 0;
158 }
159
160 gid_t
161 getegid()
162 {
163         return 0;
164 }
165
166 int
167 chown (const char *name, uid_t owner, gid_t group)
168 {
169         int len = strlen(name)+1;
170         if(len > RAMP_MAXPATH)
171                 return -1;
172
173         assert(0);
174 }
175
176 int
177 mkdir (const char *name, mode_t mode)
178 {
179         int len = strlen(name)+1;
180         if(len > RAMP_MAXPATH)
181                 return -1;
182
183         assert(0);
184 }
185
186
187 int
188 rmdir (const char *name)
189 {
190         int len = strlen(name)+1;
191         if(len > RAMP_MAXPATH)
192                 return -1;
193
194         assert(0);
195 }
196
197 long int 
198 sysconf (int name)
199 {
200         switch(name)
201         {
202                 case _SC_CLK_TCK:
203                         return procinfo.tsc_freq;
204                 case _SC_PAGESIZE:
205                         return PGSIZE;
206                 case _SC_PHYS_PAGES:
207                         return 512*1024; // 2GB mem
208                 default:
209                         printf("sysconf(%d) not supported!\n",name);
210                         abort();
211         }
212 }
213
214 typedef struct
215 {
216         int fd;
217         struct dirent ent;
218 } __dir;
219
220 DIR *opendir (const char *name)
221 {
222         __dir* dir = (__dir*)malloc(sizeof(__dir));
223         if(dir == NULL)
224                 return NULL;
225
226         int len = strlen(name)+1;
227         if(len > RAMP_MAXPATH)
228                 return NULL;
229
230         strcpy_if_off_page(name,RAMP_MAXPATH);
231         dir->fd = fe(opendir,name,0,0,IN0);
232         if(dir->fd < 0)
233         {
234                 free(dir);
235                 return NULL;
236         }
237
238         return (DIR*)((char*)dir+1); // make dereferencing fail loudly
239 }
240
241 struct dirent *readdir (DIR *d)
242 {
243         __dir* dir = (__dir*)((char*)d-1);
244         struct dirent* dep = &dir->ent;
245
246         buf_if_off_page(dep,sizeof(struct dirent));
247         int ret = fe(readdir,dir->fd,dep,0,OUT1);
248         copyout_if_off_page(dep,sizeof(struct dirent));
249
250         return ret == 0 ? dep : 0;
251 }
252
253 void rewinddir (DIR *d)
254 {
255         __dir* dir = (__dir*)((char*)d-1);
256         fe(rewinddir,dir->fd,0,0,0);
257 }
258
259 int closedir (DIR *d)
260 {
261         __dir* dir = (__dir*)((char*)d-1);
262         int ret = fe(closedir,dir->fd,0,0,0);
263         if(ret == 0)
264                 free(dir);
265         return ret;
266 }
267
268 int pipe (int __fildes[2])
269 {
270         assert(0);
271 }
272
273 int dup (int __fildes)
274 {
275         return fe(dup,__fildes,0,0,0);
276 }
277
278 int dup2 (int __fildes, int __fildes2)
279 {
280         return fe(dup2,__fildes,__fildes2,0,0);
281 }
282
283 unsigned sleep (unsigned int __seconds)
284 {
285         assert(0);
286 }
287
288 unsigned alarm(unsigned __secs)
289 {
290         assert(0);
291 }
292
293 int execvp(const char *file, char * const argv[])
294 {
295         if(file[0] == '/')
296                 return execv(file,argv);
297
298         // this is technically incorrect, because we need to search PATH
299         const char* path = getenv("PATH");
300         if(path == NULL)
301                 path = ":/bin:/usr/bin";
302         char* buf = (char*)malloc((strlen(path)+strlen(file)+2)*sizeof(char));
303
304         char* dir = path;
305         while(1)
306         {
307                 char* end = strchr(dir,':');
308                 int len = end ? end-dir : strlen(dir);
309                 memcpy(buf,dir,len);
310                 if(len && buf[len-1] != '/')
311                         buf[len++] = '/';
312                 strcpy(buf+len,file);
313         
314                 if(access(buf,X_OK) == 0)
315                 {
316                         int ret = execv(buf,argv);
317                         free(buf);
318                         return ret;
319                 }
320
321                 if(!end)
322                         break;
323
324                 dir = end+1;
325         }
326
327         free(buf);
328         errno = ENOENT;
329         return -1;
330 }
331
332 int execv(const char *path, char *const argv[])
333 {
334         return execve(path,argv,environ);
335 }
336
337 int fcntl (int fd, int cmd, ...)
338 {
339         va_list vl;
340         va_start(vl,cmd);
341         int arg = va_arg(vl,int);
342         va_end(vl);
343
344         switch(cmd)
345         {
346                 case F_DUPFD:
347                 case F_GETFD:
348                 case F_SETFD:
349                         return fe(fcntl,fd,cmd,arg,0);
350                 default:
351                         printf("fcntl(%d,%d) not supported!\n",fd,cmd);
352                         abort();
353         }
354 }
355
356 int chdir(const char *name)
357 {
358         size_t len = strlen(name)+1;
359         if(len > RAMP_MAXPATH)
360                 return -1;
361
362         strcpy_if_off_page(name,RAMP_MAXPATH);
363         return fe(chdir,name,0,0,IN0);
364 }
365
366 int
367 getppid(void)
368 {
369         assert(0);
370 //      return procinfo.ppid;
371 }
372
373 int
374 getpid(void)
375 {
376         return procinfo.pid;
377 }
378
379 void
380 _exit(int code)
381 {
382         sys_proc_destroy(getpid(),code);
383         while(1);
384 }
385
386 int
387 isatty(int fd)
388 {
389         struct stat s;
390         int ret = fstat(fd,&s);
391         return ret < 0 ? -1 : ((s.st_mode & S_IFCHR) ? 1 : 0);
392 }
393
394 static hart_lock_t child_lock = HART_LOCK_INIT;
395 static int* child_list = NULL;
396 static int child_list_capacity = 0;
397 static int child_list_size = 0;
398
399 int
400 fork(void)
401 {
402         hart_lock_lock(&child_lock);
403         if(child_list_size == child_list_capacity)
404         {
405                 child_list_capacity++;
406                 int* tmp = realloc(child_list,child_list_capacity*sizeof(int));
407                 if(tmp == NULL)
408                 {
409                         child_list_capacity--;
410                         errno = ENOMEM;
411                         hart_lock_unlock(&child_lock);
412                         return -1;
413                 }
414                 child_list = tmp;
415         }
416
417         int ret = syscall(SYS_fork,0,0,0,0,0);
418
419         if(ret > 0)
420                 child_list[child_list_size++] = ret;
421
422         hart_lock_unlock(&child_lock);
423         return ret;
424 }
425
426 static int
427 pack_argv(const char* const argv[], char* buf, size_t bufsz)
428 {
429         int argc = 0, size = sizeof(intreg_t);
430         while(argv[argc])
431         {
432                 size += sizeof(intreg_t)+strlen(argv[argc])+1;
433                 argc++;
434         }
435
436         if(size > bufsz)
437                 return -1;
438
439         intreg_t* offset = (intreg_t*)buf;
440         offset[0] = (argc+1)*sizeof(intreg_t);
441         for(int i = 0; i < argc; i++)
442         {
443                 int len = strlen(argv[i])+1;
444                 memcpy(buf+offset[i],argv[i],len);
445                 offset[i+1] = offset[i]+len;
446         }
447         offset[argc] = 0;
448
449         return 0;
450 }
451
452 static int
453 readfile(const char* filename, void** binary, int* size)
454 {
455         int fd = open(filename,O_RDONLY,0);
456         if(fd == -1)
457                 return -1;
458
459         *size = 0;
460         *binary = NULL;
461         int bytes_read = 0;
462         int bufsz = 0;
463
464         int READ_SIZE = 1024;
465         int MALLOC_SIZE = 1024*1024;
466
467         while(1)
468         {
469                 if(*size+READ_SIZE > bufsz)
470                 {
471                         void* temp_buf = realloc(*binary,bufsz+MALLOC_SIZE);
472                         if(temp_buf == NULL)
473                         {
474                                 close(fd);
475                                 free(*binary);
476                                 errno = ENOMEM;
477                                 return -1;
478                         }
479
480                         *binary = temp_buf;
481                         bufsz += MALLOC_SIZE;
482                 }
483
484                 bytes_read = read(fd, *binary+*size, READ_SIZE);
485                 *size += bytes_read;
486                 if(bytes_read <= 0)
487                 {
488                         close(fd);
489                         if(bytes_read < 0)
490                                 free(*binary);
491                         return bytes_read;
492                 }
493         }
494 }
495
496 int
497 execve(const char* name, char* const argv[], char* const env[])
498 {
499         char argv_buf[PROCINFO_MAX_ARGV_SIZE],env_buf[PROCINFO_MAX_ENV_SIZE];
500         if(pack_argv(argv,argv_buf,PROCINFO_MAX_ARGV_SIZE) ||
501            pack_argv(env,env_buf,PROCINFO_MAX_ENV_SIZE))
502         {
503                 errno = ENOMEM;
504                 return -1;
505         }
506
507         void* binary;
508         size_t binarysz;
509         if(readfile(name,&binary,&binarysz))
510                 return -1;
511
512         return syscall(SYS_exec,(intreg_t)binary,(intreg_t)binarysz,
513                        (intreg_t)argv_buf,(intreg_t)env_buf,0);
514 }
515
516 int
517 kill(int pid, int sig)
518 {
519         int ret = sys_proc_destroy(pid,0);
520         return ret < 0 ? -1 : ret;
521 }
522
523 int
524 waitpid(int pid, int* status, int options)
525 {
526         assert(options == 0);
527
528         int foo;
529         if(status == NULL)
530                 status = &foo;
531
532         hart_lock_lock(&child_lock);
533
534         if(child_list_size) while(1)
535         {
536                 for(int i = 0; i < child_list_size; i++)
537                 {
538                         if(pid == -1 || child_list[i] == pid)
539                         {
540                                 int ret = syscall(SYS_trywait,child_list[i],status,0,0,0);
541
542                                 if(ret == 0)
543                                 {
544                                         for(int j = i+1; j < child_list_size; j++)
545                                                 child_list[j-1] = child_list[j];
546                                         child_list_size--;
547                                         hart_lock_unlock(&child_lock);
548                                         return 0;
549                                 }
550                         }
551                 }
552                 sys_yield();
553         }
554
555         hart_lock_unlock(&child_lock);
556         errno = ECHILD;
557         return -1;
558 }
559
560 int
561 wait(int* status)
562 {
563         return waitpid(-1,status,0);
564 }
565
566 int
567 link(const char *old, const char *new)
568 {
569         int oldlen = strlen(old)+1, newlen = strlen(new)+1;
570         if(oldlen > RAMP_MAXPATH || newlen > RAMP_MAXPATH)
571                 return -1;
572
573         strcpy_if_off_page(old,RAMP_MAXPATH);
574         strcpy_if_off_page(new,RAMP_MAXPATH);
575         return fe(link,old,new,0,IN0 | IN1);
576 }
577
578 int
579 unlink(const char* name)
580 {
581         int len = strlen(name)+1;
582         if(len > RAMP_MAXPATH)
583                 return -1;
584
585         strcpy_if_off_page(name,RAMP_MAXPATH);
586         return fe(unlink,name,0,0,IN0);
587 }
588
589 int
590 fstat(int fd, struct stat* st)
591 {
592         buf_if_off_page(st,sizeof(*st));
593         int ret = fe(fstat,fd,st,0,OUT1);
594         copyout_if_off_page(st,sizeof(*st));
595         return ret;
596 }
597
598 int
599 lstat(const char* name, struct stat* st)
600 {
601         int len = strlen(name)+1;
602         if(len > RAMP_MAXPATH)
603                 return -1;
604
605         strcpy_if_off_page(name,RAMP_MAXPATH);
606         buf_if_off_page(st,sizeof(*st));
607         int ret = fe(lstat,name,st,0,IN0 | OUT1);
608         copyout_if_off_page(st,sizeof(*st));
609         return ret;
610 }
611
612 int
613 stat(const char* name, struct stat* st)
614 {
615         int len = strlen(name)+1;
616         if(len > RAMP_MAXPATH)
617                 return -1;
618
619         strcpy_if_off_page(name,RAMP_MAXPATH);
620         buf_if_off_page(st,sizeof(*st));
621         int ret = fe(stat,name,st,0,IN0 | OUT1);
622         copyout_if_off_page(st,sizeof(*st));
623         return ret;
624 }
625
626 off_t
627 lseek(int fd, off_t ptr, int dir)
628 {
629         return fe(lseek,fd,ptr,dir,0);
630 }
631
632 ssize_t
633 write(int fd, const void* ptr, size_t len)
634 {
635         len = MIN(PGSIZE,len);
636         memcpy_if_off_page(ptr,len);
637         return fe(write,fd,ptr,len,IN1);
638 }
639
640 ssize_t
641 read(int fd, void* ptr, size_t len)
642 {
643         len = MIN(PGSIZE,len);
644         buf_if_off_page(ptr,len);
645         int ret = fe(read,fd,ptr,len,OUT1);
646         copyout_if_off_page(ptr,len);
647         return ret;
648 }
649
650 int
651 open(const char* name, int flags, ...)
652 {
653         va_list vl;
654         va_start(vl,flags);
655         int mode = va_arg(vl,int);
656         va_end(vl);
657
658         size_t len = strlen(name)+1;
659         if(len > RAMP_MAXPATH)
660                 return -1;
661
662         strcpy_if_off_page(name,RAMP_MAXPATH);
663         return fe(open,name,flags,mode,IN0);
664 }
665
666 int
667 close(int fd)
668 {
669         return fe(close,fd,0,0,0);
670 }
671
672 clock_t
673 times(struct tms* buf)
674 {
675         extern struct timeval timeval_start;
676         if(timeval_start.tv_sec == 0)
677                 return (clock_t)-1;
678
679         struct timeval tp;
680         if(gettimeofday(&tp,NULL))
681                 return (clock_t)-1;
682
683         unsigned long long utime = (tp.tv_sec - timeval_start.tv_sec)*1000000;
684         utime += tp.tv_usec-timeval_start.tv_usec;
685         buf->tms_utime = buf->tms_cutime = utime*procinfo.tsc_freq/1000000;
686         buf->tms_stime = buf->tms_cstime = 0;
687
688         return (clock_t)buf->tms_utime;
689 }
690
691 int
692 gettimeofday(struct timeval* tp, void* tzp)
693 {
694         static struct timeval tp0 __attribute__((aligned(sizeof(*tp))));
695         if(tp0.tv_sec == 0)
696         {
697                 int ret = fe(gettimeofday,&tp0,0,0,OUT0);
698                 if(ret)
699                         return ret;
700         }
701
702         long long dt = read_tsc();
703         tp->tv_sec = tp0.tv_sec + dt/procinfo.tsc_freq;
704         tp->tv_usec = (dt % procinfo.tsc_freq)*1000000/procinfo.tsc_freq;
705
706         return 0;
707 }
708