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

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