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

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