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

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