Implementing telnet server, fixes everywhere
[tpg/acess2.git] / Kernel / syscalls.c
1 /*
2  * AcessOS Microkernel Version
3  * syscalls.c
4  */
5 #define DEBUG   0
6
7 #include <acess.h>
8 #include <syscalls.h>
9 #include <proc.h>
10 #include <hal_proc.h>
11 #include <errno.h>
12 #include <threads.h>
13 #include <events.h>
14
15 #define CHECK_NUM_NULLOK(v,size)        \
16         if((v)&&!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
17 #define CHECK_STR_NULLOK(v)     \
18         if((v)&&!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
19 #define CHECK_NUM_NONULL(v,size)        \
20         if(!(v)||!Syscall_Valid((size),(v))){ret=-1;err=-EINVAL;break;}
21 #define CHECK_STR_NONULL(v)     \
22         if(!(v)||!Syscall_ValidString((v))){ret=-1;err=-EINVAL;break;}
23 #define CHECK_STR_ARRAY(arr)    do {\
24          int    i;\
25         char    **tmp = (char**)arr; \
26         CHECK_NUM_NONULL( tmp, sizeof(char**) ); \
27         for(i=0;tmp[i];i++) { \
28                 CHECK_STR_NONULL( tmp[i] ); \
29                 CHECK_NUM_NONULL( &tmp[i+1], sizeof(char*) ); \
30         }\
31         if(tmp[i]) break;\
32 } while(0)
33
34 // === IMPORTS ===
35 extern Uint     Binary_Load(const char *file, Uint *entryPoint);
36
37 // === PROTOTYPES ===
38 void    SyscallHandler(tSyscallRegs *Regs);
39  int    Syscall_ValidString(const char *Addr);
40  int    Syscall_Valid(int Size, const void *Addr);
41
42 // === CODE ===
43 // TODO: Do sanity checking on arguments, ATM the user can really fuck with the kernel
44 void SyscallHandler(tSyscallRegs *Regs)
45 {
46         Uint64  ret = 0;
47         Uint    err = -EOK;
48          int    callNum = Regs->Num;
49         
50         #if DEBUG < 2
51         if(callNum != SYS_READ && callNum != SYS_WRITE) {
52         #endif
53         ENTER("iThread iNum", Threads_GetTID(), callNum);
54         if(callNum < NUM_SYSCALLS)
55                 LOG("Syscall %s", cSYSCALL_NAMES[callNum]);
56         LOG("Arg1: 0x%x, Arg2: 0x%x, Arg3: 0x%x, Arg4: 0x%x", Regs->Arg1, Regs->Arg2, Regs->Arg3, Regs->Arg4);
57         #if DEBUG < 2
58         }
59         #endif
60         
61         switch(Regs->Num)
62         {
63         // -- Exit the current thread
64         case SYS_EXIT:  Threads_Exit(0, Regs->Arg1);    break;
65         
66         // -- Put the current thread to sleep
67         case SYS_SLEEP: Threads_Sleep();        break;
68         
69         // -- Yield current timeslice
70         case SYS_YIELD: Threads_Yield();        break;
71         
72         // -- Set Error Handler
73         case SYS_SETFAULTHANDLER:
74                 Threads_SetFaultHandler(Regs->Arg1);
75                 break;
76         
77         // -- Clone the current thread
78         case SYS_CLONE:
79                 // Call clone system call
80                 ret = Proc_Clone(Regs->Arg1);
81                 break;
82         
83         // -- Send a signal
84         case SYS_KILL:
85                 err = -ENOSYS;
86                 ret = -1;
87                 break;
88
89         // -- Wait fr an event  
90         case SYS_WAITEVENT:
91                 // Message mask
92                 ret = Threads_WaitEvents(Regs->Arg1);
93                 break;
94
95         // -- Wait for a thread
96         case SYS_WAITTID:
97                 // Sanity Check (Status can be NULL)
98                 CHECK_NUM_NULLOK( (int*)Regs->Arg2, sizeof(int) );
99                 // TID, *Status
100                 ret = Threads_WaitTID(Regs->Arg1, (int*)Regs->Arg2);
101                 break;
102         
103         // -- Get the physical address of a page
104         case SYS_GETPHYS:
105                 ret = MM_GetPhysAddr(Regs->Arg1);
106                 break;
107         
108         // -- Map an address
109         case SYS_MAP:   MM_Map(Regs->Arg1, Regs->Arg2); break;
110         
111         // -- Allocate an address
112         case SYS_ALLOCATE:      ret = MM_Allocate(Regs->Arg1);  break;
113         
114         // -- Unmap an address
115         case SYS_UNMAP:         MM_Deallocate(Regs->Arg1);      break;
116         
117         // -- Get Thread/Process IDs
118         case SYS_GETTID:        ret = Threads_GetTID(); break;
119         case SYS_GETPID:        ret = Threads_GetPID(); break;
120         
121         // -- Get User/Group IDs
122         case SYS_GETUID:        ret = Threads_GetUID(); break;
123         case SYS_GETGID:        ret = Threads_GetGID(); break;
124         
125         // -- Set User/Group IDs
126         case SYS_SETUID:        ret = Threads_SetUID(Regs->Arg1);       break;
127         case SYS_SETGID:        ret = Threads_SetGID(Regs->Arg1);       break;
128         
129         // -- Send Message
130         case SYS_SENDMSG:
131                 CHECK_NUM_NONULL( (void*)Regs->Arg3, Regs->Arg2 );
132                 // Destination, Size, *Data
133                 ret = Proc_SendMessage(Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3);
134                 break;
135         // -- Check for messages
136         case SYS_GETMSG:
137                 CHECK_NUM_NULLOK( (Uint*)Regs->Arg1, sizeof(Uint) );
138                 // NOTE: Can't do range checking as we don't know the size
139                 // - Should be done by Proc_GetMessage
140                 if( Regs->Arg2 && Regs->Arg2 != -1 && !MM_IsUser(Regs->Arg2) ) {
141                         err = -EINVAL;  ret = -1;       break;
142                 }
143                 // *Source, *Data
144                 ret = Proc_GetMessage((Uint*)Regs->Arg1, (void*)Regs->Arg2);
145                 break;
146         
147         // -- Get the current timestamp
148         case SYS_GETTIME:
149                 ret = now();
150                 break;
151         
152         // -- Set the thread's name
153         case SYS_SETNAME:
154                 CHECK_STR_NONULL( (char*) Regs->Arg1);
155                 Threads_SetName( (char*)Regs->Arg1 );
156                 break;
157         
158         // ---
159         // Binary Control
160         // ---
161         // -- Create a new process
162         case SYS_SPAWN:
163                 CHECK_STR_NONULL((const char*)Regs->Arg1);
164                 CHECK_STR_ARRAY((const char**)Regs->Arg2);
165                 CHECK_STR_ARRAY((const char**)Regs->Arg3);
166                 CHECK_NUM_NONULL((void*)Regs->Arg5, Regs->Arg4*sizeof(int));
167                 ret = Proc_SysSpawn(
168                         (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
169                         Regs->Arg4, (int*)Regs->Arg5
170                         );
171                 break;
172         // -- Replace the current process with another
173         case SYS_EXECVE:
174                 CHECK_STR_NONULL((char*)Regs->Arg1);
175                 CHECK_STR_ARRAY( (char**)Regs->Arg2 );
176                 if( Regs->Arg3 )
177                         CHECK_STR_ARRAY( (char**)Regs->Arg3 );
178                 LEAVE('s', "Assuming 0");
179                 // Path, **Argv, **Envp, DataSize (=0 to tell it to create a copy)
180                 ret = Proc_Execve(
181                         (const char*)Regs->Arg1, (const char**)Regs->Arg2, (const char**)Regs->Arg3,
182                         0
183                         );
184                 break;
185         // -- Load a binary into the current process
186         case SYS_LOADBIN:
187                 CHECK_STR_NONULL( (char*)Regs->Arg1 );
188                 CHECK_NUM_NONULL( (Uint*)Regs->Arg2, sizeof(Uint) );
189                 // Path, *Entrypoint
190                 ret = Binary_Load((char*)Regs->Arg1, (Uint*)Regs->Arg2);
191                 break;
192         
193         // ---
194         // Virtual Filesystem
195         // ---
196         case SYS_OPEN:
197                 CHECK_STR_NONULL( (char*)Regs->Arg1 );
198                 LOG("VFS_Open(\"%s\", 0x%x)", (char*)Regs->Arg1, Regs->Arg2 | VFS_OPENFLAG_USER);
199                 ret = VFS_Open((char*)Regs->Arg1, Regs->Arg2 | VFS_OPENFLAG_USER);
200                 break;
201         
202         case SYS_CLOSE:
203                 LOG("VFS_Close(%i)", Regs->Arg1);
204                 VFS_Close( Regs->Arg1 );
205                 break;
206         
207         case SYS_SEEK:
208                 #if BITS == 64
209                 ret = VFS_Seek( Regs->Arg1, Regs->Arg2, Regs->Arg3 );
210                 #else
211                 ret = VFS_Seek( Regs->Arg1, Regs->Arg2|(((Uint64)Regs->Arg3)<<32), Regs->Arg4 );
212                 #endif
213                 break;
214                 
215         case SYS_TELL:
216                 ret = VFS_Tell( Regs->Arg1 );
217                 break;
218         
219         case SYS_WRITE:
220                 CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 );
221                 ret = VFS_Write( Regs->Arg1, Regs->Arg3, (void*)Regs->Arg2 );
222                 break;
223         
224         case SYS_READ:
225                 CHECK_NUM_NONULL( (void*)Regs->Arg2, Regs->Arg3 );
226                 ret = VFS_Read( Regs->Arg1, Regs->Arg3, (void*)Regs->Arg2 );
227                 break;
228         
229         case SYS_FINFO:
230                 CHECK_NUM_NONULL( (void*)Regs->Arg2, sizeof(tFInfo) + Regs->Arg3*sizeof(tVFS_ACL) );
231                 // FP, Dest, MaxACLs
232                 ret = VFS_FInfo( Regs->Arg1, (void*)Regs->Arg2, Regs->Arg3 );
233                 break;
234         
235         // Get ACL Value
236         case SYS_GETACL:
237                 CHECK_NUM_NONULL( (void*)Regs->Arg2, sizeof(tVFS_ACL) );
238                 ret = VFS_GetACL( Regs->Arg1, (void*)Regs->Arg2 );
239                 break;
240         
241         // Read Directory
242         case SYS_READDIR:
243                 // TODO: What if the filename is longer?
244                 // Maybe force it to be a 256 byte buffer
245                 CHECK_NUM_NONULL( (void*)Regs->Arg2, 256 );
246                 ret = VFS_ReadDir( Regs->Arg1, (void*)Regs->Arg2 );
247                 break;
248         
249         // Open a file that is a entry in an open directory
250         case SYS_OPENCHILD:
251                 CHECK_STR_NONULL( (char*)Regs->Arg2 );
252                 ret = VFS_OpenChild( Regs->Arg1, (char*)Regs->Arg2, Regs->Arg3 | VFS_OPENFLAG_USER);
253                 break;
254         
255         // Change Directory
256         case SYS_CHDIR:
257                 CHECK_STR_NONULL( (const char*)Regs->Arg1 );
258                 ret = VFS_ChDir( (const char*)Regs->Arg1 );
259                 break;
260         
261         // IO Control
262         case SYS_IOCTL:
263                 // All sanity checking should be done by the driver
264                 if( Regs->Arg3 && !MM_IsUser(Regs->Arg3) ) {
265                         err = -EINVAL;  ret = -1;       break;
266                 }
267                 ret = VFS_IOCtl( Regs->Arg1, Regs->Arg2, (void*)Regs->Arg3 );
268                 break;
269         
270         // Mount a filesystem
271         case SYS_MOUNT:
272                 // Only root can mount filesystems
273                 if(Threads_GetUID() != 0) {
274                         err = -EACCES;
275                         ret = -1;
276                         break;
277                 }
278                 // Sanity check the paths
279                 if(!Syscall_ValidString((char*)Regs->Arg1)
280                 || !Syscall_ValidString((char*)Regs->Arg2)
281                 || !Syscall_ValidString((char*)Regs->Arg3)
282                 || !Syscall_ValidString((char*)Regs->Arg4) ) {
283                         err = -EINVAL;
284                         ret = -1;
285                         break;
286                 }
287                 ret = VFS_Mount(
288                         (char*)Regs->Arg1,      // Device
289                         (char*)Regs->Arg2,      // Mount point
290                         (char*)Regs->Arg3,      // Filesystem
291                         (char*)Regs->Arg4       // Options
292                         );
293                 break;
294                 
295         // Wait on a set of handles
296         case SYS_SELECT:
297                 // Sanity checks
298                 if( (Regs->Arg2 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg2))
299                  || (Regs->Arg3 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg3))
300                  || (Regs->Arg4 && !Syscall_Valid(sizeof(fd_set), (void*)Regs->Arg4))
301                  || (Regs->Arg5 && !Syscall_Valid(sizeof(tTime), (void*)Regs->Arg5)) )
302                 {
303                         err = -EINVAL;
304                         ret = -1;
305                         break;
306                 }
307                 // Perform the call
308                 ret = VFS_Select(
309                         Regs->Arg1,     // Max handle
310                         (fd_set *)Regs->Arg2,   // Read
311                         (fd_set *)Regs->Arg3,   // Write
312                         (fd_set *)Regs->Arg4,   // Errors
313                         (tTime *)Regs->Arg5,    // Timeout
314                         (Uint32)Regs->Arg6,     // Extra wakeup events
315                         0       // User handles
316                         );
317                 break;
318         
319         // -- Debug
320         //#if DEBUG_BUILD
321         case SYS_DEBUG:
322                 CHECK_STR_NONULL( (char*)Regs->Arg1 );
323                 LogF("Log: %08lli [%i] ", now(), Threads_GetTID());
324                 LogF((const char*)Regs->Arg1,
325                         Regs->Arg2, Regs->Arg3, Regs->Arg4, Regs->Arg5, Regs->Arg6);
326                 LogF("\r\n");
327                 break;
328         //#endif
329         
330         // -- Default (Return Error)
331         default:
332                 Log_Warning("Syscalls", "Unknown System Call %i", Regs->Num);
333                 if(Regs->Num < NUM_SYSCALLS)
334                         Log_Warning("Syscall", " named '%s'", cSYSCALL_NAMES[Regs->Num]);
335                 err = -ENOSYS;
336                 ret = -1;
337                 break;
338         }
339
340         if(err == 0)    err = errno;
341         
342         if(err != 0) {
343                 LOG("ID: %i, Return errno = %i", Regs->Num, err);
344         }
345         
346         #if BITS < 64
347         Regs->Return = ret&0xFFFFFFFF;
348         Regs->RetHi = ret >> 32;
349         #else
350         Regs->Return = ret;
351         #endif
352         Regs->Error = err;
353         #if DEBUG
354         # if DEBUG < 2
355         if( callNum != SYS_READ && callNum != SYS_WRITE ) {
356         # endif
357         LOG("err = %i", err);
358         if( callNum == SYS_EXECVE )
359                 LOG("Actual %i", ret);
360         else
361                 LEAVE('x', ret);
362         # if DEBUG < 2
363         }
364         # endif
365         #endif
366 }
367
368 /**
369  * \fn int Syscall_ValidString(const char *Addr)
370  * \brief Checks if a memory address contains a valid string
371  */
372 int Syscall_ValidString(const char *Addr)
373 {
374         // Check if the memory is user memory
375         if(!MM_IsUser( (tVAddr) Addr))  return 0;
376         
377         return CheckString( Addr );
378 }
379
380 /**
381  * \fn int Syscall_Valid(int Size, const void *Addr)
382  * \brief Checks if a memory address is valid
383  */
384 int Syscall_Valid(int Size, const void *Addr)
385 {
386         if(!MM_IsUser( (tVAddr)Addr ))  return 0;
387         
388         return CheckMem( Addr, Size );
389 }

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