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

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