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

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