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