85a82325a5d11a9702c605095380c89d61ef9674
[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);
12
13 // === MACROS ===
14 #define SYSCALL3(_name, _call, _fmtstr, _t1, _t2, _t3) int _name(const char *fmt,void*args){\
15         _t1 a1;_t2 a2;_t3 a3;\
16         if(strcmp(fmt,_fmtstr)!=0)return 0;\
17         a1 = *(_t1*)args;args+=sizeof(_t1);\
18         a2 = *(_t2*)args;args+=sizeof(_t2);\
19         a3 = *(_t3*)args;args+=sizeof(_t3);\
20         return _call(a1,a2,a3);\
21 }
22
23 #define SYSCALL2(_name, _call, _fmtstr, _t1, _t2) int _name(const char *fmt,void*args){\
24         _t1 a1;_t2 a2;\
25         if(strcmp(fmt,_fmtstr)!=0)return 0;\
26         a1 = *(_t1*)args;args+=sizeof(_t1);\
27         a2 = *(_t2*)args;args+=sizeof(_t2);\
28         return _call(a1,a2);\
29 }
30
31 #define SYSCALL1V(_name, _call, _fmtstr, _t1) int _name(const char *fmt, void*args){\
32         _t1 a1;\
33         if(strcmp(fmt,_fmtstr)!=0)return 0;\
34         a1 = *(_t1*)args;args+=sizeof(_t1);\
35         _call(a1);\
36         return 0;\
37 }
38
39 // === CODE ===
40 int Syscall_Null(const char *Format, void *Args)
41 {
42         return 0;
43 }
44
45 SYSCALL2(Syscall_Open, VFS_Open, "si", const char *, int);
46 SYSCALL1V(Syscall_Close, VFS_Close, "i", int);
47 SYSCALL3(Syscall_Read, VFS_Read, "iid", int, int, void *);
48 SYSCALL3(Syscall_Write, VFS_Write, "iid", int, int, const void *);
49
50
51 const tSyscallHandler   caSyscalls[] = {
52         Syscall_Null,
53         Syscall_Open,
54         Syscall_Close,
55         Syscall_Read,
56         Syscall_Write
57 };
58 const int       ciNumSyscalls = sizeof(caSyscalls)/sizeof(caSyscalls[0]);
59 /**
60  * \brief Recieve a syscall structure from the server code
61  */
62 tRequestHeader *SyscallRecieve(tRequestHeader *Request, int *ReturnLength)
63 {
64         char    formatString[Request->NParams+1];
65         char    *inData = (char*)&Request->Params[Request->NParams];
66          int    argListLen = 0;
67          int    i, retVal;
68         tRequestHeader  *ret;
69          int    retValueCount = 1;
70          int    retDataLen = sizeof(Uint64);
71         void    *mallocdData[Request->NParams];
72         
73         // Sanity check
74         if( Request->CallID > ciNumSyscalls ) {
75                 return NULL;
76         }
77         
78         // Get size of argument list
79         for( i = 0; i < Request->NParams; i ++ )
80         {
81                 switch(Request->Params[i].Type)
82                 {
83                 case ARG_TYPE_VOID:
84                         formatString[i] = '-';
85                         break;
86                 case ARG_TYPE_INT32:
87                         formatString[i] = 'i';
88                         argListLen += sizeof(Uint32);
89                         break;
90                 case ARG_TYPE_INT64:
91                         formatString[i] = 'I';
92                         argListLen += sizeof(Uint64);
93                         break;
94                 case ARG_TYPE_DATA:
95                         formatString[i] = 'd';
96                         argListLen += sizeof(void*);
97                         break;
98                 case ARG_TYPE_STRING:
99                         formatString[i] = 's';
100                         argListLen += sizeof(char*);
101                         break;
102                 default:
103                         return NULL;    // ERROR!
104                 }
105         }
106         
107         {
108                 char    argListData[argListLen];
109                 argListLen = 0;
110                 // Build argument list
111                 for( i = 0; i < Request->NParams; i ++ )
112                 {
113                         switch(Request->Params[i].Type)
114                         {
115                         case ARG_TYPE_VOID:
116                                 break;
117                         case ARG_TYPE_INT32:
118                                 *(Uint32*)&argListData[argListLen] = *(Uint32*)inData;
119                                 argListLen += sizeof(Uint32);
120                                 inData += sizeof(Uint32);
121                                 break;
122                         case ARG_TYPE_INT64:
123                                 *(Uint64*)&argListData[argListLen] = *(Uint64*)inData;
124                                 argListLen += sizeof(Uint64);
125                                 inData += sizeof(Uint64);
126                                 break;
127                         case ARG_TYPE_STRING:
128                                 *(void**)&argListData[argListLen] = *(void**)inData;
129                                 argListLen += sizeof(void*);
130                                 inData += Request->Params[i].Length;
131                                 break;
132                         
133                         // Data gets special handling, because only it can be returned to the user
134                         // (ARG_TYPE_DATA is a pointer)
135                         case ARG_TYPE_DATA:
136                                 // Prepare the return values
137                                 if( Request->Params[i].Flags & ARG_FLAG_RETURN )
138                                 {
139                                         retDataLen += Request->Params[i].Length;
140                                         retValueCount ++;
141                                 }
142                                 
143                                 // Check for non-resident data
144                                 if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
145                                 {
146                                         // Allocate and zero the buffer
147                                         mallocdData[i] = calloc(1, Request->Params[i].Length);
148                                         *(void**)&argListData[argListLen] = mallocdData[i];
149                                         argListLen += sizeof(void*);
150                                 }
151                                 else
152                                 {
153                                         *(void**)&argListData[argListLen] = (void*)inData;
154                                         argListLen += sizeof(void*);
155                                         inData += Request->Params[i].Length;
156                                 }
157                                 break;
158                         }
159                 }
160                 
161                 retVal = caSyscalls[Request->CallID](formatString, argListData);
162         }
163         
164         // Allocate the return
165         ret = malloc(sizeof(tRequestHeader) + retValueCount * sizeof(tRequestValue)
166                 + retDataLen);
167         ret->ClientID = Request->ClientID;
168         ret->CallID = Request->CallID;
169         ret->NParams = retValueCount;
170         inData = &ret->Params[ ret->NParams ];
171         
172         // Static Uint64 return value
173         ret->Params[0].Type = ARG_TYPE_INT64;
174         ret->Params[0].Flags = 0;
175         ret->Params[0].Length = sizeof(Uint64);
176         *(Uint64*)inData = retVal;
177         inData += sizeof(Uint64);
178         
179         for( i = 0; i < Request->NParams; i ++ )
180         {
181                 if( Request->Params[i].Type != ARG_TYPE_DATA )  continue;
182                 if( !(Request->Params[i].Flags & ARG_FLAG_RETURN) )     continue;
183                 
184                 ret->Params[1 + i].Type = Request->Params[i].Type;
185                 ret->Params[1 + i].Flags = 0;
186                 ret->Params[1 + i].Length = Request->Params[i].Length;
187                 
188                 memcpy(inData, mallocdData[i], Request->Params[i].Length);
189                 inData += Request->Params[i].Length;
190                 
191                 free( mallocdData[i] ); // Free temp buffer from above
192         }
193         
194         return ret;
195 }

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