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