Merge branch 'net-dev'. See body of commit for details.
[akaros.git] / user / parlib / src / i386 / newlib_backend.c
1 /* See COPYRIGHT for copyright information. */
2
3 /** @file
4  * @brief Backend file for newlib functionality
5  *
6  * This file is responsible for defining the syscalls needed by newlib to 
7  * impliment the newlib library
8  * *
9  * @author Paul Pearce <pearce@eecs.berkeley.edu>
10  * @author Kevin Klues <klueska@cs.berkeley.edu>
11  *
12  */
13
14 #ifdef __DEPUTY__
15 #pragma nodeputy
16 #endif
17
18 #include <parlib.h>
19 #include <unistd.h>
20 #include <newlib_backend.h>
21 #include <string.h>
22 #include <malloc.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <debug.h>
26 #include <sys/times.h>
27
28 /* environ
29  * A pointer to a list of environment variables and their values. 
30  * For a minimal environment, this empty list is adequate.
31  */
32 char *__env[1] = { 0 };
33 char **environ = __env;
34
35 /* _exit()
36  * Exit a program without cleaning up files. 
37  * If your system doesn't provide this, it is best to avoid linking 
38  * with subroutines that require it (exit, system).
39  */
40 void _exit(int __status)
41 {
42         sys_proc_destroy(sys_getpid()); // TODO: can run getpid and cache it
43         while(1); //Should never get here...
44 }
45     
46 /* close()
47  * Close a file. 
48  */
49 int close(int file) {
50         debug_in_out("CLOSE\n");
51
52         // If trying to close stdin/out/err just return
53         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
54                                    || (file == STDOUT_FILENO))
55                 return 0;
56
57         // Allocate a new buffer of proper size
58         msg_t *msg = malloc(sizeof(msg_t));
59         if (msg == NULL)
60                 return -1;
61         
62         msg->id = CLOSE_ID;
63         msg->close.fd = file;
64         
65         // Send message
66         response_t *result = send_message(msg, sizeof(msg_t));
67
68         free(msg);
69
70         int return_val;
71
72         if (result == NULL) {
73                 errno = ECHANNEL;
74                 return_val = -1;
75         } else {
76                 // Read result
77                 return_val = result->ret;
78                 if (return_val == -1) errno = result->err;
79                 free(result);
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(const char *name, char * const argv[], char * const 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 pid_t 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 msg 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         // Kevin added this. I believe its needed for the serial branch
120         // Not used with the stdout hack. Review for removing stdout hack.
121         //st->st_mode = S_IFCHR;
122         
123         // stdout hack
124         if (file == 1) {
125                 st->st_mode = 8592;
126                 return 0;
127         }
128
129
130         // Allocate a new buffer of proper size 
131         msg_t *msg = malloc(sizeof(msg_t));
132         if (msg == NULL)
133                 return -1;
134         
135         msg->id = FSTAT_ID;
136         msg->fstat.fd = file;
137
138         // Send message
139         response_t *result = send_message(msg, sizeof(msg_t));
140
141         free(msg);
142
143         // Read result
144         int return_val;
145
146         if (result == NULL) {
147                 errno = ECHANNEL;
148                 return_val = -1;
149         } else {
150                 return_val = result->ret;
151                 if (return_val == -1)
152                         errno = result->err;
153                 else
154                         memcpy(st, (&result->st), sizeof(struct stat));
155                         
156                 free(result);
157         }
158
159         return return_val;
160 }
161
162 /* getpid()
163  * Process-ID; this is sometimes used to generate strings unlikely to 
164  * conflict with other processes. Minimal implementation, for a system 
165  * without processes.
166  */
167 pid_t getpid(void) 
168 {
169         return sys_getpid(); // TODO: can run getpid and cache it
170 }
171
172 /* isatty()
173  * Query whether output stream is a terminal. 
174  * For consistency with the other minimal implementations, 
175  * which only support output to stdout, this minimal 
176  * implementation is suggested.
177  */
178 int isatty(int file) 
179 {
180         debug_in_out("ISATTY\n");
181
182         // Cheap hack to avoid sending serial comm for stuff we know
183         if ((STDIN_FILENO == file) || (STDOUT_FILENO == file) 
184                                || (STDERR_FILENO == file))
185                 return 1;
186         
187         // Allocate a new buffer of proper size
188         msg_t *msg = malloc(sizeof(msg_t));
189         if (msg == NULL)
190                 return -1;
191         
192         msg->id = ISATTY_ID;
193         msg->isatty.fd = file;
194
195         // Send message
196         response_t *result = send_message(msg, sizeof(msg_t));
197
198         free(msg);
199
200         int return_val; 
201
202         // Note: Ret val of 0 defined to be an error, not < 0. Go figure.
203         if (result == NULL) {
204                 errno = ECHANNEL;
205                 return_val = 0;
206         } else {
207                 // Read result
208                 return_val = result->ret;
209                 if (return_val == 0) errno = result->err;
210                 free(result);
211         } 
212         
213         return return_val;
214 }
215
216 /* kill()
217  * Send a signal. 
218  * Minimal implementation.
219  */
220 int kill(int pid, int sig) 
221 {
222         debug_in_out("KILL\n");
223         errno = EINVAL;
224     return -1;
225 }
226
227 /* link()
228  * Establish a new name for an existing file. 
229  * Minimal implementation.
230  */
231 int link(const char *old, const char *new) 
232 {
233         debug_in_out("LINK\n");
234         
235         int s_len_old = strlen(old) + 1; // Null terminator
236         int s_len_new = strlen(new) + 1; // Null terminator
237
238         msg_t *msg = malloc(sizeof(msg_t) + s_len_old + s_len_new);
239         if (msg == NULL)
240                 return -1;
241         
242         msg->id = LINK_ID;
243         msg->link.old_len = s_len_old;
244         msg->link.new_len = s_len_new;
245         
246         memcpy(msg->link.buf, old, s_len_old);
247         memcpy(msg->link.buf + s_len_old, new, s_len_new);
248
249         // Send message
250         response_t *result = send_message(msg, sizeof(msg_t) + s_len_old + s_len_new);
251
252         free(msg);
253
254         // Read result
255         int return_val;
256
257         if (result == NULL) {
258                 errno = ECHANNEL;
259                 return_val = -1;
260         } else {
261                 return_val = result->ret;
262                 if (return_val == -1) errno = result->err;
263                 free(result);
264         }
265
266         return return_val;
267 }
268
269 /* lseek()
270  * Set position in a file. 
271  * Minimal implementation.
272  */
273 off_t lseek(int file, off_t ptr, int dir) 
274 {
275         debug_in_out("LSEEK\n");        
276         
277         // Allocate a new buffer of proper size and pack
278         msg_t *msg = malloc(sizeof(msg_t));
279         if (msg == NULL)
280                 return -1;
281         
282         msg->id = LSEEK_ID;
283         msg->lseek.fd = file;
284         msg->lseek.ptr = ptr;
285         msg->lseek.dir = dir;
286
287         // Send message
288         response_t *result = send_message(msg, sizeof(msg_t));
289
290         free(msg);
291
292         int return_val;
293
294         if (result == NULL) {
295                 errno = ECHANNEL;
296                 return_val = -1;
297         } else {
298                 // Read result
299                 return_val = result->ret;
300                 if (return_val == -1) errno = result->err;
301                 free(result);
302         }
303
304         return return_val;
305 }
306
307 /* open()
308  * Open a file. 
309  */
310 int open(const char *name, int flags, int mode) 
311 {
312         debug_in_out("OPEN\n");
313
314         int s_len = strlen(name) + 1; // Null terminator
315
316         msg_t *msg = malloc(sizeof(msg_t) + s_len);
317         if (msg == NULL)
318                 return -1;
319
320         msg->id = OPEN_ID;
321         msg->open.flags = flags;
322         msg->open.mode = mode;
323         msg->open.len = s_len;
324
325         memcpy(msg->open.buf, name, s_len);
326
327         // Send message
328         response_t *result = send_message(msg, sizeof(msg_t) + s_len);
329
330         free(msg);
331
332         // Read result
333         int return_val;
334
335         if (result == NULL) {
336                 errno = ECHANNEL;
337                 return_val = -1;
338         } else {
339                 return_val = result->ret;
340                 if (return_val == -1) errno = result->err;
341                 free(result);
342         } 
343
344         return return_val;
345 }
346
347 /* read()
348  * Read from a file. 
349  */
350 ssize_t read(int file, void *ptr, size_t len) 
351 {
352         debug_in_out("READ\n");
353
354         // Console hack.
355         if (file == STDIN_FILENO) {
356                 for(int i=0; i<len; i++)        
357                         ((uint8_t*)ptr)[i] = sys_cgetc();
358                 return len;
359         }
360
361         // Allocate a new buffer of proper size and pack
362         msg_t *msg = malloc(sizeof(msg_t));
363         if (msg == NULL)
364                 return -1;
365         
366         msg->id = READ_ID;
367         msg->read.fd = file;
368         msg->read.len = len;
369         
370         // Send message
371         response_t *result = send_message(msg, sizeof(msg_t));
372
373         free(msg);
374
375         // Read result
376         int return_val;
377
378         if (result == NULL) {
379                 errno = ECHANNEL;
380                 return_val = -1;
381         } else {
382                 return_val = result->ret;
383                 if (return_val < 0)
384                         errno = result->err;
385                 else
386                         memcpy(ptr, result->buf, return_val);
387
388                 free(result);
389         }
390
391         return return_val;
392 }
393
394 /* Read len bytes from the given channel to the buffer.
395  * If peek is NO_PEEK, will wait indefinitely until that much data is read.
396  * If peek is PEEK, if no data is available, will return immediately.
397  *              However once some data is available, 
398  *                      will block until the entire amount is available.
399  */
400 int read_from_channel(char * buf, int len, int peek)
401 {
402         // TODO: NEED TO IMPLIMENT A TIMEOUT
403         //                      Also, watch out for CONNECTION TERMINATED
404         int total_read = 0;
405
406         //int just_read = sys_serial_read(buf, len);
407         int just_read = sys_eth_read(buf, len);
408
409
410         if (just_read < 0) return just_read;
411         if (just_read == 0 && peek) return just_read;
412
413         total_read += just_read;
414
415         while (total_read != len) {
416                 //just_read = sys_serial_read(buf + total_read, len - total_read);
417                 just_read = sys_eth_read(buf + total_read, len - total_read);
418                 
419                 if (just_read == -1) return -1;
420                 total_read += just_read;
421         }
422
423         return total_read;
424 }
425
426 int read_response_from_channel(response_t *response) 
427 {
428         return read_from_channel(       (char*) response, 
429                                                 sizeof(response_t), 
430                                                                 NO_PEEK);
431 }
432
433 int read_buffer_from_channel(char *buf, int len) 
434 {
435         return read_from_channel(       buf, 
436                                                 len, 
437                                                                 NO_PEEK);
438 }
439
440 /* sbrk()
441  * Increase program data space. 
442  * As malloc and related functions depend on this, it is 
443  * useful to have a working implementation. 
444  * The following suffices for a standalone system; it exploits the 
445  * symbol _end automatically defined by the GNU linker.
446  */
447 void* sbrk(ptrdiff_t incr) 
448 {
449         debug_in_out("SBRK\n");
450         debug_in_out("\tincr: %u\n", incr);     
451
452         #define HEAP_SIZE (1<<18)
453         static uint8_t array[HEAP_SIZE];
454         static uint8_t* heap_end = array;
455         static uint8_t* stack_ptr = &(array[HEAP_SIZE-1]);
456
457         uint8_t* prev_heap_end; 
458
459         prev_heap_end = heap_end;
460         if (heap_end + incr > stack_ptr) {
461                 errno = ENOMEM;
462                 return (void*)-1;
463         }
464      
465         heap_end += incr;
466         debug_in_out("\treturning: %u\n", prev_heap_end);
467         return (caddr_t) prev_heap_end;
468 }
469
470 /* send_message()
471  * Write the message in buffer out on the channel, and wait for a response.
472  * Caller is responsible for management of buffer passed in and buffer returned.
473  */
474 response_t *send_message(msg_t *msg, int len)
475 {
476         syscall_id_t this_call_id = msg->id;
477
478         if (write_to_channel(msg, len) != len)
479                 return NULL;
480
481         int ret_value, buffer_size;
482         
483         response_t temp_response;
484         response_t *return_response = NULL;
485
486         // Pull the response from the server out of the channel.
487         if (read_response_from_channel( &temp_response ) == -1) 
488                 return NULL;
489
490         ret_value = temp_response.ret;
491         
492         char* buffer = NULL;
493
494         if (this_call_id == READ_ID) 
495         {
496                 if (ret_value < 0)
497                         buffer_size = 0;
498                 else
499                         buffer_size = ret_value;
500                         
501                 return_response = malloc(sizeof(response_t) + buffer_size);
502
503                 if (return_response == NULL)
504                         return NULL;
505                 
506                 if (read_buffer_from_channel(return_response->buf, buffer_size) == -1)
507                         return NULL;
508
509         } 
510         else 
511         {
512                         
513                 return_response = malloc(sizeof(response_t));
514                 
515                 if (return_response == NULL)
516                         return NULL;
517         }
518
519         *return_response = temp_response;
520
521         return return_response;
522 }
523
524
525 /* stat()
526  * Status of a file (by name). 
527  * Minimal implementation.
528  */
529 int stat(const char *file, struct stat *st) 
530 {
531         debug_in_out("STAT\n");
532         
533         int s_len = strlen(file) + 1; // Null terminator
534
535         // Allocate a new buffer of proper size and pack
536         msg_t *msg = malloc(sizeof(msg_t) + s_len);
537         if (msg == NULL)
538                 return -1;
539         
540         msg->id = STAT_ID;
541         msg->stat.len = s_len;
542
543         memcpy(msg->stat.buf, file, s_len);
544
545         // Send message
546         response_t *result = send_message(msg, sizeof(msg_t) + s_len);
547
548         free(msg);
549
550         // Read result
551         int return_val;
552
553         if (result == NULL) {
554                 errno = ECHANNEL;
555                 return_val = -1;
556         } else {
557                 return_val = result->ret;
558
559                 if (return_val == -1)
560                         errno = result->err;
561                 else
562                         memcpy(st, &(result->st), sizeof(struct stat));
563
564                 free(result);
565
566         }
567
568         return return_val;
569 }
570
571 /* times()
572  * Timing information for current process. 
573  * Minimal implementation.
574  */
575 clock_t times(struct tms *buf) 
576 {
577         debug_in_out("TIMES");
578         return -1;
579 }
580
581 /* unlink()
582  * Remove a file's directory entry. 
583  * Minimal implementation.
584  */
585 int unlink(const char *name) 
586 {
587         debug_in_out("UNLINK\n");
588         
589         int s_len = strlen(name) + 1; // Null terminator
590
591         // Allocate a new buffer of proper size and pack
592         msg_t *msg = malloc(sizeof(msg_t) + s_len);
593         if (msg == NULL)
594                 return -1;
595         
596         msg->id = UNLINK_ID;
597         msg->unlink.len = s_len;
598         
599         memcpy(msg->unlink.buf, name, s_len);
600
601         // Send message
602         response_t *result = send_message(msg, sizeof(msg_t) + s_len);
603
604         free(msg);
605
606         // Read result
607         int return_val;
608
609         if (result == NULL) {
610                 errno = ECHANNEL;
611                 return_val = -1;
612         } else {
613                 return_val = result->ret;
614                 if (return_val == -1) errno = result->err;
615                 free(result);
616         } 
617         
618         return return_val;
619 }
620
621 /* wait()
622  * Wait for a child process. 
623  * Minimal implementation.
624  */
625 int wait(int *status) 
626 {
627         debug_in_out("WAIT\n");
628         errno = ECHILD;
629         return -1;
630 }
631
632 /* write()
633  * Write to a file. 
634  */
635 ssize_t write(int file, const void *ptr, size_t len) {
636         
637         debug_in_out("WRITE\n");        
638         debug_in_out("\tFILE: %u\n", file);
639
640         debug_write_check("Writing len: %d\n", len);
641
642         if ((file == STDIN_FILENO) || (file == STDERR_FILENO) 
643                                    || (file == STDOUT_FILENO))
644                 return sys_cputs(ptr, len);
645         
646         // Allocate a new buffer of proper size and pack
647         msg_t *msg = malloc(sizeof(msg_t) + len);
648         if (msg == NULL)
649                 return -1;
650         
651         msg->id = WRITE_ID;
652         msg->write.fd = file;
653         msg->write.len = len;
654
655         memcpy(msg->write.buf, ptr, len);
656
657         // Send message
658         response_t *result = send_message(msg, sizeof(msg_t) + len);
659
660         free(msg);
661
662         // Read result
663         int return_val;
664
665         if (result == NULL) {
666                 errno = ECHANNEL;
667                 return_val = -1;
668         } else {
669                 return_val = result->ret;
670                 if (return_val == -1) errno = result->err;
671                 free(result);
672         } 
673
674         return return_val;
675 }
676
677
678 /* write_to_channel()
679  * Send a message out over the channel, defined by msg, of length len
680  */
681 int write_to_channel(msg_t * msg, int len)
682 {
683         //return sys_serial_write((char*)msg, len);
684         return sys_eth_write((char*)msg, len);
685         
686 }