AcessNative - Cleaning up debug
[tpg/acess2.git] / AcessNative / acesskernel_src / syscalls.c
1 /*
2  * Acess2 Native Kernel
3  * - Acess kernel emulation on another OS using SDL and UDP
4  *
5  * Syscall Distribution
6  */
7 #define DEBUG   0
8 #include <acess.h>
9 #include <threads.h>
10 #include <events.h>
11 #include "../syscalls.h"
12
13 // === IMPORTS ===
14 extern int      Threads_Fork(void);     // AcessNative only function
15
16 // === TYPES ===
17 typedef int     (*tSyscallHandler)(Uint *Errno, const char *Format, void *Args, int *Sizes);
18
19 // === MACROS ===
20 #define SYSCALL6(_name, _fmtstr, _t0, _t1, _t2, _t3, _t4, _t5, _call) int _name(Uint*Errno,const char*Fmt,void*Args,int*Sizes){\
21         _t0 a0;_t1 a1;_t2 a2;_t3 a3;_t4 a4;_t5 a5;\
22         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
23         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
24         a1 = *(_t1*)Args;Args+=sizeof(_t1);\
25         a2 = *(_t2*)Args;Args+=sizeof(_t2);\
26         a3 = *(_t3*)Args;Args+=sizeof(_t3);\
27         a4 = *(_t4*)Args;Args+=sizeof(_t4);\
28         a5 = *(_t5*)Args;Args+=sizeof(_t5);\
29         LOG("SYSCALL5 '%s' %p %p %p %p %p %p", Fmt, (intptr_t)a0,(intptr_t)a1,(intptr_t)a2,(intptr_t)a3,(intptr_t)a4,(intptr_t)a5);\
30         _call\
31 }
32 #define SYSCALL5(_name, _fmtstr, _t0, _t1, _t2, _t3, _t4, _call) int _name(Uint*Errno,const char*Fmt,void*Args,int*Sizes){\
33         _t0 a0;_t1 a1;_t2 a2;_t3 a3;_t4 a4;\
34         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
35         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
36         a1 = *(_t1*)Args;Args+=sizeof(_t1);\
37         a2 = *(_t2*)Args;Args+=sizeof(_t2);\
38         a3 = *(_t3*)Args;Args+=sizeof(_t3);\
39         a4 = *(_t4*)Args;Args+=sizeof(_t4);\
40         LOG("SYSCALL5 '%s' %p %p %p %p %p", Fmt, (intptr_t)a0,(intptr_t)a1,(intptr_t)a2,(intptr_t)a3,(intptr_t)a4);\
41         _call\
42 }
43 #define SYSCALL4(_name, _fmtstr, _t0, _t1, _t2, _t3, _call) int _name(Uint*Errno,const char*Fmt,void*Args,int*Sizes){\
44         _t0 a0;_t1 a1;_t2 a2;_t3 a3;\
45         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
46         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
47         a1 = *(_t1*)Args;Args+=sizeof(_t1);\
48         a2 = *(_t2*)Args;Args+=sizeof(_t2);\
49         a3 = *(_t3*)Args;Args+=sizeof(_t3);\
50         LOG("SYSCALL4 '%s' %p %p %p %p", Fmt, (intptr_t)a0,(intptr_t)a1,(intptr_t)a2,(intptr_t)a3);\
51         _call\
52 }
53
54 #define SYSCALL3(_name, _fmtstr, _t0, _t1, _t2, _call) int _name(Uint*Errno,const char*Fmt,void*Args,int*Sizes){\
55         _t0 a0;_t1 a1;_t2 a2;\
56         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
57         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
58         a1 = *(_t1*)Args;Args+=sizeof(_t1);\
59         a2 = *(_t2*)Args;Args+=sizeof(_t2);\
60         LOG("SYSCALL3 '%s' %p %p %p", Fmt, (intptr_t)a0,(intptr_t)a1,(intptr_t)a2);\
61         _call\
62 }
63
64 #define SYSCALL2(_name, _fmtstr, _t0, _t1, _call) int _name(Uint*Errno,const char*Fmt,void*Args,int*Sizes){\
65         _t0 a0;_t1 a1;\
66         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
67         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
68         a1 = *(_t1*)Args;Args+=sizeof(_t1);\
69         LOG("SYSCALL2 '%s' %p %p", Fmt, (intptr_t)a0,(intptr_t)a1);\
70         _call;\
71 }
72
73 #define SYSCALL1(_name, _fmtstr, _t0, _call) int _name(Uint*Errno,const char*Fmt, void*Args,int*Sizes){\
74         _t0 a0;\
75         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
76         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
77         LOG("SYSCALL1 '%s' %p", Fmt,(intptr_t)a0);\
78         _call;\
79 }
80
81 #define SYSCALL0(_name, _call) int _name(Uint*Errno,const char*Fmt, void*Args,int*Sizes){\
82         if(strcmp(Fmt,"")!=0)return 0;\
83         LOG("SYSCALL0");\
84         _call;\
85 }
86
87 // === CODE ===
88 int Syscall_Null(Uint*Errno, const char *Format, void *Args, int *Sizes)
89 {
90         return 0;
91 }
92
93 SYSCALL1(Syscall_Exit, "i", int,
94         Threads_Exit(0, a0);
95         return 0;
96 );
97
98 SYSCALL2(Syscall_Open, "si", const char *, int,
99         return VFS_Open(a0, a1|VFS_OPENFLAG_USER);
100 );
101 SYSCALL1(Syscall_Close, "i", int,
102         VFS_Close(a0);
103         return 0;
104 );
105 SYSCALL3(Syscall_Read, "iid", int, int, void *,
106         if( Sizes[2] < a1 ) {
107                 Log_Warning("Syscalls", "Read - %i < %i", Sizes[2], a1);
108                 return -1;
109         }
110         return VFS_Read(a0, a1, a2);
111 );
112 SYSCALL3(Syscall_Write, "iid", int, int, const void *,
113         if( Sizes[2] < a1 )
114                 return -1;
115         return VFS_Write(a0, a1, a2);
116 );
117 SYSCALL3(Syscall_Seek, "iIi", int, int64_t, int,
118         return VFS_Seek(a0, a1, a2);
119 );
120 SYSCALL1(Syscall_Tell, "i", int,
121         return VFS_Tell(a0);
122 );
123 SYSCALL3(Syscall_IOCtl, "iid", int, int, void *,
124         return VFS_IOCtl(a0, a1, a2);
125 );
126 SYSCALL3(Syscall_FInfo, "idi", int, void *, int,
127         if( Sizes[1] < sizeof(tFInfo)+a2*sizeof(tVFS_ACL)) {
128                 LOG("offsetof(size) = %i", offsetof(tFInfo, size));
129                 LOG("Bad size %i < %i", Sizes[1], sizeof(tFInfo)+a2*sizeof(tVFS_ACL));
130                 *Errno = -EINVAL;
131                 return -1;
132         }
133         return VFS_FInfo(a0, a1, a2);
134 );
135 SYSCALL2(Syscall_ReadDir, "id", int, char *,
136         if(Sizes[1] < 255)
137                 return -1;
138         return VFS_ReadDir(a0, a1);
139 );
140 SYSCALL6(Syscall_select, "iddddi", int, fd_set *, fd_set *, fd_set *, time_t *, unsigned int,
141         return VFS_Select(a0, a1, a2, a3, a4, a5, 0);
142 );
143 SYSCALL3(Syscall_OpenChild, "isi", int, const char *, int,
144         return VFS_OpenChild(a0, a1, a2|VFS_OPENFLAG_USER);
145 );
146 SYSCALL2(Syscall_GetACL, "id", int, void *,
147         if(Sizes[1] < sizeof(tVFS_ACL))
148                 return -1;
149         return VFS_GetACL(a0, (void*)a1);
150 );
151 SYSCALL4(Syscall_Mount, "ssss", const char *, const char *, const char *, const char *,
152         return VFS_Mount(a0, a1, a2, a3);
153 );
154 SYSCALL1(Syscall_Chdir, "s", const char *,
155         return VFS_ChDir(a0);
156 );
157 SYSCALL0(Syscall_Sleep,
158         Threads_Sleep();
159         return 0;
160 );
161 SYSCALL2(Syscall_WaitTID, "id", int, int *,
162         if(Sizes[1] < sizeof(int))
163                 return -1;
164         return Threads_WaitTID(a0, a1);
165 );
166 SYSCALL1(Syscall_SetUID, "i", int,
167         if(Sizes[0] < sizeof(int)) {
168                 *Errno = -EINVAL;       // TODO: Better message
169                 return -1;
170         }
171         return Threads_SetUID(a0);
172 );
173 SYSCALL1(Syscall_SetGID, "i", int,
174         if(Sizes[0] < sizeof(int)) {
175                 *Errno = -EINVAL;       // TODO: Better message
176                 return -1;
177         }
178         return Threads_SetGID(a0);
179 );
180
181 SYSCALL0(Syscall_GetTID, return Threads_GetTID());
182 SYSCALL0(Syscall_GetPID, return Threads_GetPID());
183 SYSCALL0(Syscall_GetUID, return Threads_GetUID());
184 SYSCALL0(Syscall_GetGID, return Threads_GetGID());
185
186 SYSCALL1(Syscall_AN_Fork, "d", int *,
187         if(Sizes[0] < sizeof(int))
188                 return -1;
189         *a0 = Threads_Fork();
190         return *a0;
191 );
192
193 SYSCALL2(Syscall_SendMessage, "id", int, void *,
194         return Proc_SendMessage(a0, Sizes[1], a1);
195 );
196
197 SYSCALL2(Syscall_GetMessage, "dd", uint32_t *, void *,
198         if( a0 && Sizes[0] < sizeof(*a0) ) {
199                 Log_Notice("Syscalls", "Syscall_GetMessage - Arg 1 Undersize (%i < %i)",
200                         Sizes[0], sizeof(*a0));
201                 return -1;
202         }
203         Uint    tmp;
204          int    rv;
205         if( a0 ) {
206                 rv = Proc_GetMessage(&tmp, a1);
207                 *a0 = tmp;
208         }
209         else
210                 rv = Proc_GetMessage(NULL, a1);
211         return rv;
212 );
213
214 SYSCALL1(Syscall_WaitEvent, "i", int,
215         return Threads_WaitEvents(a0);
216 );
217
218 const tSyscallHandler   caSyscalls[] = {
219         Syscall_Null,
220         Syscall_Exit,
221         Syscall_Open,
222         Syscall_Close,
223         Syscall_Read,
224         Syscall_Write,
225         Syscall_Seek,
226         Syscall_Tell,
227         Syscall_IOCtl,
228         Syscall_FInfo,
229         Syscall_ReadDir,
230         Syscall_OpenChild,
231         Syscall_GetACL,
232         Syscall_Mount,
233         NULL,   // SYS_REOPEN
234         Syscall_Chdir,
235         
236         Syscall_WaitTID,
237         Syscall_SetUID,
238         Syscall_SetGID,
239         
240         Syscall_GetTID,
241         Syscall_GetPID,
242         Syscall_GetUID,
243         Syscall_GetGID,
244
245         Syscall_Sleep,
246         Syscall_AN_Fork,
247
248         Syscall_SendMessage,
249         Syscall_GetMessage,
250         Syscall_select,
251         Syscall_WaitEvent
252 };
253 const int       ciNumSyscalls = sizeof(caSyscalls)/sizeof(caSyscalls[0]);
254 /**
255  * \brief Recieve a syscall structure from the server code
256  */
257 tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength)
258 {
259         char    formatString[Request->NParams+1];
260         char    *inData = (char*)&Request->Params[Request->NParams];
261          int    argListLen = 0;
262          int    i, retVal;
263         tRequestHeader  *ret;
264          int    retValueCount = 1;
265          int    retDataLen = sizeof(Uint64);
266         void    *returnData[Request->NParams];
267          int    argSizes[Request->NParams];
268         Uint    ret_errno = 0;
269         
270         // Sanity check
271         if( Request->CallID >= ciNumSyscalls ) {
272                 Log_Notice("Syscalls", "Unknown syscall number %i", Request->CallID);
273                 return NULL;
274         }
275         
276         if( !caSyscalls[Request->CallID] ) {
277                 Log_Notice("Syscalls", "Unimplemented syscall %i", Request->CallID);
278                 return NULL;
279         }
280         
281         // Get size of argument list
282         for( i = 0; i < Request->NParams; i ++ )
283         {
284                 argSizes[i] = Request->Params[i].Length;
285                 switch(Request->Params[i].Type)
286                 {
287                 case ARG_TYPE_VOID:
288                         formatString[i] = '-';
289                         break;
290                 case ARG_TYPE_INT32:
291                         formatString[i] = 'i';
292                         argListLen += sizeof(Uint32);
293                         break;
294                 case ARG_TYPE_INT64:
295                         formatString[i] = 'I';
296                         argListLen += sizeof(Uint64);
297                         break;
298                 case ARG_TYPE_DATA:
299                         formatString[i] = 'd';
300                         argListLen += sizeof(void*);
301                         break;
302                 case ARG_TYPE_STRING:
303                         formatString[i] = 's';
304                         argListLen += sizeof(char*);
305                         break;
306                 default:
307                         return NULL;    // ERROR!
308                 }
309         }
310         formatString[i] = '\0';
311         
312         LOG("Request %i(%s) '%s'", Request->CallID, casSYSCALL_NAMES[Request->CallID], formatString);
313         
314         {
315                 char    argListData[argListLen];
316                 argListLen = 0;
317                 // Build argument list
318                 for( i = 0; i < Request->NParams; i ++ )
319                 {
320                         returnData[i] = NULL;
321                         switch(Request->Params[i].Type)
322                         {
323                         case ARG_TYPE_VOID:
324                                 break;
325                         case ARG_TYPE_INT32:
326                                 //LOG("%i INT32: 0x%x", i, *(Uint32*)inData);
327                                 *(Uint32*)&argListData[argListLen] = *(Uint32*)inData;
328                                 argListLen += sizeof(Uint32);
329                                 inData += sizeof(Uint32);
330                                 break;
331                         case ARG_TYPE_INT64:
332                                 //LOG("%i INT64: 0x%llx", i, *(Uint64*)inData);
333                                 *(Uint64*)&argListData[argListLen] = *(Uint64*)inData;
334                                 argListLen += sizeof(Uint64);
335                                 inData += sizeof(Uint64);
336                                 break;
337                         case ARG_TYPE_STRING:
338                                 //LOG("%i STR: '%s'", i, (char*)inData);
339                                 *(char**)&argListData[argListLen] = (char*)inData;
340                                 argListLen += sizeof(void*);
341                                 inData += Request->Params[i].Length;
342                                 break;
343                         
344                         // Data gets special handling, because only it can be returned to the user
345                         // (ARG_TYPE_DATA is a pointer)
346                         case ARG_TYPE_DATA:
347                                 // Prepare the return values
348                                 if( Request->Params[i].Flags & ARG_FLAG_RETURN )
349                                 {
350                                         retDataLen += Request->Params[i].Length;
351                                         retValueCount ++;
352                                 }
353                                 
354                                 // Check for non-resident data
355                                 if( Request->Params[i].Length == 0 )
356                                 {
357                                         returnData[i] = NULL;
358                                         *(void**)&argListData[argListLen] = NULL;
359                                         argListLen += sizeof(void*);
360                                 }
361                                 else if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
362                                 {
363                                         // Allocate and zero the buffer
364                                         returnData[i] = calloc(1, Request->Params[i].Length);
365                                         //LOG("%i ZDAT: %i %p", i,
366                                         //      Request->Params[i].Length, returnData[i]);
367                                         *(void**)&argListData[argListLen] = returnData[i];
368                                         argListLen += sizeof(void*);
369                                 }
370                                 else
371                                 {
372                                         returnData[i] = (void*)inData;
373                                         //LOG("%i DATA: %i %p", i,
374                                         //      Request->Params[i].Length, returnData[i]);
375                                         *(void**)&argListData[argListLen] = (void*)inData;
376                                         argListLen += sizeof(void*);
377                                         inData += Request->Params[i].Length;
378                                 }
379                                 break;
380                         }
381                 }
382                 
383                 retVal = caSyscalls[Request->CallID](&ret_errno, formatString, argListData, argSizes);
384         }
385         
386         // Allocate the return
387         ret = malloc(sizeof(tRequestHeader) + retValueCount * sizeof(tRequestValue)
388                 + retDataLen);
389         ret->ClientID = Request->ClientID;
390         ret->CallID = Request->CallID;
391         ret->NParams = retValueCount;
392         inData = (char*)&ret->Params[ ret->NParams ];
393         
394         // Static Uint64 return value
395         ret->Params[0].Type = ARG_TYPE_INT64;
396         ret->Params[0].Flags = 0;
397         ret->Params[0].Length = sizeof(Uint64);
398         *(Uint64*)inData = retVal;
399         inData += sizeof(Uint64);
400         
401         Log_Debug("Syscalls", "Return 0x%llx", retVal);
402         
403         retValueCount = 1;
404         for( i = 0; i < Request->NParams; i ++ )
405         {
406                 if( Request->Params[i].Type != ARG_TYPE_DATA )  continue;
407                 if( !(Request->Params[i].Flags & ARG_FLAG_RETURN) )     continue;
408                 
409                 ret->Params[retValueCount].Type = Request->Params[i].Type;
410                 ret->Params[retValueCount].Flags = 0;
411                 ret->Params[retValueCount].Length = Request->Params[i].Length;
412                 
413                 LOG("Ret %i: Type %i, Len %i",
414                         i, Request->Params[i].Type, Request->Params[i].Length);
415                 
416                 memcpy(inData, returnData[i], Request->Params[i].Length);
417                 inData += Request->Params[i].Length;
418                 
419                 if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
420                         free( returnData[i] );  // Free temp buffer from above
421                 retValueCount ++;
422         }
423         
424         *ReturnLength = sizeof(tRequestHeader)
425                 + retValueCount * sizeof(tRequestValue)
426                 + retDataLen;
427         
428         return ret;
429 }

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