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

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