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

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