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

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