Merge branch 'master' into proc-work
[akaros.git] / user / parlib / src / newlib_backend.c
1 /* See COPYRIGHT for copyright information. */
2 /* Kevin Klues <klueska@cs.berkeley.edu>        */
3
4 #ifdef __DEPUTY__
5 #pragma nodeputy
6 #endif
7
8 #include <parlib.h>
9 #include <unistd.h>
10 #include <newlib_backend.h>
11 #include <string.h>
12 #include <malloc.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <debug.h>
16
17 #define debug_in_out(...) // debug(__VA_ARGS__)  
18 #define debug_write_check(fmt, ...) // debug(fmt, __VA_ARGS__)
19
20 /* environ
21  * A pointer to a list of environment variables and their values. 
22  * For a minimal environment, this empty list is adequate.
23  */
24 char *__env[1] = { 0 };
25 char **environ = __env;
26
27 /* _exit()
28  * Exit a program without cleaning up files. 
29  * If your system doesn't provide this, it is best to avoid linking 
30  * with subroutines that require it (exit, system).
31  */
32 void _exit(int __status) _ATTRIBUTE ((noreturn))
33 {
34         sys_proc_destroy(sys_getpid()); // TODO: can run getpid and cache it
35         while(1); //Should never get here...
36 }
37     
38 /* close()
39  * Close a file. 
40  */
41 int close(int file) {
42         debug_in_out("CLOSE\n");
43
44         // If trying to close stdin/out/err just return
45         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
46                                    || (file == STDOUT_FILENO))
47                 return 0;
48
49         // Allocate a new buffer of proper size
50         char *out_msg = malloc(CLOSE_MESSAGE_FIXED_SIZE);
51         if (out_msg == NULL)
52                 return -1;
53
54         char *out_msg_pos = out_msg;
55
56         // Fill the buffer
57         *((syscall_id_t *)out_msg_pos) = CLOSE_ID;
58         out_msg_pos += sizeof(syscall_id_t);
59
60         *((int*)out_msg_pos) = file;
61         out_msg_pos += sizeof(int);
62
63
64         // Send message
65         char *result = send_message(out_msg, CLOSE_MESSAGE_FIXED_SIZE);
66
67         free(out_msg);
68
69         int return_val;
70
71         if (result != NULL) {
72                 // Read result
73                 return_val = *((int *) result);
74                 if (return_val == -1) errno = *(((int *)result) + 1);
75                 free(result);
76         } else {
77                 errno = ECHANNEL;
78                 return_val = -1;
79         }
80         
81         return return_val;
82 }
83
84 /* execve()
85  * Transfer control to a new process. 
86  * Minimal implementation (for a system without processes).
87  */
88
89 int execve(char *name, char **argv, char **env) 
90 {
91         debug_in_out("EXECVE\n");
92         errno = ENOMEM;
93         return -1;
94 }
95
96 /* fork()
97  * Create a new process. 
98  * Minimal implementation (for a system without processes).
99  */
100 int fork(void) 
101 {
102         debug_in_out("FORK\n");
103         errno = EAGAIN;
104     return -1;
105 }
106
107 /* fstat()
108  * Status of an open file. 
109  * For consistency with other minimal implementations in these stubs, 
110  * all files are regarded as character special devices. 
111  * The sys/stat.h header file required is distributed in the include 
112  * subdirectory for the newlib C library.
113  */
114 int fstat(int file, struct stat *st) 
115 {
116         debug_in_out("FSTAT\n");        
117
118         st->st_mode = S_IFCHR;
119         
120         // stdout hack
121         if (file == 1)
122                 st->st_mode = 8592;
123         return 0;
124
125
126         // Allocate a new buffer of proper size
127         char *out_msg = malloc(FSTAT_MESSAGE_FIXED_SIZE);
128         if(out_msg == NULL)
129                 return -1;
130         char *out_msg_pos = out_msg;
131
132         // Fill the buffer
133         *((syscall_id_t *)out_msg_pos) = FSTAT_ID;
134         out_msg_pos += sizeof(syscall_id_t);
135
136         *((int*)out_msg_pos) = file;
137         out_msg_pos += sizeof(int);
138
139         // Send message
140         char *result = send_message(out_msg, FSTAT_MESSAGE_FIXED_SIZE);
141
142         free(out_msg);
143
144         // Read result
145         int return_val;
146
147         if (result != NULL) {
148                 return_val = *((int *)result);
149                 if (return_val == -1)
150                         errno = *(((char *)result) + 
151                                        sizeof(int) + sizeof(struct stat));
152                 else
153                         memcpy(st, ((int *)result) + 1, sizeof(struct stat));
154                 free(result);
155         } else {
156                 errno = ECHANNEL;
157                 return_val = -1;
158         }
159
160         return return_val;
161 }
162
163 /* getpid()
164  * Process-ID; this is sometimes used to generate strings unlikely to 
165  * conflict with other processes. Minimal implementation, for a system 
166  * without processes.
167  */
168 int getpid(void) 
169 {
170         return sys_getpid(); // TODO: can run getpid and cache it
171 }
172
173 /* isatty()
174  * Query whether output stream is a terminal. 
175  * For consistency with the other minimal implementations, 
176  * which only support output to stdout, this minimal 
177  * implementation is suggested.
178  */
179 int isatty(int file) 
180 {
181         debug_in_out("ISATTY\n");
182
183         // Cheap hack to avoid sending serial comm for stuff we know
184         if ((STDIN_FILENO == file) || (STDOUT_FILENO == file) 
185                                || (STDERR_FILENO == file))
186                 return 1;
187
188         
189         // Allocate a new buffer of proper size
190         char *out_msg = malloc(ISATTY_MESSAGE_FIXED_SIZE);
191         if(out_msg == NULL)
192                 return -1;
193         char *out_msg_pos = out_msg;
194
195         // Fill the buffer
196         *((syscall_id_t *)out_msg_pos) = ISATTY_ID;
197         out_msg_pos += sizeof(syscall_id_t);
198
199         *((int*)out_msg_pos) = file;
200         out_msg_pos += sizeof(int);
201
202         // Send message
203         char *result = send_message(out_msg, ISATTY_MESSAGE_FIXED_SIZE);
204
205         free(out_msg);
206
207         int return_val;
208
209         if (result != NULL) {
210                 // Read result
211                 return_val = *((int *) result);
212                 if (return_val == 0) errno = *(((int *)result) + 1);
213                 free(result);
214         } else {
215                 errno = ECHANNEL;
216                 return_val = 0;
217         }
218         
219         return return_val;
220 }
221
222 /* kill()
223  * Send a signal. 
224  * Minimal implementation.
225  */
226 int kill(int pid, int sig) 
227 {
228         debug_in_out("KILL\n");
229         errno = EINVAL;
230     return -1;
231 }
232
233 /* link()
234  * Establish a new name for an existing file. 
235  * Minimal implementation.
236  */
237 int link(char *old, char *new) 
238 {
239         debug_in_out("LINK\n");
240         
241         int s_len_old = strlen(old) + 1; // Null terminator
242         int s_len_new = strlen(new) + 1; // Null terminator
243
244         int out_msg_len = LINK_MESSAGE_FIXED_SIZE + s_len_old + s_len_new;
245
246         // Allocate a new buffer of proper size
247         char *out_msg = malloc(out_msg_len);
248         char *out_msg_pos = out_msg;
249
250         if (out_msg == NULL)
251                 return -1;
252
253         // Fill the buffer
254         *((syscall_id_t *)out_msg_pos) = LINK_ID;
255         out_msg_pos += sizeof(syscall_id_t);
256
257         *((int*)out_msg_pos) = s_len_old;
258         out_msg_pos += sizeof(int);
259
260         *((int*)out_msg_pos) = s_len_new;
261         out_msg_pos += sizeof(int);
262
263         memcpy(out_msg_pos, old, s_len_old);
264         out_msg_pos += s_len_old;
265
266         memcpy(out_msg_pos, new, s_len_new);
267
268         // Send message
269         char *result = send_message(out_msg, out_msg_len);
270
271         free(out_msg);
272
273         // Read result
274         int return_val;
275
276         if (result != NULL) {
277                 return_val = *((int *)result);
278                 if (return_val == -1) errno = *(((int *)result) + 1);
279                 free(result);
280         } else {
281                 errno = ECHANNEL;
282                 return_val = -1;
283         }
284
285         return return_val;
286 }
287
288 /* lseek()
289  * Set position in a file. 
290  * Minimal implementation.
291  */
292 off_t lseek(int file, off_t ptr, int dir) 
293 {
294         debug_in_out("LSEEK\n");        
295         
296         // Allocate a new buffer of proper size
297         char *out_msg = malloc(LSEEK_MESSAGE_FIXED_SIZE);
298         if(out_msg == NULL)
299                 return -1;
300         char *out_msg_pos = out_msg;
301
302         // Fill the buffer
303         *((syscall_id_t *)out_msg_pos) = LSEEK_ID;
304         out_msg_pos += sizeof(syscall_id_t);
305
306         *((int*)out_msg_pos) = file;
307         out_msg_pos += sizeof(int);
308
309         *((int*)out_msg_pos) = ptr;
310         out_msg_pos += sizeof(int);
311
312         *((int*)out_msg_pos) = dir;
313         out_msg_pos += sizeof(int);
314
315         // Send message
316         char *result = send_message(out_msg, LSEEK_MESSAGE_FIXED_SIZE);
317
318         free(out_msg);
319
320         int return_val;
321
322         if (result != NULL) {
323                 // Read result
324                 return_val = *((int *) result);
325                 if (return_val == -1) errno = *(((int *)result) + 1);
326                 free(result);
327         } else {
328                 errno = ECHANNEL;
329                 return_val = -1;
330         }
331
332         return return_val;
333 }
334
335 /* open()
336  * Open a file. 
337  */
338 int open(const char *name, int flags, int mode) 
339 {
340         debug_in_out("OPEN\n");
341
342         int s_len = strlen(name) + 1; // Null terminator
343         int out_msg_len = OPEN_MESSAGE_FIXED_SIZE + s_len;
344
345         // Allocate a new buffer of proper size
346         char *out_msg = malloc(out_msg_len);
347         char *out_msg_pos = out_msg;
348
349         if (out_msg == NULL)
350                 return -1;
351
352         // Fill the buffer
353         *((syscall_id_t *)out_msg_pos) = OPEN_ID;
354         out_msg_pos += sizeof(syscall_id_t);
355
356         *((int*)out_msg_pos) = flags;
357         out_msg_pos += sizeof(int);
358
359         *((int*)out_msg_pos) = mode;
360         out_msg_pos += sizeof(int);
361
362         *((int*)out_msg_pos) = s_len;
363         out_msg_pos += sizeof(int);
364
365         memcpy(out_msg_pos, name, s_len);
366
367         // Send message
368         char *result = send_message(out_msg, out_msg_len);
369
370         free(out_msg);
371
372         // Read result
373         int return_val;
374
375         if (result != NULL) {
376                 return_val = *((int *)result);
377                 if (return_val == -1) errno = *(((int *)result) + 1);
378                 free(result);
379         } else {
380                 errno = ECHANNEL;
381                 return_val = -1;
382         }
383
384         return return_val;
385 }
386
387 /* read()
388  * Read from a file. 
389  */
390 ssize_t read(int file, void *ptr, size_t len) 
391 {
392         debug_in_out("READ\n");
393
394         if (file == STDIN_FILENO) {
395                 for(int i=0; i<len; i++)        
396                         ((uint8_t*)ptr)[i] = sys_cgetc();
397                 return len;
398         }
399
400         // Allocate a new buffer of proper size
401         char *out_msg = (char*)malloc(READ_MESSAGE_FIXED_SIZE);
402         if (out_msg == NULL)
403                 return -1;
404
405         char *out_msg_pos = out_msg;
406
407         // Fill the buffer
408         *((syscall_id_t *)out_msg_pos) = READ_ID;
409         out_msg_pos += sizeof(syscall_id_t);
410
411         *((int *)out_msg_pos) = file;
412         out_msg_pos += sizeof(int);
413
414         *((int *)out_msg_pos) = len;
415         out_msg_pos += sizeof(int);
416
417         // Send message
418         char *result = send_message(out_msg, READ_MESSAGE_FIXED_SIZE);
419
420         free(out_msg);
421
422         // Read result
423         int return_val;
424
425         if (result != NULL) {
426                 return_val = *((int *)result);
427                 if (return_val > 0)
428                         memcpy(ptr, ((int *)result) + 1, return_val);
429                 else 
430                         errno = *(((int *)result) + 1);
431
432                 free(result);
433         } else {
434                 errno = ECHANNEL;
435                 return_val = -1;
436         }
437
438         return return_val;
439 }
440
441 /* Read len bytes from the given channel to the buffer.
442  * If peek is NO_PEEK, will wait indefinitely until that much data is read.
443  * If peek is PEEK, if no data is available, will return immediately.
444  *              However once some data is available, 
445  *                      will block until the entire amount is available.
446  */
447 int read_from_channel(char * buf, int len, int peek)
448 {
449         // TODO: NEED TO IMPLIMENT A TIMEOUT
450         //                      Also, watch out for CONNECTION TERMINATED
451         int total_read = 0;
452
453         int just_read = sys_serial_read(buf, len);
454
455
456         if (just_read < 0) return just_read;
457         if (just_read == 0 && peek) return just_read;
458
459         total_read += just_read;
460
461         while (total_read != len) {
462                 just_read = sys_serial_read(buf + total_read, len - total_read);
463
464                 if (just_read == -1) return -1;
465                 total_read += just_read;
466         }
467
468         return total_read;
469 }
470
471 /* sbrk()
472  * Increase program data space. 
473  * As malloc and related functions depend on this, it is 
474  * useful to have a working implementation. 
475  * The following suffices for a standalone system; it exploits the 
476  * symbol _end automatically defined by the GNU linker.
477  */
478 void* sbrk(ptrdiff_t incr) 
479 {
480         debug_in_out("SBRK\n");
481         debug_in_out("\tincr: %u\n", incr);     
482
483         #define HEAP_SIZE 8192
484         static uint8_t array[HEAP_SIZE];
485         static uint8_t* heap_end = array;
486         static uint8_t* stack_ptr = &(array[HEAP_SIZE-1]);
487
488         uint8_t* prev_heap_end; 
489
490         prev_heap_end = heap_end;
491         if (heap_end + incr > stack_ptr) {
492                 errno = ENOMEM;
493                 return (void*)-1;
494         }
495      
496         heap_end += incr;
497         debug_in_out("\treturning: %u\n", prev_heap_end);
498         return (caddr_t) prev_heap_end;
499 }
500
501 /* send_message()
502  * Write the message in buffer out on the channel, and wait for a response.
503  * Caller is responsible for management of buffer passed in and buffer returned.
504  */
505 char *send_message(char *message, int len)
506 {
507         syscall_id_t this_call_id = *((syscall_id_t*)message);
508
509         if (write_to_channel(message, len) != len)
510                 return NULL;
511
512         int response_value;
513
514         // Pull the response from the server out of the channel.
515         if (read_from_channel( (char*)&response_value, 
516                                sizeof(int), 
517                                NO_PEEK) == -1) 
518                 return NULL;
519
520         char* return_msg = NULL;
521         char* errno_pos = NULL;
522         int extra_space = (response_value == -1) ? sizeof(int) : 0;
523
524         // TODO: Make these sizes an array we index into, and only have this code once.
525         // TODO: Will have a flag that tells us we have a variable length response (right now only for read case)
526         // TODO: Default clause with error handling.
527         switch (this_call_id) {
528                 case ISATTY_ID:
529                         // This case must be at the top! Else extra space will be wrong at times 
530                         // ISATTY is special, 0 signifies error, not -1. Annoying.
531                         extra_space = (response_value == 0) ? sizeof(int) : 0;
532                 case OPEN_ID:           
533                 case CLOSE_ID:
534                 case WRITE_ID:  
535                 case LSEEK_ID:
536                 case UNLINK_ID:
537                 case LINK_ID:
538                         return_msg = (char*)malloc(sizeof(int) + extra_space);
539                         if (return_msg == NULL)
540                                 return NULL;
541
542                         errno_pos = return_msg + sizeof(int);
543                         if (extra_space && (-1 == read_from_channel(errno_pos,
544                                                                     sizeof(int), 
545                                                                     NO_PEEK))) {
546                                 free(return_msg);
547                                 return NULL;
548                         }
549
550                         break;
551
552                 case STAT_ID:
553                 case FSTAT_ID:
554                         return_msg = (char*)malloc(sizeof(int) 
555                                                     + sizeof(struct stat)
556                                                     + extra_space);
557                         if (return_msg == NULL)
558                                 return NULL;
559
560                         if (-1 == read_from_channel(return_msg + sizeof(int),
561                                                     sizeof(struct stat), 
562                                                     NO_PEEK)) {
563                                 free(return_msg);
564                                 return NULL;
565                         }
566
567                         errno_pos = return_msg + sizeof(int) 
568                                                + sizeof(struct stat);
569
570                         if (extra_space && (-1 == read_from_channel(errno_pos,
571                                                                     sizeof(int), 
572                                                                     NO_PEEK))) {
573                                 free(return_msg);
574                                 return NULL;
575                         }
576
577                         break;
578                 
579                 case READ_ID:
580                         if (response_value > 0)
581                                 extra_space = response_value;
582                         else
583                                 extra_space = extra_space;
584
585                         return_msg = (char*)malloc(sizeof(int) + extra_space);
586
587                         if (return_msg == NULL)
588                                 return NULL;
589
590                         if (-1 == read_from_channel(return_msg + sizeof(int),
591                                                     extra_space,
592                                                     NO_PEEK)) {
593                                 free(return_msg);
594                                 return NULL;
595                         }
596
597                         break;
598
599         }
600
601         // Copy response value in place
602         memcpy(return_msg, &response_value, sizeof(int));
603
604         return return_msg;
605 }
606
607
608 /* stat()
609  * Status of a file (by name). 
610  * Minimal implementation.
611  */
612 int stat(char *file, struct stat *st) 
613 {
614         debug_in_out("STAT\n");
615         
616         int s_len = strlen(file) + 1; // Null terminator
617         int out_msg_len = STAT_MESSAGE_FIXED_SIZE + s_len;
618
619         // Allocate a new buffer of proper size
620         char *out_msg = malloc(out_msg_len);
621         char *out_msg_pos = out_msg;
622
623         if (out_msg == NULL)
624                 return -1;
625
626         // Fill the buffer
627         *((syscall_id_t *)out_msg_pos) = STAT_ID;
628         out_msg_pos += sizeof(syscall_id_t);
629
630         *((int*)out_msg_pos) = s_len;
631         out_msg_pos += sizeof(int);
632
633         memcpy(out_msg_pos, file, s_len);
634
635         // Send message
636         char *result = send_message(out_msg, out_msg_len);
637
638         free(out_msg);
639
640         // Read result
641         int return_val;
642
643         if (result != NULL) {
644                 return_val = *((int *)result);
645
646                 if (return_val == -1)
647                         errno = *(((char *)result) + sizeof(int) 
648                                                    + sizeof(struct stat));
649                 else
650                         memcpy(st, ((int *)result) + 1, sizeof(struct stat));
651
652                 free(result);
653
654         } else {
655                 errno = ECHANNEL;
656                 return_val = -1;
657         }
658
659         return return_val;
660 }
661
662 /* times()
663  * Timing information for current process. 
664  * Minimal implementation.
665  */
666 int times(struct tms *buf) 
667 {
668         debug_in_out("TIMES");
669         return -1;
670 }
671
672 /* unlink()
673  * Remove a file's directory entry. 
674  * Minimal implementation.
675  */
676 int unlink(char *name) 
677 {
678         debug_in_out("UNLINK\n");
679         
680         int s_len = strlen(name) + 1; // Null terminator
681         int out_msg_len = UNLINK_MESSAGE_FIXED_SIZE + s_len;
682
683         // Allocate a new buffer of proper size
684         char *out_msg = malloc(out_msg_len);
685         char *out_msg_pos = out_msg;
686
687         if (out_msg == NULL)
688                 return -1;
689
690         // Fill the buffer
691         *((syscall_id_t *)out_msg_pos) = UNLINK_ID;
692         out_msg_pos += sizeof(syscall_id_t);
693
694         *((int*)out_msg_pos) = s_len;
695         out_msg_pos += sizeof(int);
696
697         memcpy(out_msg_pos, name, s_len);
698
699         // Send message
700         char *result = send_message(out_msg, out_msg_len);
701
702         free(out_msg);
703
704         // Read result
705         int return_val;
706
707         if (result != NULL) {
708                 return_val = *((int *)result);
709                 if (return_val == -1) errno = *(((int *)result) + 1);
710                 free(result);
711         } else {
712                 errno = ECHANNEL;
713                 return_val = -1;
714         }
715         return return_val;
716 }
717
718 /* wait()
719  * Wait for a child process. 
720  * Minimal implementation.
721  */
722 int wait(int *status) 
723 {
724         debug_in_out("WAIT\n");
725         errno = ECHILD;
726         return -1;
727 }
728
729 /* write()
730  * Write to a file. 
731  */
732 ssize_t write(int file, void *ptr, size_t len) {
733         
734         debug_in_out("WRITE\n");        
735         debug_in_out("\tFILE: %u\n", file);
736
737         debug_write_check("Writing len: %d\n", len);
738
739         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
740                                    || (file == STDOUT_FILENO))
741                 return sys_cputs(ptr, len);
742         
743         int out_msg_len = WRITE_MESSAGE_FIXED_SIZE + len;
744
745         // Allocate a new buffer of proper size
746         char *out_msg = malloc(out_msg_len);
747         char *out_msg_pos = out_msg;
748
749         // Fill the buffer
750         *((syscall_id_t *)out_msg_pos) = WRITE_ID;
751         out_msg_pos += sizeof(syscall_id_t);
752
753         *((int*)out_msg_pos) = file;
754         out_msg_pos += sizeof(int);
755
756         *((int*)out_msg_pos) = len;
757         out_msg_pos += sizeof(int);
758
759         memcpy(out_msg_pos, ptr, len);
760
761         // Send message
762         char *result = send_message(out_msg, out_msg_len);
763
764         free(out_msg);
765
766         // Read result
767         int return_val;
768
769         if (result != NULL) {
770                 return_val = *((int *)result);
771                 if (return_val == -1) errno = *(((int *)result) + 1);
772                 free(result);
773         } else {
774                 errno = ECHANNEL;
775                 return_val = -1;
776         }
777
778         return return_val;
779 }
780
781
782 /* write_to_channel()
783  * Send a message out over the channel, defined by msg, of length len
784  */
785 int write_to_channel(char * msg, int len)
786 {
787         return sys_serial_write((char*)msg, len);
788 }
789