58dc80171cf245a83ab481ca6b6fe5dd9a51f287
[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   1
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", Uint *, void *,
198         if( Sizes[0] < sizeof(*a0) )
199                 return -1;
200         return Proc_GetMessage(a0, a1);
201 );
202
203 SYSCALL1(Syscall_WaitEvent, "i", int,
204         return Threads_WaitEvents(a0);
205 );
206
207 const tSyscallHandler   caSyscalls[] = {
208         Syscall_Null,
209         Syscall_Exit,
210         Syscall_Open,
211         Syscall_Close,
212         Syscall_Read,
213         Syscall_Write,
214         Syscall_Seek,
215         Syscall_Tell,
216         Syscall_IOCtl,
217         Syscall_FInfo,
218         Syscall_ReadDir,
219         Syscall_OpenChild,
220         Syscall_GetACL,
221         Syscall_Mount,
222         NULL,   // SYS_REOPEN
223         Syscall_Chdir,
224         
225         Syscall_WaitTID,
226         Syscall_SetUID,
227         Syscall_SetGID,
228         
229         Syscall_GetTID,
230         Syscall_GetPID,
231         Syscall_GetUID,
232         Syscall_GetGID,
233
234         Syscall_Sleep,
235         Syscall_AN_Fork,
236
237         Syscall_SendMessage,
238         Syscall_GetMessage,
239         Syscall_select,
240         Syscall_WaitEvent
241 };
242 const int       ciNumSyscalls = sizeof(caSyscalls)/sizeof(caSyscalls[0]);
243 /**
244  * \brief Recieve a syscall structure from the server code
245  */
246 tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength)
247 {
248         char    formatString[Request->NParams+1];
249         char    *inData = (char*)&Request->Params[Request->NParams];
250          int    argListLen = 0;
251          int    i, retVal;
252         tRequestHeader  *ret;
253          int    retValueCount = 1;
254          int    retDataLen = sizeof(Uint64);
255         void    *returnData[Request->NParams];
256          int    argSizes[Request->NParams];
257         Uint    ret_errno = 0;
258         
259         // Sanity check
260         if( Request->CallID >= ciNumSyscalls ) {
261                 Log_Notice("Syscalls", "Unknown syscall number %i", Request->CallID);
262                 return NULL;
263         }
264         
265         if( !caSyscalls[Request->CallID] ) {
266                 Log_Notice("Syscalls", "Unimplemented syscall %i", Request->CallID);
267                 return NULL;
268         }
269         
270         // Get size of argument list
271         for( i = 0; i < Request->NParams; i ++ )
272         {
273                 argSizes[i] = Request->Params[i].Length;
274                 switch(Request->Params[i].Type)
275                 {
276                 case ARG_TYPE_VOID:
277                         formatString[i] = '-';
278                         break;
279                 case ARG_TYPE_INT32:
280                         formatString[i] = 'i';
281                         argListLen += sizeof(Uint32);
282                         break;
283                 case ARG_TYPE_INT64:
284                         formatString[i] = 'I';
285                         argListLen += sizeof(Uint64);
286                         break;
287                 case ARG_TYPE_DATA:
288                         formatString[i] = 'd';
289                         argListLen += sizeof(void*);
290                         break;
291                 case ARG_TYPE_STRING:
292                         formatString[i] = 's';
293                         argListLen += sizeof(char*);
294                         break;
295                 default:
296                         return NULL;    // ERROR!
297                 }
298         }
299         formatString[i] = '\0';
300         
301         //LOG("Request %i(%s) '%s'", Request->CallID, casSYSCALL_NAMES[Request->CallID], formatString);
302         
303         {
304                 char    argListData[argListLen];
305                 argListLen = 0;
306                 // Build argument list
307                 for( i = 0; i < Request->NParams; i ++ )
308                 {
309                         returnData[i] = NULL;
310                         switch(Request->Params[i].Type)
311                         {
312                         case ARG_TYPE_VOID:
313                                 break;
314                         case ARG_TYPE_INT32:
315                                 //LOG("%i INT32: 0x%x", i, *(Uint32*)inData);
316                                 *(Uint32*)&argListData[argListLen] = *(Uint32*)inData;
317                                 argListLen += sizeof(Uint32);
318                                 inData += sizeof(Uint32);
319                                 break;
320                         case ARG_TYPE_INT64:
321                                 //LOG("%i INT64: 0x%llx", i, *(Uint64*)inData);
322                                 *(Uint64*)&argListData[argListLen] = *(Uint64*)inData;
323                                 argListLen += sizeof(Uint64);
324                                 inData += sizeof(Uint64);
325                                 break;
326                         case ARG_TYPE_STRING:
327                                 //LOG("%i STR: '%s'", i, (char*)inData);
328                                 *(char**)&argListData[argListLen] = (char*)inData;
329                                 argListLen += sizeof(void*);
330                                 inData += Request->Params[i].Length;
331                                 break;
332                         
333                         // Data gets special handling, because only it can be returned to the user
334                         // (ARG_TYPE_DATA is a pointer)
335                         case ARG_TYPE_DATA:
336                                 // Prepare the return values
337                                 if( Request->Params[i].Flags & ARG_FLAG_RETURN )
338                                 {
339                                         retDataLen += Request->Params[i].Length;
340                                         retValueCount ++;
341                                 }
342                                 
343                                 // Check for non-resident data
344                                 if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
345                                 {
346                                         // Allocate and zero the buffer
347                                         returnData[i] = calloc(1, Request->Params[i].Length);
348                                         //LOG("%i ZDAT: %i %p", i,
349                                         //      Request->Params[i].Length, returnData[i]);
350                                         *(void**)&argListData[argListLen] = returnData[i];
351                                         argListLen += sizeof(void*);
352                                 }
353                                 else
354                                 {
355                                         returnData[i] = (void*)inData;
356                                         //LOG("%i DATA: %i %p", i,
357                                         //      Request->Params[i].Length, returnData[i]);
358                                         *(void**)&argListData[argListLen] = (void*)inData;
359                                         argListLen += sizeof(void*);
360                                         inData += Request->Params[i].Length;
361                                 }
362                                 break;
363                         }
364                 }
365                 
366                 retVal = caSyscalls[Request->CallID](&ret_errno, formatString, argListData, argSizes);
367         }
368         
369         // Allocate the return
370         ret = malloc(sizeof(tRequestHeader) + retValueCount * sizeof(tRequestValue)
371                 + retDataLen);
372         ret->ClientID = Request->ClientID;
373         ret->CallID = Request->CallID;
374         ret->NParams = retValueCount;
375         inData = (char*)&ret->Params[ ret->NParams ];
376         
377         // Static Uint64 return value
378         ret->Params[0].Type = ARG_TYPE_INT64;
379         ret->Params[0].Flags = 0;
380         ret->Params[0].Length = sizeof(Uint64);
381         *(Uint64*)inData = retVal;
382         inData += sizeof(Uint64);
383         
384         Log_Debug("Syscalls", "Return 0x%llx", retVal);
385         
386         retValueCount = 1;
387         for( i = 0; i < Request->NParams; i ++ )
388         {
389                 if( Request->Params[i].Type != ARG_TYPE_DATA )  continue;
390                 if( !(Request->Params[i].Flags & ARG_FLAG_RETURN) )     continue;
391                 
392                 ret->Params[retValueCount].Type = Request->Params[i].Type;
393                 ret->Params[retValueCount].Flags = 0;
394                 ret->Params[retValueCount].Length = Request->Params[i].Length;
395                 
396                 LOG("Ret %i: Type %i, Len %i",
397                         i, Request->Params[i].Type, Request->Params[i].Length);
398                 
399                 memcpy(inData, returnData[i], Request->Params[i].Length);
400                 inData += Request->Params[i].Length;
401                 
402                 if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
403                         free( returnData[i] );  // Free temp buffer from above
404                 retValueCount ++;
405         }
406         
407         *ReturnLength = sizeof(tRequestHeader)
408                 + retValueCount * sizeof(tRequestValue)
409                 + retDataLen;
410         
411         return ret;
412 }

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