50352f8740b6148a9b0d53989179a0e1c61dc7c5
[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(tRequestValue *Dest, void *DataDest, void **PtrDest, const char *ArgTypes, va_list Args)
19 {
20         uint64_t        val64;
21         uint32_t        val32;
22          int    direction = 0;  // 0: Invalid, 1: Out, 2: In, 3: Out
23         char    *str;
24          int    len;
25         
26         // Eat whitespace
27         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
28         if( *ArgTypes == '\0' ) return ArgTypes;
29         
30         // Get direction
31         switch(*ArgTypes)
32         {
33         default:        // Defaults to output
34         case '>':       direction = 1;  break;
35         case '<':       direction = 2;  break;
36         case '?':       direction = 3;  break;
37         }
38         ArgTypes ++;
39         
40         // Eat whitespace
41         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
42         if( *ArgTypes == '\0' ) return ArgTypes;
43         
44         // Get type
45         switch(*ArgTypes)
46         {
47         // 32-bit integer
48         case 'i':
49                 
50                 if( direction != 1 ) {
51                         fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
52                         return NULL;
53                 }
54                 
55                 val32 = va_arg(Args, uint32_t);
56                 
57                 Dest->Type = ARG_TYPE_INT32;
58                 Dest->Length = sizeof(uint32_t);
59                 Dest->Flags = 0;
60                 
61                 if( DataDest )
62                         *(uint32_t*)DataDest = val32;
63                 break;
64         // 64-bit integer
65         case 'I':
66                 
67                 if( direction != 1 ) {
68                         fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
69                         return NULL;
70                 }
71                 
72                 val64 = va_arg(Args, uint64_t);
73                 
74                 Dest->Type = ARG_TYPE_INT64;
75                 Dest->Length = sizeof(uint64_t);
76                 Dest->Flags = 0;
77                 if( DataDest )
78                         *(uint64_t*)DataDest = val64;
79                 break;
80         // String
81         case 's':
82                 // Input string makes no sense!
83                 if( direction != 1 ) {
84                         fprintf(stderr, "ReadEntry: Recieving a string is not defined\n");
85                         return NULL;
86                 }
87                 
88                 str = va_arg(Args, char*);
89                 
90                 Dest->Type = ARG_TYPE_STRING;
91                 Dest->Length = strlen(str) + 1;
92                 Dest->Flags = 0;
93                 
94                 if( DataDest )
95                 {
96                         memcpy(DataDest, str, Dest->Length);
97                 }
98                 break;
99         // Data (special handling)
100         case 'd':
101                 len = va_arg(Args, int);
102                 str = va_arg(Args, char*);
103                 
104                 // Save the pointer for later
105                 if( PtrDest )   *PtrDest = str;
106                 
107                 // Create parameter block
108                 Dest->Type = ARG_TYPE_INT64;
109                 Dest->Length = sizeof(uint64_t);
110                 Dest->Flags = 0;
111                 if( direction & 2 )
112                         Dest->Flags |= ARG_FLAG_RETURN;
113                 
114                 // Has data?
115                 if( direction & 1 )
116                 {
117                         if( DataDest )
118                                 memcpy(DataDest, str, len);
119                 }
120                 else
121                         Dest->Flags |= ARG_FLAG_ZEROED;
122                 break;
123         
124         default:
125                 return NULL;
126         }
127         ArgTypes ++;
128         
129         return ArgTypes;
130 }
131
132 /**
133  * \param ArgTypes
134  *
135  * Whitespace is ignored
136  * >i:  Input Integer (32-bits)
137  * >I:  Input Long Integer (64-bits)
138  * >s:  Input String
139  * >d:  Input Buffer (Preceded by valid size)
140  * <I:  Output long integer
141  * <d:  Output Buffer (Preceded by valid size)
142  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
143  *      are returned
144  */
145 uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...)
146 {
147         va_list args;
148          int    paramCount, dataLength;
149          int    retCount = 1, retLength = sizeof(uint64_t);
150         void    **retPtrs;      // Pointers to return buffers
151         const char      *str;
152         tRequestHeader  *req;
153         void    *dataPtr;
154         uint64_t        retValue;
155          int    i;
156         
157         // Get data size
158         va_start(args, ArgTypes);
159         str = ArgTypes;
160         paramCount = 0;
161         dataLength = 0;
162         while(*str)
163         {
164                 tRequestValue   tmpVal;
165                 
166                 str = ReadEntry(&tmpVal, NULL, NULL, str, args);
167                 if( !str ) {
168                         fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
169                         exit(127);
170                 }
171                 paramCount ++;
172                 if( !(tmpVal.Flags & ARG_FLAG_ZEROED) )
173                         dataLength += tmpVal.Length;
174                 
175                 if( tmpVal.Flags & ARG_FLAG_RETURN ) {
176                         retLength += tmpVal.Length;
177                         retCount ++;
178                 }
179         }
180         va_end(args);
181         
182         dataLength += sizeof(tRequestHeader) + paramCount*sizeof(tRequestValue);
183         retLength += sizeof(tRequestHeader) + retCount*sizeof(tRequestValue);
184         
185         // Allocate buffers
186         retPtrs = malloc( sizeof(void*) * (retCount+1) );
187         if( dataLength > retLength)
188                 req = malloc( dataLength );
189         else
190                 req = malloc( retLength );
191         req->ClientID = 0;      //< Filled later
192         req->CallID = SyscallID;
193         req->NParams = paramCount;
194         dataPtr = &req->Params[paramCount];
195         
196         // Fill `output` and `input`
197         va_start(args, ArgTypes);
198         str = ArgTypes;
199         // - re-zero so they can be used as indicies
200         paramCount = 0;
201         retCount = 0;
202         while(*str)
203         {               
204                 str = ReadEntry(&req->Params[paramCount], dataPtr, &retPtrs[retCount], str, args);
205                 if( !str )      break;
206                 
207                 if( !(req->Params[paramCount].Flags & ARG_FLAG_ZEROED) )
208                         dataPtr += req->Params[paramCount].Length;
209                 if( req->Params[paramCount].Flags & ARG_FLAG_RETURN )
210                         retCount ++;
211                 
212                 paramCount ++;
213         }
214         va_end(args);
215         
216         // Send syscall request
217         if( SendRequest(req, dataLength) ) {
218                 fprintf(stderr, "syscalls.c: SendRequest failed (SyscallID = %i)\n", SyscallID);
219                 exit(127);
220         }
221         
222         // Parse return value
223         dataPtr = &req->Params[req->NParams];
224         retValue = 0;
225         if( req->NParams > 1 )
226         {
227                 switch(req->Params[0].Type)
228                 {
229                 case ARG_TYPE_INT64:
230                         retValue = *(uint64_t*)dataPtr;
231                         dataPtr += req->Params[0].Length;
232                         break;
233                 case ARG_TYPE_INT32:
234                         retValue = *(uint32_t*)dataPtr;
235                         dataPtr += req->Params[0].Length;
236                         break;
237                 }       
238         }
239         
240         // Write changes to buffers
241         va_start(args, ArgTypes);
242         for( i = 1; i < req->NParams; i ++ )
243         {
244                 memcpy( retPtrs[i-1], dataPtr, req->Params[i].Length );
245                 dataPtr += req->Params[i].Length;
246         }
247         va_end(args);
248         
249         free( req );
250         
251         return 0;
252 }
253
254 // --- VFS Calls
255 int open(const char *Path, int Flags) {
256         return _Syscall(SYS_OPEN, ">s >i", Path, Flags);
257 }
258
259 void close(int FD) {
260         _Syscall(SYS_CLOSE, ">i", FD);
261 }
262
263 size_t read(int FD, size_t Bytes, void *Dest) {
264         return _Syscall(SYS_READ, "<i >i >i <d", FD, Bytes, Bytes, Dest);
265 }
266
267 size_t write(int FD, size_t Bytes, void *Src) {
268         return _Syscall(SYS_WRITE, ">i >i >d", FD, Bytes, Bytes, Src);
269 }
270
271 int seek(int FD, int64_t Ofs, int Dir) {
272         return _Syscall(SYS_SEEK, ">i >I >i", FD, Ofs, Dir);
273 }
274
275 uint64_t tell(int FD) {
276         return _Syscall(SYS_TELL, ">i", FD);
277 }
278
279 int ioctl(int fd, int id, void *data) {
280          int    ret = 0;
281         // NOTE: 1024 byte size is a hack
282         _Syscall(SYS_IOCTL, "<i >i >i ?d", &ret, fd, id, 1024, data);
283         return ret;
284 }
285 int finfo(int fd, t_sysFInfo *info, int maxacls) {
286          int    ret = 0;
287         _Syscall(SYS_FINFO, "<i >i <d >i",
288                 &ret, fd,
289                 sizeof(t_sysFInfo)+maxacls*sizeof(t_sysACL), info,
290                 maxacls);
291         return ret;
292 }
293
294 int readdir(int fd, char *dest) {
295          int    ret = 0;
296         _Syscall(SYS_READDIR, "<i >i <d", &ret, fd, 256, dest);
297         return ret;
298 }
299
300 int _SysOpenChild(int fd, char *name, int flags) {
301          int    ret = 0;
302         _Syscall(SYS_OPENCHILD, "<i >i >s >i", &ret, fd, name, flags);
303         return ret;
304 }
305
306 int _SysGetACL(int fd, t_sysACL *dest) {
307          int    ret = 0;
308         _Syscall(SYS_GETACL, "<i >i <d", &ret, fd, sizeof(t_sysACL), dest);
309         return ret;
310 }
311
312 int _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options) {
313          int    ret = 0;
314         _Syscall(SYS_MOUNT, "<i >s >s >s >s", &ret, Device, Directory, Type, Options);
315         return ret;
316 }
317
318
319 // --- Error Handler
320 int     _SysSetFaultHandler(int (*Handler)(int)) {
321         return 0;
322 }
323
324
325 // === Symbol List ===
326 #define DEFSYM(name)    {#name, name}
327 const tSym      caBuiltinSymbols[] = {
328         {"_exit", exit},
329         
330         DEFSYM(open),
331         DEFSYM(close),
332         DEFSYM(read),
333         DEFSYM(write),
334         DEFSYM(seek),
335         DEFSYM(tell),
336         DEFSYM(ioctl),
337         DEFSYM(finfo),
338         DEFSYM(readdir),
339         DEFSYM(_SysOpenChild),
340         DEFSYM(_SysGetACL),
341         DEFSYM(_SysMount),
342         
343         {"_SysSetFaultHandler", _SysSetFaultHandler}
344 };
345
346 const int       ciNumBuiltinSymbols = sizeof(caBuiltinSymbols)/sizeof(caBuiltinSymbols[0]);
347

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