Lots of work on the AcessNative kernel
[tpg/acess2.git] / AcessNative / ld-acess_src / syscalls.c
1 /*
2  */
3 #include "../../Usermode/include/acess/sys.h"
4 #include "common.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include "request.h"
11 #include "../syscalls.h"
12
13 // === Types ===
14
15 // === IMPORTS ===
16
17 // === CODE ===
18 const char *ReadEntry(tOutValue **OutDest, tInValue **InDest,
19         int *Direction, const char *ArgTypes, va_list Args)
20 {
21         uint64_t        val64, *ptr64;
22         uint32_t        val32, *ptr32;
23          int    direction = 0;  // 0: Invalid, 1: Out, 2: In, 3: Out
24         char    *str;
25          int    len;
26         
27         // Eat whitespace
28         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
29         if( *ArgTypes == '\0' ) return ArgTypes;
30         
31         // Get direction
32         switch(*ArgTypes)
33         {
34         case '>':       direction = 1;  break;
35         case '<':       direction = 2;  break;
36         case '?':       direction = 3;  break;
37         default:
38                 return NULL;
39         }
40         ArgTypes ++;
41         
42         // Eat whitespace
43         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
44         if( *ArgTypes == '\0' ) return ArgTypes;
45         
46         // Internal helper macro
47         #define MAKE_OUT(_dest,_typeChar,_typeName,_value) do{if((_dest)){\
48                 *(_dest) = (tOutValue*)malloc(sizeof(tOutValue)+sizeof(_typeName));\
49                 (*(_dest))->Type=(_typeChar);(*(_dest))->Length=sizeof(_typeName);\
50                 *(_typeName*)((*(_dest))->Data) = (_value);\
51                 }}while(0)
52         #define MAKE_IN(_dest,_typeChar,_typeName,_value) do{if((_dest)){\
53                 *(_dest) = (tInValue*)malloc(sizeof(tInValue));\
54                 (*(_dest))->Type=(_typeChar);(*(_dest))->Length=sizeof(_typeName);\
55                 (*(_dest))->Data = (_value);\
56                 }}while(0)
57         
58         // Get type
59         switch(*ArgTypes)
60         {
61         case 'i':       // 32-bit integer
62                 // Input?
63                 if( direction & 2 )
64                 {
65                         ptr32 = va_arg(Args, uint32_t*);
66                         MAKE_IN(InDest, 'i', uint32_t*, ptr32);
67                         if( direction & 1 )
68                                 MAKE_OUT(OutDest, 'i', uint32_t, *ptr32);
69                 }
70                 else
71                 {
72                         val32 = va_arg(Args, uint32_t);
73                         MAKE_OUT(OutDest, 'i', uint32_t, val32);
74                 }
75                 break;
76         case 'I':       // 64-bit integer
77                 // Input?
78                 if( direction & 2 )
79                 {
80                         ptr64 = va_arg(Args, uint64_t*);
81                         MAKE_IN(InDest, 'I', uint64_t*, ptr64);
82                         if( direction & 1 )
83                                 MAKE_OUT(OutDest, 'I', uint64_t, *ptr64);
84                 }
85                 else
86                 {
87                         val64 = va_arg(Args, uint64_t);
88                         MAKE_OUT(OutDest, 'I', uint64_t, val64);
89                 }
90                 break;
91         case 's':
92                 // Input string makes no sense!
93                 if( direction & 2 ) {
94                         fprintf(stderr, "ReadEntry: Incoming string is not defined\n");
95                         return NULL;
96                 }
97                 
98                 str = va_arg(Args, char*);
99                 if( OutDest )
100                 {
101                          int    len = strlen(str) + 1;
102                         *OutDest = malloc( sizeof(tOutValue) + len );
103                         (*OutDest)->Type = 's';
104                         (*OutDest)->Length = len;
105                         memcpy((*OutDest)->Data, str, len);
106                 }
107                 break;
108         
109         case 'd':
110                 len = va_arg(Args, int);
111                 str = va_arg(Args, char*);
112                 
113                 // Input ?
114                 if( (direction & 2) && InDest )
115                 {
116                         *InDest = (tInValue*)malloc( sizeof(tInValue) );
117                         (*InDest)->Type = 'd';
118                         (*InDest)->Length = len;
119                         (*InDest)->Data = str;
120                 }
121                 
122                 // Output ?
123                 if( (direction & 1) && InDest )
124                 {
125                         *OutDest = (tOutValue*)malloc( sizeof(tOutValue) + len );
126                         (*OutDest)->Type = 'd';
127                         (*OutDest)->Length = len;
128                         memcpy((*OutDest)->Data, str, len);
129                 }
130                 break;
131         
132         default:
133                 return NULL;
134         }
135         ArgTypes ++;
136         #undef MAKE_ASSIGN
137         
138         *Direction = direction;
139         
140         return ArgTypes;
141 }
142
143 /**
144  * \param ArgTypes
145  *
146  * Whitespace is ignored
147  * >i:  Input Integer (32-bits)
148  * >I:  Input Long Integer (64-bits)
149  * >s:  Input String
150  * >d:  Input Buffer (Preceded by valid size)
151  * <I:  Output long integer
152  * <d:  Output Buffer (Preceded by valid size)
153  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
154  *      are returned
155  */
156 void _Syscall(int SyscallID, const char *ArgTypes, ...)
157 {
158         va_list args;
159          int    outCount;
160          int    inCount;
161         const char      *str;
162         tOutValue       **output;
163         tInValue        **input;
164         
165         // Get data size
166         va_start(args, ArgTypes);
167         str = ArgTypes;
168         outCount = 0;
169         inCount = 0;
170         while(*str)
171         {
172                  int    dir;
173                 
174                 str = ReadEntry(NULL, NULL, &dir, str, args);
175                 if( !str ) {
176                         fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
177                         exit(127);
178                 }
179                 
180                 // Out!
181                 if( dir & 1 )   outCount ++;
182                 
183                 // and.. In!
184                 if( dir & 2 )   inCount ++;
185         }
186         va_end(args);
187         
188         // Allocate buffers
189         output = malloc( outCount*sizeof(tOutValue*) );
190         input = malloc( inCount*sizeof(tInValue*) );
191         
192         // Fill `output` and `input`
193         va_start(args, ArgTypes);
194         str = ArgTypes;
195         // - re-zero so they can be used as indicies
196         outCount = 0;
197         inCount = 0;
198         while(*str)
199         {
200                 tOutValue       *outParam;
201                 tInValue        *inParam;
202                  int    dir;
203                 
204                 str = ReadEntry(&outParam, &inParam, &dir, str, args);
205                 if( !str )      break;
206                 
207                 if( dir & 1 )
208                         output[outCount++] = outParam;
209                 if( dir & 2 )
210                         input[inCount++] = inParam;
211         }
212         va_end(args);
213         
214         // Send syscall request
215         if( SendRequest(SyscallID, outCount, output, inCount, input) ) {
216                 fprintf(stderr, "syscalls.c: SendRequest failed (SyscallID = %i)\n", SyscallID);
217                 exit(127);
218         }
219         
220         // Clean up
221         while(outCount--)       free(output[outCount]);
222         free(output);
223         while(inCount--)        free(input[inCount]);
224         free(input);
225 }
226
227 // --- VFS Calls
228 int open(const char *Path, int Flags) {
229          int    ret = 0;
230         _Syscall(SYS_OPEN, "<i >s >i", &ret, Path, Flags);
231         return ret;
232 }
233
234 void close(int FD) {
235         _Syscall(SYS_CLOSE, ">i", FD);
236 }
237
238 size_t read(int FD, size_t Bytes, void *Dest) {
239          int    ret = 0;
240         _Syscall(SYS_READ, "<i >i >i <d", &ret, FD, Bytes, Bytes, Dest);
241         return ret;
242 }
243
244 size_t write(int FD, size_t Bytes, void *Src) {
245          int    ret = 0;
246         _Syscall(SYS_WRITE, "<i >i >i >d", &ret, FD, Bytes, Bytes, Src);
247         return ret;
248 }
249
250 int seek(int FD, int64_t Ofs, int Dir) {
251          int    ret = 0;
252         _Syscall(SYS_SEEK, "<i >i >I >i", &ret, FD, Ofs, Dir);
253         return ret;
254 }
255
256 uint64_t tell(int FD) {
257         uint64_t        ret;
258         _Syscall(SYS_TELL, "<I >i", &ret, FD);
259         return ret;
260 }
261
262 int ioctl(int fd, int id, void *data) {
263          int    ret = 0;
264         // NOTE: 1024 byte size is a hack
265         _Syscall(SYS_IOCTL, "<i >i >i ?d", &ret, fd, id, 1024, data);
266         return ret;
267 }
268 int finfo(int fd, t_sysFInfo *info, int maxacls) {
269          int    ret = 0;
270         _Syscall(SYS_FINFO, "<i >i <d >i",
271                 &ret, fd,
272                 sizeof(t_sysFInfo)+maxacls*sizeof(t_sysACL), info,
273                 maxacls);
274         return ret;
275 }
276
277 int readdir(int fd, char *dest) {
278          int    ret = 0;
279         _Syscall(SYS_READDIR, "<i >i <d", &ret, fd, 256, dest);
280         return ret;
281 }
282
283 int _SysOpenChild(int fd, char *name, int flags) {
284          int    ret = 0;
285         _Syscall(SYS_OPENCHILD, "<i >i >s >i", &ret, fd, name, flags);
286         return ret;
287 }
288
289 int _SysGetACL(int fd, t_sysACL *dest) {
290          int    ret = 0;
291         _Syscall(SYS_GETACL, "<i >i <d", &ret, fd, sizeof(t_sysACL), dest);
292         return ret;
293 }
294
295 int _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options) {
296          int    ret = 0;
297         _Syscall(SYS_MOUNT, "<i >s >s >s >s", &ret, Device, Directory, Type, Options);
298         return ret;
299 }
300
301
302 // --- Error Handler
303 int     _SysSetFaultHandler(int (*Handler)(int)) {
304         return 0;
305 }
306
307
308 // === Symbol List ===
309 #define DEFSYM(name)    {#name, name}
310 const tSym      caBuiltinSymbols[] = {
311         {"_exit", exit},
312         
313         DEFSYM(open),
314         DEFSYM(close),
315         DEFSYM(read),
316         DEFSYM(write),
317         DEFSYM(seek),
318         DEFSYM(tell),
319         DEFSYM(ioctl),
320         DEFSYM(finfo),
321         DEFSYM(readdir),
322         DEFSYM(_SysOpenChild),
323         DEFSYM(_SysGetACL),
324         DEFSYM(_SysMount),
325         
326         {"_SysSetFaultHandler", _SysSetFaultHandler}
327 };
328
329 const int       ciNumBuiltinSymbols = sizeof(caBuiltinSymbols)/sizeof(caBuiltinSymbols[0]);
330

UCC git Repository :: git.ucc.asn.au