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