text: // MIT License, Copyright (c) 2020 Marvin Borner
  
  #include <cpu.h>
  #include <errno.h>
  #include <fs.h>
  #include <interrupts.h>
  #include <load.h>
  #include <mem.h>
  #include <mm.h>
  #include <net.h>
  #include <print.h>
  #include <proc.h>
  #include <str.h>
  #include <sys.h>
  #include <syscall.h>
  #include <timer.h>
  
  static void syscall_handler(struct regs *r)
  {
  	enum sys num = r->eax;
  	r->eax = EOK;
  
  	/* printf("[SYSCALL] %d from %s\n", num, proc_current()->name); */
  
  	switch (num) {
  	case SYS_LOOP: {
  		loop();
  		panic("Fell out of the looping!\n");
  		break;
  	}
  	case SYS_ALLOC: {
  		r->eax = (u32)memory_sys_alloc(proc_current()->page_dir, r->ebx, (u32 *)r->ecx,
  					       (u32 *)r->edx, (u8)r->esi);
  		break;
  	}
  	case SYS_FREE: {
  		r->eax = memory_sys_free(proc_current()->page_dir, r->ebx);
  		break;
  	}
  	case SYS_SHACCESS: {
  		r->eax = memory_sys_shaccess(proc_current()->page_dir, r->ebx, (u32 *)r->ecx,
  					     (u32 *)r->edx);
  		break;
  	}
  	case SYS_STAT: {
  		r->eax = vfs_stat((char *)r->ebx, (struct stat *)r->ecx);
  		break;
  	}
  	case SYS_READ: {
  		if (vfs_ready((char *)r->ebx)) {
  			r->eax = (u32)vfs_read((char *)r->ebx, (void *)r->ecx, r->edx, r->esi);
  		} else {
  			res wait = vfs_wait((char *)r->ebx, (u32)vfs_read);
  			if (wait != 0)
  				r->eax = wait;
  			else
  				proc_yield(r);
  		}
  		break;
  	}
  	case SYS_WRITE: {
  		r->eax = vfs_write((char *)r->ebx, (void *)r->ecx, r->edx, r->esi);
  		break;
  	}
  	case SYS_IOCTL: {
  		r->eax = vfs_ioctl((char *)r->ebx, r->ecx, (void *)r->edx, (void *)r->esi,
  				   (void *)r->edi);
  		break;
  	}
  	case SYS_POLL: {
  		res ret = vfs_poll((const char **)r->ebx);
  		r->eax = ret;
  		if (ret == PROC_MAX_WAIT_IDS + 1)
  			proc_yield(r);
  		break;
  	}
  	case SYS_EXEC: {
  		char *path = (char *)r->ebx;
  		struct proc *proc = proc_make(PROC_PRIV_NONE);
  		r->eax = (u32)elf_load(path, proc);
  		if (r->eax != 0) {
  			proc_exit(proc, -r->eax);
  		} else {
  			// TODO: Reimplement argc,argv
  			proc_stack_push(proc, 0);
  			proc_yield(r);
  		}
  		break;
  	}
  	case SYS_EXIT: {
  		proc_exit(proc_current(), (s32)r->ebx);
  		proc_yield(r);
  		break;
  	}
  	case SYS_BOOT: { // TODO: Move
  		if (r->ebx != SYS_BOOT_MAGIC) {
  			r->eax = -EINVAL;
  			break;
  		}
  		if (!proc_super()) {
  			r->eax = -EACCES;
  		}
  		switch (r->ecx) {
  		case SYS_BOOT_REBOOT:
  			print("Rebooting...\n");
  			outb(0x64, 0xfe);
  			__asm__ volatile("ud2");
  			break;
  		case SYS_BOOT_SHUTDOWN:
  			print("Shutting down...\n");
  			outw(0xB004, 0x2000);
  			outw(0x604, 0x2000);
  			outw(0x4004, 0x3400);
  			outb(0x64, 0xfe);
  			__asm__ volatile("ud2");
  			break;
  		default:
  			r->eax = -EINVAL;
  		}
  		break;
  	}
  	case SYS_YIELD: {
  		proc_yield(r);
  		break;
  	}
  	case SYS_TIME: {
  		r->eax = timer_get();
  		break;
  	}
  	// TODO: Reimplement network functions using VFS
  	default: {
  		printf("Unknown syscall %d!\n", num);
  		break;
  	}
  	}
  }
  
  void syscall_init(void)
  {
  	idt_set_gate(0x80, (u32)isr128, 0x08, 0x8E);
  	isr_install_handler(0x80, syscall_handler);
  }
  