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