New developer version 0.6.8; added select () function; added demonstrating example...
[ZeXOS.git] / kernel / arch / i386 / syscall.c
blob7afe1de251fc83ada79e17e6ba7996a3a521b79a
1 /*
2 * ZeX/OS
3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
6 * Copyright (C) 2009 Martin 'povik' Poviser (martin.povik@gmail.com)
7 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <system.h>
25 #include <arch/io.h>
26 #include <string.h>
27 #include <tty.h>
28 #include <proc.h>
29 #include <net/socket.h>
30 #include <file.h>
31 #include <signal.h>
32 #include <module.h>
33 #include <rs232.h>
34 #include <ioctl.h>
35 #include <fd.h>
36 #include <paging.h>
37 #include <pipe.h>
38 #include <errno.h>
39 #include <sound/audio.h>
40 #include <select.h>
41 #include <syscall.h>
43 void sys_exit (struct regs *r)
45 task_t *taskc = task_find (0);
47 if (!taskc)
48 return;
50 page_dir_switch (taskc->page_cover->page_dir);
52 proc_t *proc = proc_find (_curr_task);
54 if (!proc)
55 return;
57 task_t *task = proc->tty->task;
59 proc->pid = 0;
61 if (int_disable ())
62 longjmp (task->state, 1);
63 else
64 for (;;)
65 schedule ();
68 void sys_getch (struct regs *r)
70 proc_t *proc = proc_find (_curr_task);
72 if (!proc)
73 return;
75 if (proc->tty != currtty)
76 return;
78 unsigned char c = (unsigned char) getkey ();
80 if (c)
81 setkey (0);
83 *SYSV_GETCH = (unsigned) c;
87 void sys_sleep (struct regs *r)
89 unsigned long timer_start = timer_ticks + ((unsigned) r->ebx * 1000);
91 while (timer_start > timer_ticks)
92 schedule ();
95 void sys_putch (struct regs *r)
97 //page_dir_switch (taskc->page_cover->page_dir);
99 proc_t *proc = proc_find (_curr_task);
101 if (!proc)
102 return;
104 int c = r->ebx;
106 tty_putnch (proc->tty, c);
108 //page_dir_switch (proc->task->page_cover->page_dir);
111 void sys_color (struct regs *r)
113 video_color (r->ebx, r->ecx);
117 void sys_cls (struct regs *r)
119 proc_t *proc = proc_find (_curr_task);
121 if (!proc)
122 return;
124 if (proc->tty != currtty)
125 return;
127 /* NOTE: Why we should disable interrupts ? Nobody know, but works better */
128 if (int_disable ()) {
129 tty_cls (proc->tty);
130 int_enable ();
134 void sys_getkey (struct regs *r)
136 proc_t *proc = proc_find (_curr_task);
138 if (!proc)
139 return;
141 if (proc->tty != currtty)
142 return;
144 *SYSV_GETKEY = (unsigned) scancode;
146 scancode = 0;
149 void sys_gotoxy (struct regs *r)
151 proc_t *proc = proc_find (_curr_task);
153 if (!proc)
154 return;
156 tty_gotoxy (proc->tty, r->ebx, r->ecx);
159 void sys_fork (struct regs *r)
161 *SYSV_FORK = fork ();
164 void sys_schedule (struct regs *r)
166 schedule ();
169 void sys_write (struct regs *r)
171 unsigned len = r->ecx;
172 unsigned fd = r->edx;
174 unsigned char *buf = (unsigned char *) r->ebx;
176 if (!buf)
177 return;
179 int ret = 0;
181 proc_t *proc = 0;
182 char *mem = 0;
184 switch (fd) {
185 case 0:
186 proc = proc_find (_curr_task);
188 if (!proc) {
189 ret = -1;
190 break;
193 mem = (char *) buf;
195 //printf ("data: %s | 0x%x | %d\n", mem, proc->data, len);
197 tty_write (proc->tty, (char *) mem, len);
199 ret = len;
201 break;
202 case 1:
203 proc = proc_find (_curr_task);
205 if (!proc) {
206 ret = -1;
207 break;
210 if (len > KBD_MAX_QUAUE)
211 len = KBD_MAX_QUAUE;
213 mem = (char *) buf;
215 int i = 0;
216 for (i = len; i >= 0; i --)
217 setkey (buf[i]);
219 //mem[len] = '\0';
221 ret = len;
222 break;
223 default:
224 mem = (char *) buf;
226 ret = write (fd, (char *) mem, len);
227 break;
230 *SYSV_WRITE = ret;
233 void sys_socket (struct regs *r)
235 *SYSV_SOCKET = socket (r->ebx, r->ecx, r->edx);
238 void sys_connect (struct regs *r)
240 sockaddr *addr = (sockaddr *) r->ebx;
242 *SYSV_CONNECT = connect (r->ecx, addr, r->edx);
245 void sys_malloc (struct regs *r)
247 proc_t *proc = proc_find (_curr_task);
249 paging_disable ();
250 r->eax = (unsigned) umalloc (proc, (int) r->ebx);
251 paging_enable ();
253 DPRINT (DBG_SYSCALL, "malloc (): 0x%x", r->eax);
256 void sys_send (struct regs *r)
258 *SYSV_SEND = send ((int) r->ecx, (char *) r->ebx, (unsigned) r->edx, 0);
261 void sys_recv (struct regs *r)
263 unsigned char *msg = (unsigned char *) r->ebx;
264 unsigned size = (unsigned) r->edx;
265 int fd = (int) r->ecx;
267 *SYSV_RECV = recv (fd, (char *) msg, size, 0);
270 void sys_close (struct regs *r)
272 close (r->ebx);
275 void sys_open (struct regs *r)
277 *SYSV_OPEN = open ((char *) r->ebx, (unsigned) r->ecx);
280 void sys_pcspk (struct regs *r)
282 dev_t *dev = dev_find ("/dev/pcspk");
284 if (dev)
285 dev->handler (DEV_ACT_PLAY, (unsigned) r->ebx);
288 void sys_usleep (struct regs *r)
290 //unsigned long timer_start = timer_ticks + ((unsigned) r->ebx);
292 //while (timer_start > timer_ticks)
293 // schedule ();
294 usleep ((unsigned) r->ebx);
297 void sys_read (struct regs *r)
299 unsigned fd = r->ecx;
300 unsigned len = r->edx;
302 unsigned char *buf = (unsigned char *) r->ebx;
304 int ret = 0;
306 proc_t *proc = 0;
308 switch (fd) {
309 case 0:
310 break;
311 case 1:
312 proc = proc_find (_curr_task);
314 if (!proc)
315 break;
317 //if (proc->tty != currtty)
318 // return;
320 ret = tty_read (proc->tty, (char *) buf, len);
321 break;
322 default:
323 ret = read (fd, (char *) buf, len);
324 break;
327 *SYSV_READ = ret;
330 void sys_time (struct regs *r)
332 time_t *memptr = (time_t *) SYSV_TIME;
334 tm *t = rtc_getcurrtime ();
336 if (t)
337 *memptr = (time_t) t->__tm_gmtoff;
340 void sys_system (struct regs *r)
342 proc_t *proc = proc_find (_curr_task);
344 if (!proc)
345 return;
347 task_t *oldtask = _curr_task;
349 unsigned char *cmd = (unsigned char *) r->ebx;
351 /*paging_disable ();
352 page_dir_switch (task->page_cover->page_dir);
353 paging_enable ();
355 _curr_task = task;
356 schedule ();*/
358 command_parser ((char *) cmd, strlen (cmd));
360 page_dir_switch (oldtask->page_cover->page_dir);
362 /* needed for correct scheduling (when you execute new process, _curr_task is tasj of current tty) */
363 _curr_task = oldtask;
365 schedule ();
369 void sys_chdir (struct regs *r)
371 char *dir = (unsigned char *) r->ebx;
373 *SYSV_CHDIR = vfs_cd (dir, strlen (dir)) ? 0 : -1;
376 void sys_getdir (struct regs *r)
378 r->eax = (unsigned) vfs_dirent ();
381 void sys_procarg (struct regs *r)
383 proc_t *proc = proc_find (_curr_task);
385 if (!proc)
386 return;
388 switch (r->ecx) {
389 case 0:
390 r->eax = (unsigned) proc->argv;
391 break;
392 case 1:
393 r->eax = (unsigned) proc->argc;
394 break;
395 default:
396 r->eax = 0;
400 void sys_signal (struct regs *r)
402 signal (r->ebx, (sighandler_t) r->ecx);
405 void sys_mount (struct regs *r)
407 partition_t *p = partition_find ((char *) r->ebx);
409 if (p) {
410 mount (p, "", (char *) r->ecx);
411 r->eax = 1;
412 } else
413 r->eax = 0;
416 void sys_kputs (struct regs *r)
418 int_disable ();
420 module_t *kmod = module_find (_curr_task);
422 if (!kmod)
423 return;
425 if (kmod->task != _curr_task)
426 return;
428 unsigned char *buf = (unsigned char *) r->ebx;
429 kprintf (buf);
431 //kprintf ("yeah, sys_kputs: '%s' '0x%x'\n", buf, buf);
433 int_enable ();
436 void sys_bind (struct regs *r)
438 *SYSV_BIND = bind (r->ecx, (sockaddr *) r->ebx, r->edx);
441 void sys_listen (struct regs *r)
443 *SYSV_LISTEN = listen (r->ebx, r->ecx);
446 void sys_accept (struct regs *r)
448 *SYSV_ACCEPT = accept (r->ecx, r->ebx, r->edx);
451 void sys_fcntl (struct regs *r)
453 *SYSV_FCNTL = fcntl (r->ebx, r->ecx, r->edx);
456 void sys_gvgafb (struct regs *r)
458 proc_t *proc = proc_find (_curr_task);
460 if (!proc)
461 return;
463 if (vgagui != 2) {
464 printf ("Please start this program in graphical VESA mode\n");
465 sys_exit (r);
466 return;
469 *SYSV_GVGAFB = (unsigned) init_vgafb ();
472 void sys_gcls (struct regs *r)
474 //gcls (r->ebx);
477 void sys_gfbswap (struct regs *r)
479 proc_t *proc = proc_find (_curr_task);
481 if (!proc)
482 return;
484 if (proc->tty == currtty)
485 video_gfx_fbswap ();
487 schedule ();
490 void sys_rs232read (struct regs *r)
492 *SYSV_RS232READ = (int) rs232_read ();
495 void sys_rs232write (struct regs *r)
497 rs232_write ((char) r->ebx);
500 void sys_gttyexit (struct regs *r)
502 proc_t *proc = proc_find (_curr_task);
504 if (!proc)
505 return;
507 tty_change (proc->tty);
510 void sys_gexit (struct regs *r)
512 video_gfx_exit ();
515 void sys_gttyinit (struct regs *r)
517 tty_t *tty = gtty_init ();
519 if (!tty)
520 return;
522 r->eax = (unsigned) &tty->screen;
525 void sys_getenv (struct regs *r)
527 char *name = (char *) r->ebx;
529 char *val = (char *) env_get (name);
531 r->eax = (unsigned) val;
534 void sys_free (struct regs *r)
536 proc_t *proc = proc_find (_curr_task);
538 paging_disable ();
540 ufree (proc, (void *) r->ebx);
542 DPRINT (DBG_SYSCALL, "free (): 0x%x", r->ebx);
544 paging_enable ();
547 void sys_realloc (struct regs *r)
549 proc_t *proc = proc_find (_curr_task);
551 paging_disable ();
553 r->eax = (unsigned) urealloc (proc, (void *) r->ebx, (size_t) r->ecx);
555 DPRINT (DBG_SYSCALL, "realloc (): 0x%x", r->eax);
557 paging_enable ();
560 void sys_gethostbyname (struct regs *r)
562 char *buf = (char *) r->ebx;
564 if (!buf) {
565 r->eax = 0;
566 return;
569 r->eax = (unsigned) gethostbyname (buf);
572 void sys_vfsent (struct regs *r)
574 char *pathname = (char *) r->ebx;
576 r->eax = (unsigned) vfs_find (pathname, strlen (pathname));
579 void sys_sendto (struct regs *r)
581 /* HACK: bleeh, there is problem with fourth argument,
582 so we need to use another way to getting address */
583 sockaddr_in *to = (sockaddr_in *) *SYSV_SENDTO;
585 *SYSV_SENDTO = sendto ((int) r->ecx, (char *) r->ebx, (unsigned) r->edx, 0, to, 0);
588 void sys_recvfrom (struct regs *r)
590 unsigned char *msg = (unsigned char *) r->ebx;
592 /* HACK: bleeh, there is problem with fourth argument,
593 so we need to use another way to getting address */
594 sockaddr_in *from = (sockaddr_in *) *SYSV_RECVFROM;
596 *SYSV_RECVFROM = recvfrom ((int) r->ecx, (char *) msg, (unsigned) r->edx, 0, from, 0);
599 void sys_getchar (struct regs *r)
601 proc_t *proc = proc_find (_curr_task);
603 int i = 1;
604 unsigned char s = '\n';
606 int *memptr = SYSV_GETCHAR;
608 /* non-blocking mode */
609 if (stdin->flags & O_NONBLOCK) {
610 if (!proc)
611 return;
613 if (proc->tty != currtty)
614 return;
616 unsigned char c = getkey ();
618 if (!c) {
619 *memptr = -1;
620 return;
623 tty_putnch (proc->tty, c);
625 *memptr = c;
627 return;
630 /* blocking - clasical mode */
631 for (;;) {
632 if (!proc)
633 return;
635 if (proc->tty != currtty)
636 return;
638 char c = getkey ();
640 if (c) {
641 if (i > 0 && c != '\b')
642 tty_write (proc->tty, &c, 1);
644 if (c == '\n')
645 break;
646 else if (i == 1)
647 s = c;
649 if (c == '\b') {
650 if (i > 1) {
651 i --;
652 tty_write (proc->tty, "\b", 1);
654 } else
655 i ++;
659 *memptr = (int) s;
662 void sys_threadopen (struct regs *r)
664 void *ptr = (void *) r->ebx;
666 unsigned m = *SYSV_THREADOPEN;
668 *SYSV_THREADOPEN = proc_thread_create (ptr, (void *) m);
671 void sys_threadclose (struct regs *r)
673 proc_t *proc = proc_find (_curr_task);
675 if (!proc)
676 return;
678 task_t *task = _curr_task;
680 /* free child process thread */
681 *SYSV_THREADCLOSE = proc_thread_destroy (proc, task);
683 task = proc->tty->task;
685 if (int_disable ())
686 longjmp (task->state, 1);
687 else
688 for (;;)
689 schedule ();
692 void sys_ioctl (struct regs *r)
694 void *s = (void *) r->ebx;
695 unsigned id = r->ecx;
696 int l = r->edx;
698 *SYSV_IOCTL = ioctl_call (id, s, l);
701 void sys_getpid (struct regs *r)
703 proc_t *proc = proc_find (_curr_task);
705 if (!proc)
706 return;
708 r->eax = (int) &proc->pid;
711 void sys_lseek (struct regs *r)
713 int fd = r->ebx;
714 long offset = r->ecx;
715 int whence = r->edx;
717 *SYSV_LSEEK = lseek (fd, offset, whence);
720 void sys_pipe (struct regs *r)
722 int *p = (int *) r->ebx;
724 int ret = pipe (p);
726 r->eax = (int) &ret;
729 void sys_creat (struct regs *r)
731 char *file = (char *) r->ebx;
732 unsigned mode = r->ecx; /* TODO: mode */
734 int ret = -1;
736 if (file) {
737 if (mode == O_CREAT)
738 ret = (touch (file) == 1) ? 0 : -1;
739 } else
740 errno_set (EFAULT);
742 r->eax = (int) &ret;
745 void sys_mkdir (struct regs *r)
747 char *dir = (char *) r->ebx;
748 unsigned mode = r->ecx; /* TODO: mode */
750 int ret = -1;
752 if (dir) {
753 if (mode)
754 ret = (mkdir (dir) == 1) ? 0 : -1;
755 } else
756 errno_set (EFAULT);
758 r->eax = (int) &ret;
761 void sys_rmdir (struct regs *r)
763 char *dir = (char *) r->ebx;
765 int ret = -1;
767 if (dir) {
768 ret = (rm (dir) == 1) ? 0 : -1;
769 } else
770 errno_set (EFAULT);
772 r->eax = (int) &ret;
775 void sys_sndopen (struct regs *r)
777 snd_cfg_t *cfg = (snd_cfg_t *) r->ebx;
779 int ret = 0;
781 if (!cfg)
782 r->eax = (int) &ret;
783 else
784 r->eax = (int) audio_open (cfg);
787 void sys_sndclose (struct regs *r)
789 snd_audio_t *aud = (snd_audio_t *) r->ebx;
791 int ret = -1;
793 if (!aud)
794 r->eax = (int) &ret;
795 else
796 r->eax = (int) audio_close (aud);
799 void sys_sndwrite (struct regs *r)
801 snd_audio_t *aud = (snd_audio_t *) r->ebx;
802 char *buf = (char *) r->ecx;
803 unsigned len = (unsigned) r->edx;
805 int ret = -1;
807 if (!aud)
808 r->eax = (int) &ret;
809 else
810 r->eax = (int) audio_write (aud, buf, len);
813 void sys_remove (struct regs *r)
815 char *file = (char *) r->ebx;
817 int ret = -1;
819 if (file) {
820 ret = (vfs_rm (file, strlen (file)) == 1) ? 0 : -1;
821 } else
822 errno_set (EFAULT);
824 r->eax = (int) &ret;
827 void sys_rename (struct regs *r)
829 char *file = (char *) r->ebx;
830 char *file2 = (char *) r->ecx;
832 int ret = 0;
834 if (file) {
835 if (cp (file, file2) != 1)
836 ret = -1;
838 if (!ret && rm (file) != 1)
839 ret = -1;
840 } else
841 errno_set (EFAULT);
843 r->eax = (int) &ret;
846 void sys_select (struct regs *r)
848 struct select_t {
849 int nfds;
850 fd_set *readfds;
851 fd_set *writefds;
852 fd_set *exceptfds;
853 struct timeval *timeout;
856 struct select_t *s = (struct select_t *) r->ebx;
858 *SYSV_SELECT = select (s->nfds, s->readfds, s->writefds, s->exceptfds, s->timeout);
861 void syscall_handler (struct regs *r)
863 switch (r->eax) {
864 case 1:
865 return sys_exit (r);
866 case 2:
867 return sys_getch (r);
868 case 3:
869 return sys_sleep (r);
870 case 4:
871 return sys_putch (r);
872 case 5:
873 return sys_color (r);
874 case 6:
875 return sys_cls (r);
876 case 7:
877 return sys_getkey (r);
878 case 8:
879 return sys_gotoxy (r);
880 case 9:
881 return sys_fork (r);
882 case 10:
883 return sys_schedule (r);
884 case 11:
885 return sys_write (r);
886 case 12:
887 return sys_socket (r);
888 case 13:
889 return sys_connect (r);
890 case 14:
891 return sys_malloc (r);
892 case 15:
893 return sys_send (r);
894 case 16:
895 return sys_recv (r);
896 case 17:
897 return sys_close (r);
898 case 18:
899 return sys_open (r);
900 case 19:
901 return sys_pcspk (r);
902 case 20:
903 return sys_usleep (r);
904 case 21:
905 return sys_read (r);
906 case 22:
907 return sys_time (r);
908 case 23:
909 return sys_system (r);
910 case 24:
911 return sys_chdir (r);
912 case 25:
913 return sys_getdir (r);
914 case 26:
915 return sys_procarg (r);
916 case 27:
917 return sys_signal (r);
918 case 28:
919 return sys_mount (r);
920 case 29:
921 return sys_kputs (r);
922 case 30:
923 return sys_bind (r);
924 case 31:
925 return sys_listen (r);
926 case 32:
927 return sys_accept (r);
928 case 33:
929 return sys_fcntl (r);
930 case 34:
931 return sys_gvgafb (r);
932 case 35:
933 return sys_gcls (r);
934 case 36:
935 return sys_gfbswap (r);
936 case 37:
937 return sys_rs232read (r);
938 case 38:
939 return sys_rs232write (r);
940 case 39:
941 return sys_gttyexit (r);
942 case 40:
943 return sys_gexit (r);
944 case 41:
945 return sys_gttyinit (r);
946 case 42:
947 return sys_getenv (r);
948 case 43:
949 return sys_free (r);
950 case 44:
951 return sys_realloc (r);
952 case 45:
953 return sys_gethostbyname (r);
954 case 46:
955 return sys_vfsent (r);
956 case 47:
957 return sys_sendto (r);
958 case 48:
959 return sys_recvfrom (r);
960 case 49:
961 return sys_getchar (r);
962 case 50:
963 return sys_threadopen (r);
964 case 51:
965 return sys_threadclose (r);
966 case 52:
967 return sys_ioctl (r);
968 case 53:
969 return sys_getpid (r);
970 case 54:
971 return sys_lseek (r);
972 case 55:
973 return sys_pipe (r);
974 case 56:
975 return sys_creat (r);
976 case 57:
977 return sys_mkdir (r);
978 case 58:
979 return sys_rmdir (r);
980 case 59:
981 return sys_sndopen (r);
982 case 60:
983 return sys_sndclose (r);
984 case 61:
985 return sys_sndwrite (r);
986 case 62:
987 return sys_remove (r);
988 case 63:
989 return sys_rename (r);
990 case 64:
991 return sys_select (r);