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

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