Changed debug() format inside newlib_backend, added multiline print test
[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 <newlib_backend.h>
10 #include <string.h>
11 #include <malloc.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <debug.h>
15
16 #define debug_in_out(fmt, ...) // debug(fmt, __VA_ARGS__)  
17 #define debug_write_check(fmt, ...) debug(fmt, __VA_ARGS__)
18
19 /* environ
20  * A pointer to a list of environment variables and their values. 
21  * For a minimal environment, this empty list is adequate.
22  */
23 char *__env[1] = { 0 };
24 char **environ = __env;
25 extern env_t* env;
26
27 /* _exit()
28  * Exit a program without cleaning up files. 
29  * If your system doesn't provide this, it is best to avoid linking 
30  * with subroutines that require it (exit, system).
31  */
32 void _exit(int __status) _ATTRIBUTE ((noreturn))
33 {
34         sys_env_destroy(env->env_id);
35         while(1); //Should never get here...
36 }
37     
38 /* close()
39  * Close a file. 
40  */
41 int close(int file) 
42 {
43         debug_in_out("CLOSE\n");
44
45         // If trying to close stdin/out/err just return
46         if ((file > -1) && (file <3))
47                 return 0;
48
49         // Allocate a new buffer of proper size
50         byte *out_msg = malloc(CLOSE_MESSAGE_FIXED_SIZE);
51         if(out_msg == NULL)
52                 return -1;
53
54         byte *out_msg_pos = out_msg;
55
56         // Fill the buffer
57         *((syscall_id *)out_msg_pos) = CLOSE_ID;
58         out_msg_pos += sizeof(syscall_id);
59
60         *((int*)out_msg_pos) = file;
61         out_msg_pos += sizeof(int);
62
63
64         // Send message
65         byte *result = send_message(out_msg, CLOSE_MESSAGE_FIXED_SIZE);
66
67         free(out_msg);
68
69         if (result != NULL) {
70                 // Read result
71                 int return_val;
72                 return_val = *((int *) result);
73                 free(result);
74                 return return_val;
75         } else {
76                 return -1;
77         }
78 }
79
80 /* execve()
81  * Transfer control to a new process. 
82  * Minimal implementation (for a system without processes).
83  */
84
85 int execve(char *name, char **argv, char **env) 
86 {
87         debug_in_out("EXECVE\n");
88         errno = ENOMEM;
89         return -1;
90 }
91
92 /* fork()
93  * Create a new process. 
94  * Minimal implementation (for a system without processes).
95  */
96 int fork(void) 
97 {
98         debug_in_out("FORK\n");
99         errno = EAGAIN;
100     return -1;
101 }
102
103 /* fstat()
104  * Status of an open file. 
105  * For consistency with other minimal implementations in these stubs, 
106  * all files are regarded as character special devices. 
107  * The sys/stat.h header file required is distributed in the include 
108  * subdirectory for the newlib C library.
109  */
110 int fstat(int file, struct stat *st) 
111 {
112         debug_in_out("FSTAT\n");        
113         debug_in_out("\tfile: %u\n", file);
114         st->st_mode = S_IFCHR;
115         
116         // stdout hack
117         if (file == 1)
118                 st->st_mode = 8592;
119         return 0;
120 }
121
122 /* getpid()
123  * Process-ID; this is sometimes used to generate strings unlikely to 
124  * conflict with other processes. Minimal implementation, for a system 
125  * without processes.
126  */
127 int getpid(void) 
128 {
129         return env->env_id;
130 }
131
132 /* isatty()
133  * Query whether output stream is a terminal. 
134  * For consistency with the other minimal implementations, 
135  * which only support output to stdout, this minimal 
136  * implementation is suggested.
137  */
138 int isatty(int file) 
139 {
140         debug_in_out("ISATTY\n");
141         debug_in_out("\tfile: %u\n", file);
142         return 1;
143 }
144
145 /* kill()
146  * Send a signal. 
147  * Minimal implementation.
148  */
149 int kill(int pid, int sig) 
150 {
151         debug_in_out("KILL\n");
152         errno = EINVAL;
153     return -1;
154 }
155
156 /* link()
157  * Establish a new name for an existing file. 
158  * Minimal implementation.
159  */
160 int link(char *old, char *new) 
161 {
162         debug_in_out("LINK\n");
163         errno = EMLINK;
164         return -1;
165 }
166
167 /* lseek()
168  * Set position in a file. 
169  * Minimal implementation.
170  */
171 off_t lseek(int file, off_t ptr, int dir) 
172 {
173         debug_in_out("LSEEK\n");
174         return 0;
175 }
176
177 /* open()
178  * Open a file. 
179  */
180 int open(const char *name, int flags, int mode) 
181 {
182         debug_in_out("OPEN\n");
183
184         int s_len = strlen(name) + 1; // Null terminator
185         int out_msg_len = OPEN_MESSAGE_FIXED_SIZE + s_len;
186
187         // Allocate a new buffer of proper size
188         byte *out_msg = malloc(out_msg_len);
189         byte *out_msg_pos = out_msg;
190
191         if (out_msg == NULL)
192                 return -1;
193
194         // Fill the buffer
195         *((syscall_id*)out_msg_pos) = OPEN_ID;
196         out_msg_pos += sizeof(syscall_id);
197
198         *((int*)out_msg_pos) = flags;
199         out_msg_pos += sizeof(int);
200
201         *((int*)out_msg_pos) = mode;
202         out_msg_pos += sizeof(int);
203
204         *((int*)out_msg_pos) = s_len;
205         out_msg_pos += sizeof(int);
206
207         memcpy(out_msg_pos, name, s_len);
208
209         // Send message
210         byte *result = send_message(out_msg, out_msg_len);
211
212         free(out_msg);
213
214         // Read result
215         int return_val;
216
217         if (result != NULL) {
218                 return_val = *((int *)result);
219                 free(result);
220         } else {
221                 return_val = -1;
222         }
223
224         return return_val;
225 }
226
227 /* read()
228  * Read from a file. 
229  */
230 ssize_t read(int file, void *ptr, size_t len) 
231 {
232         debug_in_out("READ\n");
233
234
235         // Allocate a new buffer of proper size
236         byte *out_msg = (byte*)malloc(READ_MESSAGE_FIXED_SIZE);
237         if (out_msg == NULL)
238                 return -1;
239
240         byte *out_msg_pos = out_msg;
241
242         // Fill the buffer
243         *((syscall_id*)out_msg_pos) = READ_ID;
244         out_msg_pos += sizeof(syscall_id);
245
246         *((int *)out_msg_pos) = file;
247         out_msg_pos += sizeof(int);
248
249         *((int *)out_msg_pos) = len;
250         out_msg_pos += sizeof(int);
251
252         // Send message
253         byte *result = send_message(out_msg, READ_MESSAGE_FIXED_SIZE);
254
255         free(out_msg);
256
257         // Read result
258         int return_val;
259
260         if (result != NULL) {
261                 return_val = *((int *)result);
262                 if (return_val > 0)
263                         memcpy(ptr, ((int *)result) + 1, return_val);
264                 free(result);
265         } else {
266                 return_val = -1;
267         }
268
269         return return_val;
270 }
271
272 /* Read len bytes from the given channel to the buffer.
273  * If peek is 0, will wait indefinitely until that much data is read.
274  * If peek is 1, if no data is available, will return immediately.
275  *              However once some data is available, it will block until the entire amount is available.
276  */
277 int read_from_channel(byte * buf, int len, int peek)
278 {
279         // TODO: NEED TO IMPLIMENT A TIMEOUT
280         //                      Also, watch out for CONNECTION TERMINATED
281         // TODO: Add a #define for peek / no peek. Don't know why I didnt do this from the start?
282         int total_read = 0;
283
284         int just_read = sys_serial_read(buf, len);
285
286
287         if (just_read < 0) return just_read;
288         if (just_read == 0 && peek) return just_read;
289
290         total_read += just_read;
291
292         while (total_read != len) {
293                 just_read = sys_serial_read(buf + total_read, len - total_read);
294
295                 if (just_read == -1) return -1;
296                 total_read += just_read;
297         }
298
299         return total_read;
300 }
301
302 /* sbrk()
303  * Increase program data space. 
304  * As malloc and related functions depend on this, it is 
305  * useful to have a working implementation. 
306  * The following suffices for a standalone system; it exploits the 
307  * symbol _end automatically defined by the GNU linker.
308  */
309 caddr_t sbrk(int incr) 
310 {
311         debug_in_out("SBRK\n");
312         debug_in_out("\tincr: %u\n", incr);     
313
314         #define HEAP_SIZE 4096
315         static uint8_t array[HEAP_SIZE];
316         static uint8_t* heap_end = array;
317         static uint8_t* stack_ptr = &(array[HEAP_SIZE-1]);
318
319         uint8_t* prev_heap_end; 
320
321         prev_heap_end = heap_end;
322         if (heap_end + incr > stack_ptr) {
323                 errno = ENOMEM;
324                 return (void*)-1;
325         }
326      
327         heap_end += incr;
328         debug_in_out("\treturning: %u\n", prev_heap_end);
329         return (caddr_t) prev_heap_end;
330 }
331
332 /* send_message()
333  * Write the message defined in buffer out across the channel, and wait for a response.
334  * Caller is responsible for management of both the buffer passed in and the buffer ptr returned.
335  */
336 byte *send_message(byte *message, int len)
337 {
338
339         syscall_id this_call_id = *((syscall_id*)message);
340
341         if (write_to_channel(message, len) != len)
342                 return NULL;
343
344         int response_value;
345
346         // Pull the response from the server out of the channel.
347         if (read_from_channel((char*)&response_value, sizeof(int), 0) == -1) return NULL;
348
349         byte* return_msg = NULL;
350
351         // TODO: Make these sizes an array we index into, and only have this code once.
352         // TODO: Will have a flag that tells us we have a variable length response (right now only for read case)
353         // TODO: Default clause with error handling.
354         switch (this_call_id) {
355                 case OPEN_ID:
356                         if ((return_msg = (byte*)malloc(OPEN_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
357                                 return NULL;
358
359                         break;
360
361                 case CLOSE_ID:
362                         if ((return_msg = (byte*)malloc(CLOSE_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
363                                 return NULL;
364
365                         break;
366
367                 case READ_ID:
368                         if ((return_msg = (byte*)malloc(READ_RETURN_MESSAGE_FIXED_SIZE + ((response_value > 0) ? response_value : 0))) == NULL)
369                                 return NULL;
370
371
372                         if ((response_value != -1) &&  (read_from_channel(return_msg + sizeof(int), response_value, 0) == -1))
373                                 return NULL;
374
375                         break;
376
377                 case WRITE_ID:
378                         if ((return_msg = (byte*)malloc(WRITE_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
379                                 return NULL;
380
381                         break;
382
383
384                 case LSEEK_ID:
385                         if ((return_msg = (byte*)malloc(LSEEK_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
386                                 return NULL;
387
388                         break;
389
390                 case ISATTY_ID:
391                         if ((return_msg = (byte*)malloc(ISATTY_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
392                                 return NULL;
393
394                         break;
395
396                 case UNLINK_ID:
397                         if ((return_msg = (byte*)malloc(UNLINK_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
398                                 return NULL;
399
400
401                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int), sizeof(int), 0)) == -1))
402                                 return NULL;
403
404                         break;
405
406                 case LINK_ID:
407                         if ((return_msg = (byte*)malloc(LINK_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
408                                 return NULL;
409
410
411                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int), sizeof(int), 0)) == -1))
412                                 return NULL;
413
414                         break;
415
416                 case FSTAT_ID:
417                         if ((return_msg = (byte*)malloc(FSTAT_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
418                                 return NULL;
419
420                         if (read_from_channel(return_msg + sizeof(int), sizeof(struct stat), 0) == -1)
421                                 return NULL;
422
423                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int) + sizeof(struct stat), sizeof(int), 0)) == -1))
424                                 return NULL;
425
426                         break;
427
428                 case STAT_ID:
429                         if ((return_msg = (byte*)malloc(STAT_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
430                                 return NULL;
431
432                         if (read_from_channel(return_msg + sizeof(int), sizeof(struct stat), 0) == -1)
433                                 return NULL;
434
435                         if ((response_value == -1) && (read_from_channel(return_msg + sizeof(int) + sizeof(struct stat), sizeof(int), 0) == -1))
436                                 return NULL;
437
438                         break;
439         }
440
441         memcpy(return_msg, &response_value, sizeof(int));
442
443         return return_msg;
444 }
445
446
447 /* stat()
448  * Status of a file (by name). 
449  * Minimal implementation.
450  */
451 int stat(char *file, struct stat *st) 
452 {
453         debug_in_out("STAT\n");
454         st->st_mode = S_IFCHR;
455         return 0;
456 }
457
458 /* times()
459  * Timing information for current process. 
460  * Minimal implementation.
461  */
462 int times(struct tms *buf) 
463 {
464         debug_in_out("TIMES");
465         return -1;
466 }
467
468 /* unlink()
469  * Remove a file's directory entry. 
470  * Minimal implementation.
471  */
472 int unlink(char *name) 
473 {
474         debug_in_out("UNLINK\n");
475         errno = ENOENT;
476         return -1;
477 }
478
479 /* wait()
480  * Wait for a child process. 
481  * Minimal implementation.
482  */
483 int wait(int *status) 
484 {
485         debug_in_out("WAIT\n");
486         errno = ECHILD;
487         return -1;
488 }
489
490 /* write()
491  * Write to a file. 
492  */
493 ssize_t write(int file, void *ptr, size_t len) {
494         
495         debug_in_out("WRITE\n");        
496         debug_in_out("\tFILE: %u\n", file);
497
498         debug_write_check("Writing len: %d\n", len);
499
500         if ((file > -1) && (file < 3))  //STDOUT_FILENO || STDERR_FILENO || STDIN_FILENO
501                 return (sys_cputs(ptr, len) == E_SUCCESS) ? len : -1;
502         
503         int out_msg_len = WRITE_MESSAGE_FIXED_SIZE + len;
504
505         // Allocate a new buffer of proper size
506         byte *out_msg = malloc(out_msg_len);
507         byte *out_msg_pos = out_msg;
508
509         // Fill the buffer
510         *((syscall_id*)out_msg_pos) = WRITE_ID;
511         out_msg_pos += sizeof(syscall_id);
512
513         *((int*)out_msg_pos) = file;
514         out_msg_pos += sizeof(int);
515
516         *((int*)out_msg_pos) = len;
517         out_msg_pos += sizeof(int);
518
519         memcpy(out_msg_pos, ptr, len);
520
521         // Send message
522         byte *result = send_message(out_msg, out_msg_len);
523
524         free(out_msg);
525
526         // Read result
527         int return_val;
528
529         if (result != NULL) {
530                 return_val = *((int *)result);
531                 free(result);
532         } else {
533                 return_val = -1;
534         }
535
536         return return_val;
537 }
538
539
540 /* write_to_channel()
541  * Send a message out over the channel, defined by msg, of length len
542  */
543 int write_to_channel(byte * msg, int len)
544 {
545         return sys_serial_write((char*)msg, len);
546 }
547