Fixed a typo in syscall.c introduced in last commit.
[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
468                 if (just_read == -1) return -1;
469                 total_read += just_read;
470         }
471
472         return total_read;
473 }
474
475 /* sbrk()
476  * Increase program data space. 
477  * As malloc and related functions depend on this, it is 
478  * useful to have a working implementation. 
479  * The following suffices for a standalone system; it exploits the 
480  * symbol _end automatically defined by the GNU linker.
481  */
482 void* sbrk(ptrdiff_t incr) 
483 {
484         debug_in_out("SBRK\n");
485         debug_in_out("\tincr: %u\n", incr);     
486
487         #define HEAP_SIZE 8192
488         static uint8_t array[HEAP_SIZE];
489         static uint8_t* heap_end = array;
490         static uint8_t* stack_ptr = &(array[HEAP_SIZE-1]);
491
492         uint8_t* prev_heap_end; 
493
494         prev_heap_end = heap_end;
495         if (heap_end + incr > stack_ptr) {
496                 errno = ENOMEM;
497                 return (void*)-1;
498         }
499      
500         heap_end += incr;
501         debug_in_out("\treturning: %u\n", prev_heap_end);
502         return (caddr_t) prev_heap_end;
503 }
504
505 /* send_message()
506  * Write the message in buffer out on the channel, and wait for a response.
507  * Caller is responsible for management of buffer passed in and buffer returned.
508  */
509 char *send_message(char *message, int len)
510 {
511         syscall_id_t this_call_id = *((syscall_id_t*)message);
512
513         if (write_to_channel(message, len) != len)
514                 return NULL;
515
516         int response_value;
517
518         // Pull the response from the server out of the channel.
519         if (read_from_channel( (char*)&response_value, 
520                                sizeof(int), 
521                                NO_PEEK) == -1) 
522                 return NULL;
523
524         char* return_msg = NULL;
525         char* errno_pos = NULL;
526         int extra_space = (response_value == -1) ? sizeof(int) : 0;
527
528         // TODO: Make these sizes an array we index into, and only have this code once.
529         // TODO: Will have a flag that tells us we have a variable length response (right now only for read case)
530         // TODO: Default clause with error handling.
531         switch (this_call_id) {
532                 case ISATTY_ID:
533                         // This case must be at the top! Else extra space will be wrong at times 
534                         // ISATTY is special, 0 signifies error, not -1. Annoying.
535                         extra_space = (response_value == 0) ? sizeof(int) : 0;
536                 case OPEN_ID:           
537                 case CLOSE_ID:
538                 case WRITE_ID:  
539                 case LSEEK_ID:
540                 case UNLINK_ID:
541                 case LINK_ID:
542                         return_msg = (char*)malloc(sizeof(int) + extra_space);
543                         if (return_msg == NULL)
544                                 return NULL;
545
546                         errno_pos = return_msg + sizeof(int);
547                         if (extra_space && (-1 == read_from_channel(errno_pos,
548                                                                     sizeof(int), 
549                                                                     NO_PEEK))) {
550                                 free(return_msg);
551                                 return NULL;
552                         }
553
554                         break;
555
556                 case STAT_ID:
557                 case FSTAT_ID:
558                         return_msg = (char*)malloc(sizeof(int) 
559                                                     + sizeof(struct stat)
560                                                     + extra_space);
561                         if (return_msg == NULL)
562                                 return NULL;
563
564                         if (-1 == read_from_channel(return_msg + sizeof(int),
565                                                     sizeof(struct stat), 
566                                                     NO_PEEK)) {
567                                 free(return_msg);
568                                 return NULL;
569                         }
570
571                         errno_pos = return_msg + sizeof(int) 
572                                                + sizeof(struct stat);
573
574                         if (extra_space && (-1 == read_from_channel(errno_pos,
575                                                                     sizeof(int), 
576                                                                     NO_PEEK))) {
577                                 free(return_msg);
578                                 return NULL;
579                         }
580
581                         break;
582                 
583                 case READ_ID:
584                         if (response_value > 0)
585                                 extra_space = response_value;
586                         else
587                                 extra_space = extra_space;
588
589                         return_msg = (char*)malloc(sizeof(int) + extra_space);
590
591                         if (return_msg == NULL)
592                                 return NULL;
593
594                         if (-1 == read_from_channel(return_msg + sizeof(int),
595                                                     extra_space,
596                                                     NO_PEEK)) {
597                                 free(return_msg);
598                                 return NULL;
599                         }
600
601                         break;
602
603         }
604
605         // Copy response value in place
606         memcpy(return_msg, &response_value, sizeof(int));
607
608         return return_msg;
609 }
610
611
612 /* stat()
613  * Status of a file (by name). 
614  * Minimal implementation.
615  */
616 int stat(char *file, struct stat *st) 
617 {
618         debug_in_out("STAT\n");
619         
620         int s_len = strlen(file) + 1; // Null terminator
621         int out_msg_len = STAT_MESSAGE_FIXED_SIZE + s_len;
622
623         // Allocate a new buffer of proper size
624         char *out_msg = malloc(out_msg_len);
625         char *out_msg_pos = out_msg;
626
627         if (out_msg == NULL)
628                 return -1;
629
630         // Fill the buffer
631         *((syscall_id_t *)out_msg_pos) = STAT_ID;
632         out_msg_pos += sizeof(syscall_id_t);
633
634         *((int*)out_msg_pos) = s_len;
635         out_msg_pos += sizeof(int);
636
637         memcpy(out_msg_pos, file, s_len);
638
639         // Send message
640         char *result = send_message(out_msg, out_msg_len);
641
642         free(out_msg);
643
644         // Read result
645         int return_val;
646
647         if (result != NULL) {
648                 return_val = *((int *)result);
649
650                 if (return_val == -1)
651                         errno = *(((char *)result) + sizeof(int) 
652                                                    + sizeof(struct stat));
653                 else
654                         memcpy(st, ((int *)result) + 1, sizeof(struct stat));
655
656                 free(result);
657
658         } else {
659                 errno = ECHANNEL;
660                 return_val = -1;
661         }
662
663         return return_val;
664 }
665
666 /* times()
667  * Timing information for current process. 
668  * Minimal implementation.
669  */
670 int times(struct tms *buf) 
671 {
672         debug_in_out("TIMES");
673         return -1;
674 }
675
676 /* unlink()
677  * Remove a file's directory entry. 
678  * Minimal implementation.
679  */
680 int unlink(char *name) 
681 {
682         debug_in_out("UNLINK\n");
683         
684         int s_len = strlen(name) + 1; // Null terminator
685         int out_msg_len = UNLINK_MESSAGE_FIXED_SIZE + s_len;
686
687         // Allocate a new buffer of proper size
688         char *out_msg = malloc(out_msg_len);
689         char *out_msg_pos = out_msg;
690
691         if (out_msg == NULL)
692                 return -1;
693
694         // Fill the buffer
695         *((syscall_id_t *)out_msg_pos) = UNLINK_ID;
696         out_msg_pos += sizeof(syscall_id_t);
697
698         *((int*)out_msg_pos) = s_len;
699         out_msg_pos += sizeof(int);
700
701         memcpy(out_msg_pos, name, s_len);
702
703         // Send message
704         char *result = send_message(out_msg, out_msg_len);
705
706         free(out_msg);
707
708         // Read result
709         int return_val;
710
711         if (result != NULL) {
712                 return_val = *((int *)result);
713                 if (return_val == -1) errno = *(((int *)result) + 1);
714                 free(result);
715         } else {
716                 errno = ECHANNEL;
717                 return_val = -1;
718         }
719         return return_val;
720 }
721
722 /* wait()
723  * Wait for a child process. 
724  * Minimal implementation.
725  */
726 int wait(int *status) 
727 {
728         debug_in_out("WAIT\n");
729         errno = ECHILD;
730         return -1;
731 }
732
733 /* write()
734  * Write to a file. 
735  */
736 ssize_t write(int file, void *ptr, size_t len) {
737         
738         debug_in_out("WRITE\n");        
739         debug_in_out("\tFILE: %u\n", file);
740
741         debug_write_check("Writing len: %d\n", len);
742
743         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
744                                    || (file == STDOUT_FILENO))
745                 return sys_cputs(ptr, len);
746         
747         int out_msg_len = WRITE_MESSAGE_FIXED_SIZE + len;
748
749         // Allocate a new buffer of proper size
750         char *out_msg = malloc(out_msg_len);
751         char *out_msg_pos = out_msg;
752
753         // Fill the buffer
754         *((syscall_id_t *)out_msg_pos) = WRITE_ID;
755         out_msg_pos += sizeof(syscall_id_t);
756
757         *((int*)out_msg_pos) = file;
758         out_msg_pos += sizeof(int);
759
760         *((int*)out_msg_pos) = len;
761         out_msg_pos += sizeof(int);
762
763         memcpy(out_msg_pos, ptr, len);
764
765         // Send message
766         char *result = send_message(out_msg, out_msg_len);
767
768         free(out_msg);
769
770         // Read result
771         int return_val;
772
773         if (result != NULL) {
774                 return_val = *((int *)result);
775                 if (return_val == -1) errno = *(((int *)result) + 1);
776                 free(result);
777         } else {
778                 errno = ECHANNEL;
779                 return_val = -1;
780         }
781
782         return return_val;
783 }
784
785
786 /* write_to_channel()
787  * Send a message out over the channel, defined by msg, of length len
788  */
789 int write_to_channel(char * msg, int len)
790 {
791         //return sys_serial_write((char*)msg, len);
792         return sys_eth_write((char*)msg, len);
793         
794 }
795