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