Merge branch 'master' of github.com:thepowersgang/acess2
[tpg/acess2.git] / AcessNative / ld-acess_src / syscalls.c
1 /*
2  */
3 #define DONT_INCLUDE_SYSCALL_NAMES 1
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 <stddef.h>
11 #include <unistd.h>
12 #ifndef __WIN32__
13 # include <spawn.h>     // posix_spawn
14 #endif
15 #include "request.h"
16
17 #if SYSCALL_TRACE
18 #define DEBUG(str, x...)        Debug(str, x)
19 #else
20 #define DEBUG(...)      do{}while(0)
21 #endif
22
23 #define MAX_FPS 16
24
25 // === Types ===
26
27 // === IMPORTS ===
28
29 // === GLOBALS ===
30 FILE    *gaSyscall_LocalFPs[MAX_FPS];
31
32 // === CODE ===
33 const char *ReadEntry(tRequestValue *Dest, void *DataDest, void **PtrDest, const char *ArgTypes, va_list *Args)
34 {
35         uint64_t        val64;
36         uint32_t        val32;
37          int    direction = 0;  // 0: Invalid, 1: Out, 2: In, 3: Out
38         char    *str;
39          int    len;
40
41         // Eat whitespace
42         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
43         if( *ArgTypes == '\0' ) return ArgTypes;
44         
45 //      DEBUG("ArgTypes = '%s'", ArgTypes);
46         
47         // Get direction
48         switch(*ArgTypes)
49         {
50         default:        // Defaults to output
51         case '>':       direction = 1;  break;
52         case '<':       direction = 2;  break;
53         case '?':       direction = 3;  break;
54         }
55         ArgTypes ++;
56         
57         // Eat whitespace
58         while(*ArgTypes && *ArgTypes == ' ')    ArgTypes ++;
59         if( *ArgTypes == '\0' ) return ArgTypes;
60         
61         // Get type
62         switch(*ArgTypes)
63         {
64         // 32-bit integer
65         case 'i':
66                 
67                 if( direction != 1 ) {
68                         Warning("ReadEntry: Recieving an integer is not defined");
69                         return NULL;
70                 }
71                 
72                 val32 = va_arg(*Args, uint32_t);
73                 
74                 Dest->Type = ARG_TYPE_INT32;
75                 Dest->Length = sizeof(uint32_t);
76                 Dest->Flags = 0;
77                 
78                 if( DataDest )
79                         *(uint32_t*)DataDest = val32;
80                 break;
81         // 64-bit integer
82         case 'I':
83                 
84                 if( direction != 1 ) {
85                         fprintf(stderr, "ReadEntry: Recieving an integer is not defined\n");
86                         return NULL;
87                 }
88                 
89                 val64 = va_arg(*Args, uint64_t);
90                 
91                 Dest->Type = ARG_TYPE_INT64;
92                 Dest->Length = sizeof(uint64_t);
93                 Dest->Flags = 0;
94                 if( DataDest )
95                         *(uint64_t*)DataDest = val64;
96                 break;
97         // String
98         case 's':
99                 // Input string makes no sense!
100                 if( direction != 1 ) {
101                         fprintf(stderr, "ReadEntry: Recieving a string is not defined\n");
102                         return NULL;
103                 }
104                 
105                 str = va_arg(*Args, char*);
106                 
107                 Dest->Type = ARG_TYPE_STRING;
108                 Dest->Length = strlen(str) + 1;
109                 Dest->Flags = 0;
110                 
111                 if( DataDest )
112                 {
113                         memcpy(DataDest, str, Dest->Length);
114                 }
115                 break;
116         // Data (special handling)
117         case 'd':
118                 len = va_arg(*Args, size_t);
119                 str = va_arg(*Args, char*);
120                 
121                 // Save the pointer for later
122                 if( PtrDest )   *PtrDest = str;
123                 
124                 // Create parameter block
125                 Dest->Type = ARG_TYPE_DATA;
126                 Dest->Length = str ? len : 0;
127                 Dest->Flags = 0;
128                 if( direction & 2 )
129                         Dest->Flags |= ARG_FLAG_RETURN;
130                 
131                 // Has data?
132                 if( direction & 1 )
133                 {
134                         if( DataDest && str )
135                                 memcpy(DataDest, str, len);
136                 }
137                 else
138                         Dest->Flags |= ARG_FLAG_ZEROED;
139                 break;
140         
141         default:
142                 return NULL;
143         }
144         ArgTypes ++;
145         
146         return ArgTypes;
147 }
148
149 /**
150  * \param ArgTypes
151  *
152  * Whitespace is ignored
153  * >i:  Input Integer (32-bits)
154  * >I:  Input Long Integer (64-bits)
155  * >s:  Input String
156  * >d:  Input Buffer (Preceded by valid size)
157  * <I:  Output long integer
158  * <d:  Output Buffer (Preceded by valid size)
159  * ?d:  Bi-directional buffer (Preceded by valid size), buffer contents
160  *      are returned
161  */
162 uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...)
163 {
164         va_list args;
165          int    paramCount, dataLength;
166          int    retCount = 1, retLength = sizeof(uint64_t);
167         void    **retPtrs;      // Pointers to return buffers
168         const char      *str;
169         tRequestHeader  *req;
170         void    *dataPtr;
171         uint64_t        retValue;
172          int    i;
173         
174         // DEBUG!
175 //      printf("&tRequestHeader->Params = %i\n", offsetof(tRequestHeader, Params));
176 //      printf("&tRequestValue->Flags = %i\n", offsetof(tRequestValue, Flags));
177 //      printf("&tRequestValue->Length = %i\n", offsetof(tRequestValue, Length));
178         
179         // Get data size
180         va_start(args, ArgTypes);
181         str = ArgTypes;
182         paramCount = 0;
183         dataLength = 0;
184         while(*str)
185         {
186                 tRequestValue   tmpVal;
187                 
188                 str = ReadEntry(&tmpVal, NULL, NULL, str, &args);
189                 if( !str ) {
190                         fprintf(stderr, "syscalls.c: ReadEntry failed (SyscallID = %i)\n", SyscallID);
191                         exit(127);
192                 }
193                 paramCount ++;
194                 if( !(tmpVal.Flags & ARG_FLAG_ZEROED) )
195                         dataLength += tmpVal.Length;
196                 
197                 if( tmpVal.Flags & ARG_FLAG_RETURN ) {
198                         retLength += tmpVal.Length;
199                         retCount ++;
200                 }
201         }
202         va_end(args);
203         
204         dataLength += sizeof(tRequestHeader) + paramCount*sizeof(tRequestValue);
205         retLength += sizeof(tRequestHeader) + retCount*sizeof(tRequestValue);
206         
207         // Allocate buffers
208         retPtrs = malloc( sizeof(void*) * (retCount+1) );
209         if( dataLength > retLength)
210                 req = malloc( dataLength );
211         else
212                 req = malloc( retLength );
213         req->ClientID = 0;      //< Filled later
214         req->CallID = SyscallID;
215         req->NParams = paramCount;
216         req->MessageLength = dataLength;
217         dataPtr = &req->Params[paramCount];
218         
219         // Fill `output` and `input`
220         va_start(args, ArgTypes);
221         str = ArgTypes;
222         // - re-zero so they can be used as indicies
223         paramCount = 0;
224         retCount = 0;
225         while(*str)
226         {               
227                 str = ReadEntry(&req->Params[paramCount], dataPtr, &retPtrs[retCount], str, &args);
228                 if( !str )      break;
229                 
230                 if( !(req->Params[paramCount].Flags & ARG_FLAG_ZEROED) )
231                         dataPtr += req->Params[paramCount].Length;
232                 if( req->Params[paramCount].Flags & ARG_FLAG_RETURN )
233                         retCount ++;
234                 
235                 paramCount ++;
236         }
237         va_end(args);
238         
239         // Send syscall request
240         if( SendRequest(req, dataLength, retLength) < 0 ) {
241                 fprintf(stderr, "syscalls.c: SendRequest failed (SyscallID = %i)\n", SyscallID);
242                 exit(127);
243         }
244         
245         // Parse return value
246         dataPtr = &req->Params[req->NParams];
247         retValue = 0;
248         if( req->NParams >= 1 )
249         {
250                 switch(req->Params[0].Type)
251                 {
252                 case ARG_TYPE_INT64:
253                         retValue = *(uint64_t*)dataPtr;
254                         dataPtr += req->Params[0].Length;
255                         break;
256                 case ARG_TYPE_INT32:
257                         retValue = *(uint32_t*)dataPtr;
258                         dataPtr += req->Params[0].Length;
259                         break;
260                 }       
261         }
262         
263         // Write changes to buffers
264         if( req->NParams - 1 != retCount ) {
265                 fprintf(stderr, "syscalls.c: Return count inbalance (%i - 1 != exp %i) [Call %i]\n",
266                         req->NParams, retCount, SyscallID);
267                 exit(127);
268         }
269         retCount = 0;
270         for( i = 1; i < req->NParams; i ++ )
271         {
272                 #if 0
273                  int     j;
274                 printf("Return Data %i: (%i)", i, req->Params[i].Length);
275                 for( j = 0; j < req->Params[i].Length; j ++ )
276                         printf(" %02x", ((uint8_t*)dataPtr)[j]);
277                 printf("\n");
278                 #endif
279                 memcpy( retPtrs[retCount++], dataPtr, req->Params[i].Length );
280                 dataPtr += req->Params[i].Length;
281         }
282         
283         free( req );
284         free( retPtrs );
285         
286         DEBUG(": %i 0x%llx", SyscallID, retValue);
287         
288         return retValue;
289 }
290
291
292 int native_open(const char *Path, int Flags)
293 {
294         int     ret;
295        for(ret = 0; ret < MAX_FPS && gaSyscall_LocalFPs[ret]; ret ++ )  ;
296        if(ret == MAX_FPS)       return -1;
297        // TODO: Handle directories
298        gaSyscall_LocalFPs[ret] = fopen(&Path[4], "r+");
299        if(!gaSyscall_LocalFPs[ret])     return -1;
300        return ret;
301 }
302
303 void native_close(int FD)
304 {
305         fclose( gaSyscall_LocalFPs[FD] );
306         gaSyscall_LocalFPs[FD] = NULL;
307 }
308
309 size_t native_read(int FD, void *Dest, size_t Bytes)
310 {
311         return fread( Dest, Bytes, 1, gaSyscall_LocalFPs[FD] );
312 }
313
314 size_t native_write(int FD, const void *Src, size_t Bytes)
315 {
316         return fwrite( Src, Bytes, 1, gaSyscall_LocalFPs[FD] );
317 }
318
319 int native_seek(int FD, int64_t Ofs, int Dir)
320 {
321         if(Dir == 0)
322                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_CUR );
323         else if(Dir > 0)
324                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_SET );
325         else
326                 return fseek( gaSyscall_LocalFPs[FD], Ofs, SEEK_END );
327 }
328
329 uint64_t native_tell(int FD)
330 {
331         return ftell( gaSyscall_LocalFPs[FD] );
332 }
333
334 int native_execve(const char *filename, const char *const argv[], const char *const envp[])
335 {
336         int ret;
337         ret = execve(filename, (void*)argv, (void*)envp);
338         perror("native_execve");
339         return ret;
340 }
341
342 int native_spawn(const char *filename, const char *const argv[], const char *const envp[])
343 {
344         int rv;
345         
346         #if __WIN32__
347         rv = _spawnve(_P_NOWAIT, filename, argv, envp);
348         #else
349         rv = posix_spawn(NULL, filename, NULL, NULL, (void*)argv, (void*)envp);
350         #endif
351         
352         return rv;
353 }

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