Fixed those damn __sseek and __swrite problems!
[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 /* open()
155  * Open a file. 
156  */
157 int open(const char *name, int flags, int mode) 
158 {
159         int s_len = strlen(name) + 1; // Null terminator
160         int out_msg_len = OPEN_MESSAGE_FIXED_SIZE + s_len;
161
162         // Allocate a new buffer of proper size
163         byte *out_msg = malloc(out_msg_len);
164         byte *out_msg_pos = out_msg;
165
166         if (out_msg == NULL)
167                 return -1;
168
169         // Fill the buffer
170         *((syscall_id*)out_msg_pos) = OPEN_ID;
171         out_msg_pos += sizeof(syscall_id);
172
173         *((int*)out_msg_pos) = flags;
174         out_msg_pos += sizeof(int);
175
176         *((int*)out_msg_pos) = mode;
177         out_msg_pos += sizeof(int);
178
179         *((int*)out_msg_pos) = s_len;
180         out_msg_pos += sizeof(int);
181
182         memcpy(out_msg_pos, name, s_len);
183
184         // Send message
185         byte *result = send_message(out_msg, out_msg_len);
186
187         free(out_msg);
188
189         // Read result
190         int return_val;
191
192         if (result != NULL) {
193                 return_val = *((int *)result);
194                 free(result);
195         } else {
196                 return_val = -1;
197         }
198
199         return return_val;
200 }
201
202 /* read()
203  * Read from a file. 
204  */
205 int read(int file, char *ptr, int len) 
206 {
207         // Allocate a new buffer of proper size
208         byte *out_msg = (byte*)malloc(READ_MESSAGE_FIXED_SIZE);
209         if (out_msg == NULL)
210                 return -1;
211
212         byte *out_msg_pos = out_msg;
213
214         // Fill the buffer
215         *((syscall_id*)out_msg_pos) = READ_ID;
216         out_msg_pos += sizeof(syscall_id);
217
218         *((int *)out_msg_pos) = file;
219         out_msg_pos += sizeof(int);
220
221         *((int *)out_msg_pos) = len;
222         out_msg_pos += sizeof(int);
223
224         // Send message
225         byte *result = send_message(out_msg, READ_MESSAGE_FIXED_SIZE);
226
227         free(out_msg);
228
229         // Read result
230         int return_val;
231
232         if (result != NULL) {
233                 return_val = *((int *)result);
234                 memcpy(ptr, ((int *)result) + 1, return_val);
235                 free(result);
236         } else {
237                 return_val = -1;
238         }
239
240         return return_val;
241 }
242
243 /* Read len bytes from the given channel to the buffer.
244  * If peek is 0, will wait indefinitely until that much data is read.
245  * If peek is 1, if no data is available, will return immediately.
246  *              However once some data is available, it will block until the entire amount is available.
247  */
248 int read_from_channel(byte * buf, int len, int peek)
249 {
250         // TODO: NEED TO IMPLIMENT A TIMEOUT
251         //                      Also, watch out for CONNECTION TERMINATED
252         // TODO: Add a #define for peek / no peek. Don't know why I didnt do this from the start?
253         int total_read = 0;
254
255         int just_read = sys_serial_read(buf, len);
256
257
258         if (just_read < 0) return just_read;
259         if (just_read == 0 && peek) return just_read;
260
261         total_read += just_read;
262
263         while (total_read != len) {
264                 just_read = sys_serial_read(buf + total_read, len - total_read);
265
266                 if (just_read == -1) return -1;
267                 total_read += just_read;
268         }
269
270         return total_read;
271 }
272
273 /* sbrk()
274  * Increase program data space. 
275  * As malloc and related functions depend on this, it is 
276  * useful to have a working implementation. 
277  * The following suffices for a standalone system; it exploits the 
278  * symbol _end automatically defined by the GNU linker.
279  */
280 caddr_t sbrk(int incr) 
281 {
282         #define HEAP_SIZE 1000
283         static uint8_t array[HEAP_SIZE];
284         static uint8_t* heap_end = array;
285         static uint8_t* stack_ptr = &(array[HEAP_SIZE-1]);
286
287         uint8_t* prev_heap_end; 
288
289         prev_heap_end = heap_end;
290         if (heap_end + incr > stack_ptr) {
291                 errno = ENOMEM;
292                 return (void*)-1;
293         }
294       
295         heap_end += incr;
296         return (caddr_t) prev_heap_end;
297 }
298
299 /* send_message()
300  * Write the message defined in buffer out across the channel, and wait for a response.
301  * Caller is responsible for management of both the buffer passed in and the buffer ptr returned.
302  */
303 byte *send_message(byte *message, int len)
304 {
305
306         syscall_id this_call_id = *((syscall_id*)message);
307
308         if (write_to_channel(message, len) != len)
309                 return NULL;
310
311         int response_value;
312
313         // Pull the response from the server out of the channel.
314         if (read_from_channel((char*)&response_value, sizeof(int), 0) == -1) return NULL;
315
316         byte* return_msg = NULL;
317
318         // TODO: Make these sizes an array we index into, and only have this code once.
319         // TODO: Will have a flag that tells us we have a variable length response (right now only for read case)
320         // TODO: Default clause with error handling.
321         switch (this_call_id) {
322                 case OPEN_ID:
323                         if ((return_msg = (byte*)malloc(OPEN_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
324                                 return NULL;
325
326                         break;
327
328                 case CLOSE_ID:
329                         if ((return_msg = (byte*)malloc(CLOSE_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
330                                 return NULL;
331
332                         break;
333
334                 case READ_ID:
335                         if ((return_msg = (byte*)malloc(READ_RETURN_MESSAGE_FIXED_SIZE + response_value)) == NULL)
336                                 return NULL;
337
338
339                         if ((read_from_channel(return_msg + sizeof(int), response_value, 0)) == -1)
340                                 return NULL;
341
342                         break;
343
344                 case WRITE_ID:
345                         if ((return_msg = (byte*)malloc(WRITE_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
346                                 return NULL;
347
348                         break;
349
350
351                 case LSEEK_ID:
352                         if ((return_msg = (byte*)malloc(LSEEK_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
353                                 return NULL;
354
355                         break;
356
357                 case ISATTY_ID:
358                         if ((return_msg = (byte*)malloc(ISATTY_RETURN_MESSAGE_FIXED_SIZE)) == NULL)
359                                 return NULL;
360
361                         break;
362
363                 case UNLINK_ID:
364                         if ((return_msg = (byte*)malloc(UNLINK_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
365                                 return NULL;
366
367
368                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int), sizeof(int), 0)) == -1))
369                                 return NULL;
370
371                         break;
372
373                 case LINK_ID:
374                         if ((return_msg = (byte*)malloc(LINK_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
375                                 return NULL;
376
377
378                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int), sizeof(int), 0)) == -1))
379                                 return NULL;
380
381                         break;
382
383                 case FSTAT_ID:
384                         if ((return_msg = (byte*)malloc(FSTAT_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
385                                 return NULL;
386
387                         if ((read_from_channel(return_msg + sizeof(int), sizeof(struct stat), 0)) == -1)
388                                 return NULL;
389
390                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int) + sizeof(struct stat), sizeof(int), 0)) == -1))
391                                 return NULL;
392
393                         break;
394
395                 case STAT_ID:
396                         if ((return_msg = (byte*)malloc(STAT_RETURN_MESSAGE_FIXED_SIZE + ((response_value != -1) ? 0 : sizeof(int)))) == NULL)
397                                 return NULL;
398
399                         if ((read_from_channel(return_msg + sizeof(int), sizeof(struct stat), 0)) == -1)
400                                 return NULL;
401
402                         if ((response_value == -1) && ((read_from_channel(return_msg + sizeof(int) + sizeof(struct stat), sizeof(int), 0)) == -1))
403                                 return NULL;
404
405                         break;
406         }
407
408         memcpy(return_msg, &response_value, sizeof(int));
409
410         return return_msg;
411 }
412
413
414 /* stat()
415  * Status of a file (by name). 
416  * Minimal implementation.
417  */
418 int stat(char *file, struct stat *st) 
419 {
420         st->st_mode = S_IFCHR;
421         return 0;
422 }
423
424 /* times()
425  * Timing information for current process. 
426  * Minimal implementation.
427  */
428 int times(struct tms *buf) 
429 {
430         return -1;
431 }
432
433 /* unlink()
434  * Remove a file's directory entry. 
435  * Minimal implementation.
436  */
437 int unlink(char *name) 
438 {
439         errno = ENOENT;
440         return -1;
441 }
442
443 /* wait()
444  * Wait for a child process. 
445  * Minimal implementation.
446  */
447 int wait(int *status) 
448 {
449         errno = ECHILD;
450         return -1;
451 }
452
453 /* write()
454  * Write to a file. 
455  */
456 int write(int file, char *ptr, int len) {
457         if(file == 1) //STDOUT_FILENO
458                 return sys_cputs(ptr, len);
459         
460         int out_msg_len = WRITE_MESSAGE_FIXED_SIZE + len;
461
462         // Allocate a new buffer of proper size
463         byte *out_msg = malloc(out_msg_len);
464         byte *out_msg_pos = out_msg;
465
466         // Fill the buffer
467         *((syscall_id*)out_msg_pos) = WRITE_ID;
468         out_msg_pos += sizeof(syscall_id);
469
470         *((int*)out_msg_pos) = file;
471         out_msg_pos += sizeof(int);
472
473         *((int*)out_msg_pos) = len;
474         out_msg_pos += sizeof(int);
475
476         memcpy(out_msg_pos, ptr, len);
477
478         // Send message
479         byte *result = send_message(out_msg, out_msg_len);
480
481         free(out_msg);
482
483         // Read result
484         int return_val;
485
486         if (result != NULL) {
487                 return_val = *((int *)result);
488                 free(result);
489         } else {
490                 return_val = -1;
491         }
492
493         return return_val;
494 }
495
496
497 /* write_to_channel()
498  * Send a message out over the channel, defined by msg, of length len
499  */
500 int write_to_channel(byte * msg, int len)
501 {
502         return sys_serial_write((char*)msg, len);
503 }
504