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