eb9d8a2d079f976fd6dae48a4bc5d99763d2136f
[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 "../syscalls.h"
9
10 // === TYPES ===
11 typedef int     (*tSyscallHandler)(const char *Format, void *Args, int *Sizes);
12
13 // === MACROS ===
14 #define SYSCALL3(_name, _fmtstr, _t0, _t1, _t2, _call) int _name(const char*Fmt,void*Args,int*Sizes){\
15         _t0 a0;_t1 a1;_t2 a2;\
16         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
17         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
18         a1 = *(_t1*)Args;Args+=sizeof(_t1);\
19         a2 = *(_t2*)Args;Args+=sizeof(_t2);\
20         _call\
21 }
22
23 #define SYSCALL2(_name, _fmtstr, _t0, _t1, _call) int _name(const char*Fmt,void*Args,int*Sizes){\
24         _t0 a0;_t1 a1;\
25         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
26         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
27         a1 = *(_t1*)Args;Args+=sizeof(_t1);\
28         _call;\
29 }
30
31 #define SYSCALL1(_name, _fmtstr, _t0, _call) int _name(const char*Fmt, void*Args,int*Sizes){\
32         _t0 a0;\
33         if(strcmp(Fmt,_fmtstr)!=0)return 0;\
34         a0 = *(_t0*)Args;Args+=sizeof(_t0);\
35         _call;\
36 }
37
38 // === CODE ===
39 int Syscall_Null(const char *Format, void *Args, int *Sizes)
40 {
41         return 0;
42 }
43
44 SYSCALL2(Syscall_Open, "si", const char *, int,
45         return VFS_Open(a0, a1|VFS_OPENFLAG_USER);
46 );
47 SYSCALL1(Syscall_Close, "i", int,
48         VFS_Close(a0);
49         return 0;
50 );
51 SYSCALL3(Syscall_Read, "iid", int, int, void *,
52         if( Sizes[2] <= a1 )
53                 return -1;
54         return VFS_Read(a0, a1, a2);
55 );
56 SYSCALL3(Syscall_Write, "iid", int, int, const void *,
57         if( Sizes[2] <= a1 )
58                 return -1;
59         return VFS_Write(a0, a1, a2);
60 );
61 SYSCALL3(Syscall_Seek, "iIi", int, int64_t, int,
62         return VFS_Seek(a0, a1, a2);
63 );
64 SYSCALL1(Syscall_Tell, "i", int,
65         return VFS_Tell(a0);
66 );
67 SYSCALL3(Syscall_IOCtl, "iid", int, int, void *,
68         return VFS_IOCtl(a0, a1, a2);
69 );
70 SYSCALL3(Syscall_FInfo, "idi", int, void *, int,
71         if( Sizes[1] < sizeof(tFInfo)+a2*sizeof(tVFS_ACL))
72                 return -1;
73         return VFS_FInfo(a0, a1, a2);
74 );
75
76
77 const tSyscallHandler   caSyscalls[] = {
78         Syscall_Null,
79         Syscall_Open,
80         Syscall_Close,
81         Syscall_Read,
82         Syscall_Write,
83         Syscall_Seek,
84         Syscall_Tell,
85         Syscall_IOCtl,
86         Syscall_FInfo
87 };
88 const int       ciNumSyscalls = sizeof(caSyscalls)/sizeof(caSyscalls[0]);
89 /**
90  * \brief Recieve a syscall structure from the server code
91  */
92 tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength)
93 {
94         char    formatString[Request->NParams+1];
95         char    *inData = (char*)&Request->Params[Request->NParams];
96          int    argListLen = 0;
97          int    i, retVal;
98         tRequestHeader  *ret;
99          int    retValueCount = 1;
100          int    retDataLen = sizeof(Uint64);
101         void    *returnData[Request->NParams];
102          int    argSizes[Request->NParams];
103         
104         // Sanity check
105         if( Request->CallID >= ciNumSyscalls ) {
106                 Log_Notice("Syscalls", "Unknown syscall number %i", Request->CallID);
107                 return NULL;
108         }
109         
110         // Get size of argument list
111         for( i = 0; i < Request->NParams; i ++ )
112         {
113                 argSizes[i] = Request->Params[i].Length;
114                 switch(Request->Params[i].Type)
115                 {
116                 case ARG_TYPE_VOID:
117                         formatString[i] = '-';
118                         break;
119                 case ARG_TYPE_INT32:
120                         formatString[i] = 'i';
121                         argListLen += sizeof(Uint32);
122                         break;
123                 case ARG_TYPE_INT64:
124                         formatString[i] = 'I';
125                         argListLen += sizeof(Uint64);
126                         break;
127                 case ARG_TYPE_DATA:
128                         formatString[i] = 'd';
129                         argListLen += sizeof(void*);
130                         break;
131                 case ARG_TYPE_STRING:
132                         formatString[i] = 's';
133                         argListLen += sizeof(char*);
134                         break;
135                 default:
136                         return NULL;    // ERROR!
137                 }
138         }
139         formatString[i] = '\0';
140         
141         Log_Debug("Syscalls", "Request %i '%s'", Request->CallID, formatString);
142         
143         {
144                 char    argListData[argListLen];
145                 argListLen = 0;
146                 // Build argument list
147                 for( i = 0; i < Request->NParams; i ++ )
148                 {
149                         returnData[i] = NULL;
150                         switch(Request->Params[i].Type)
151                         {
152                         case ARG_TYPE_VOID:
153                                 break;
154                         case ARG_TYPE_INT32:
155                                 Log_Debug("Syscalls", "Arg %i: 0x%x", i, *(Uint32*)inData);
156                                 *(Uint32*)&argListData[argListLen] = *(Uint32*)inData;
157                                 argListLen += sizeof(Uint32);
158                                 inData += sizeof(Uint32);
159                                 break;
160                         case ARG_TYPE_INT64:
161                                 Log_Debug("Syscalls", "Arg %i: 0x%llx", i, *(Uint64*)inData);
162                                 *(Uint64*)&argListData[argListLen] = *(Uint64*)inData;
163                                 argListLen += sizeof(Uint64);
164                                 inData += sizeof(Uint64);
165                                 break;
166                         case ARG_TYPE_STRING:
167                                 Log_Debug("Syscalls", "Arg %i: '%s'", i, (char*)inData);
168                                 *(char**)&argListData[argListLen] = (char*)inData;
169                                 argListLen += sizeof(void*);
170                                 inData += Request->Params[i].Length;
171                                 break;
172                         
173                         // Data gets special handling, because only it can be returned to the user
174                         // (ARG_TYPE_DATA is a pointer)
175                         case ARG_TYPE_DATA:
176                                 // Prepare the return values
177                                 if( Request->Params[i].Flags & ARG_FLAG_RETURN )
178                                 {
179                                         retDataLen += Request->Params[i].Length;
180                                         retValueCount ++;
181                                 }
182                                 
183                                 // Check for non-resident data
184                                 if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
185                                 {
186                                         // Allocate and zero the buffer
187                                         returnData[i] = calloc(1, Request->Params[i].Length);
188                                         Log_Debug("Syscalls", "Arg %i: %i %p", i,
189                                                 Request->Params[i].Length, returnData[i]);
190                                         *(void**)&argListData[argListLen] = returnData[i];
191                                         argListLen += sizeof(void*);
192                                 }
193                                 else
194                                 {
195                                         returnData[i] = (void*)inData;
196                                         Log_Debug("Syscalls", "Arg %i: %i %p", i,
197                                                 Request->Params[i].Length, returnData[i]);
198                                         *(void**)&argListData[argListLen] = (void*)inData;
199                                         argListLen += sizeof(void*);
200                                         inData += Request->Params[i].Length;
201                                 }
202                                 break;
203                         }
204                 }
205                 
206                 retVal = caSyscalls[Request->CallID](formatString, argListData, argSizes);
207         }
208         
209         // Allocate the return
210         ret = malloc(sizeof(tRequestHeader) + retValueCount * sizeof(tRequestValue)
211                 + retDataLen);
212         ret->ClientID = Request->ClientID;
213         ret->CallID = Request->CallID;
214         ret->NParams = retValueCount;
215         inData = (char*)&ret->Params[ ret->NParams ];
216         
217         // Static Uint64 return value
218         ret->Params[0].Type = ARG_TYPE_INT64;
219         ret->Params[0].Flags = 0;
220         ret->Params[0].Length = sizeof(Uint64);
221         *(Uint64*)inData = retVal;
222         inData += sizeof(Uint64);
223         
224         Log_Debug("Syscalls", "Return 0x%llx", retVal);
225         
226         for( i = 0; i < Request->NParams; i ++ )
227         {
228                 if( Request->Params[i].Type != ARG_TYPE_DATA )  continue;
229                 if( !(Request->Params[i].Flags & ARG_FLAG_RETURN) )     continue;
230                 
231                 ret->Params[1 + i].Type = Request->Params[i].Type;
232                 ret->Params[1 + i].Flags = 0;
233                 ret->Params[1 + i].Length = Request->Params[i].Length;
234                 
235                 memcpy(inData, returnData[i], Request->Params[i].Length);
236                 inData += Request->Params[i].Length;
237                 
238                 if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
239                         free( returnData[i] );  // Free temp buffer from above
240         }
241         
242         *ReturnLength = sizeof(tRequestHeader)
243                 + retValueCount * sizeof(tRequestValue)
244                 + retDataLen;
245         
246         return ret;
247 }

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