// remember to sync this with interface/syscalls.c #include "lib/string/string.h" #include "lib/printf/printf.h" #include "fs/ext2.h" #include "kernel.h" #include "driver/vesa.h" #include "fifo.h" #include "fd.h" #include "fs/elf.h" #include "driver/terminal.h" #include "driver/screen.h" #include #include #include #include #include #include "syscalls.h" #include "scheduler.h" #include "log.h" #include "timer.h" #include "mount.h" #include "mem.h" #include "reent.h" #include "errno.h" #include "compositor.h" #include "stdstreams.h" #include "sys/unistd.h" #define MAX_PID 200 //TODO move to process.c and implement per process // static fd fds[MAX_PID][MAX_FD]; //static uint32_t opendir_pos[MAX_PID][MAX_FD]; //static char opendir_name[MAX_PID][MAX_FD][256]; static int tty[MAX_PID]; // keep track of /dev/tty fd for each process :P static bool open_fd[MAX_PID][MAX_FD]; fd *get_tty(uint32_t pid) { return &(fds[pid][tty[pid]]); } void fd_init_std_streams(uint32_t pid) { fds[pid][0]=fd_from_ringbuffer(); open_fd[pid][0]=true; fds[pid][1]=fd_from_ringbuffer(); open_fd[pid][1]=true; fds[pid][2]=fd_from_ringbuffer(); open_fd[pid][2]=true; return; } // /** helper */ int nextfd(int pid) { for(int i=0;i_errno=no; } /** get string represnation of syscall */ char* syscall_get_name(uint32_t num) { switch(num) { case SYSCALL_EXIT: return "SYSCALL_EXIT"; case SYSCALL_CLOSE: return "SYSCALL_CLOSE"; case SYSCALL_EXECVE: return "SYSCALL_EXECVE"; case SYSCALL_FORK: return "SYSCALL_FORK"; case SYSCALL_GETPID: return "SYSCALL_GETPID"; case SYSCALL_ISATTY: return "SYSCALL_ISATTY"; case SYSCALL_LINK: return "SYSCALL_LINK"; case SYSCALL_LSEEK: return "SYSCALL_LSEEK"; case SYSCALL_OPEN: return "SYSCALL_OPEN"; case SYSCALL_READ: return "SYSCALL_READ"; case SYSCALL_SBRK: return "SYSCALL_SBRK"; case SYSCALL_STAT: return "SYSCALL_STAT"; case SYSCALL_FSTAT: return "SYSCALL_FSTAT"; case SYSCALL_LSTAT: return "SYSCALL_LSTAT"; case SYSCALL_TIMES: return "SYSCALL_TIMES"; case SYSCALL_UNLINK: return "SYSCALL_UNLINK"; case SYSCALL_WAIT: return "SYSCALL_WAIT"; case SYSCALL_WRITE: return "SYSCALL_WRITE"; case SYSCALL_GETTIMEOFDAY: return "SYSCALL_GETTIMEOFDAY"; case SYSCALL_READDIR: return "SYSCALL_READDIR"; case SYSCALL_OPENDIR: return "SYSCALL_OPENDIR"; case SYSCALL_KILL: return "SYSCALL_KILL"; case SYSCALL_CLONE: return "SYSCALL_CLONE"; case SYSCALL_PIPE: return "SYSCALL_PIPE"; case SYSCALL_DUP2: return "SYSCALL_DUP2"; case SYSCALL_GUI_RECT: return "SYSCALL_GUI_RECT"; case SYSCALL_GUI_WIN: return "SYSCALL_GUI_WIN"; case SYSCALL_SELECT: return "SYSCALL_SELECT"; case SYSCALL_TCGETATTR: return "SYSCALL_TCGETATTR"; case SYSCALL_TCSETATTR: return "SYSCALL_TCSETATTR"; case SYSCALL_UNIMPLEMENTED: return "SYSCALL_UNIMPLEMENTED"; } kpanic("UNKNOWN SYSCALL NUM: %d",num); } int syscall_gettimeofday(struct timeval *tv, struct timezone *tz,uint32_t none1, uint32_t pid) { if(tv!=NULL) { uint64_t t=timer_get_ms(); tv->tv_sec=t/1000+2*3600; // add gmt+2 tv->tv_usec=1000*(t%1000); } // tz struct is obsolote if(tz!=NULL) { tz->tz_minuteswest=0;// -21*60; // warsaw tz->tz_dsttime=DST_NONE; } return 0; } int syscall_lseek(int file,int ptr,int dir,uint32_t pid) { if(dir==SEEK_CUR) { uint32_t *dat=fds[pid][file].data; dat[1]+=ptr; return dat[1]; } else if(dir==SEEK_SET) { uint32_t *dat=fds[pid][file].data; dat[1]=ptr; return dat[1]; } else if(dir==SEEK_END) { kpanic("SEEK_END dir for lseek!"); } else { kpanic("wrong dir for lseek!"); } return 0; } // TODO: /dev/console or /dev/tty1 - /dev/ttyN int syscall_write(int file, char *buf, int len,uint32_t pid) { if(!open_fd[pid][file])kpanic("writing to closed file descriptor"); for(int i=0;i0) { if(fd_eof(&fds[pid][file]))return ret; *buf++=fd_read(&fds[pid][file]); ret++; } return ret; } /** * Monitor multiple descriptors * ============================ * * nfds is the MAX file descriptor number +1. * * It is possible to provide 3 different sets of filedescriptors * (they can be NULL as well) * * - readfds - reading * - writefds - writing * - exceptfds - exceptions (all cleared unless exception occurs) * * The call returns the total number of descriptors contained in all * sets after returning. * * This call will block until time (timeout) runs out * OR a file descriptor becomes ready. */ int syscall_select(int maxxfd,struct timeval *tv, fd_set **fd_sets, uint32_t pid, bool test) { int ret=0; if(test&&tv!=NULL) // check if time did not run out already { if(tv->tv_sec==0&&tv->tv_usec==0)return 1; uint64_t t=timer_get_ms(); // current time in milliseconds (10^-3) uint64_t t0=0; t0+=tv->tv_sec*1000; // seconds * 10^3 t0+=tv->tv_usec/1000; // microseconds * 10^-3 if(t>t0)return 1; // ready to fire! } // TODO: wake when timeout runs out! if(!test) { // if(tv==NULL)klog("select with infinite timeout"); // else klog ("select with timeout: sec=%d, usec=%d",tv->tv_sec,tv->tv_usec); } for(int i=0;idirname,name); if(dirs->dirname[strlen(dirs->dirname)-1]=='/')dirs->dirname[strlen(dirs->dirname)-1]=0; klog("syscall to opendir(%s)",dirs->dirname); // test if exists.... struct dirent testdirent; uint32_t testpos; int ret=mount_read_dir(dirs->dirname, &testdirent, &testpos); if(ret==-1) { // no it does not! set_errno(ENOENT); return NULL; } dirs->pos=0; /* uint32_t fdn=nextfd(pid); strcpy(opendir_name[pid][fdn],dirs->dirname); opendir_pos[pid][fdn]=0; */ return dirs; } struct dirent *syscall_readdir(struct dirent *dirs,int none1, int none2,uint32_t pid) { // this dirent will get filled with next entry... int ret=mount_read_dir(dirs->dirname, dirs, &dirs->pos); // no more entries if(ret==0)return NULL; return dirs; } /** execve helper */ int copy_args(char **in, char **out) { //klog("copy_args(0x%08x, 0x%08X)",in,out); int count=0; while(in[count]!=NULL) { // klog("args(0x%08x: %s)",in[count],out); count++; }; // klog("copy_args : count: %d",count); char **pos=out; pos+=sizeof(char **)*(count+1); int i=0; do{ int l=strlen(in[i]); char *var=pos; memcpy(var,in[i],l+1); pos+=sizeof(char *)*(l+1); out[i]=var; i++; }while(in[i]!=NULL); out[i]=NULL; return count; } /** does not return on success otherwise -1 and errrno set */ // int execve(const char *filename, char *const argv[], char *const envp[]); int syscall_execve(const char *name, char *const argv[], char *const env[], int pid) { fixme("not overwrite yourself?"); int arg_count=0; while(argv[arg_count]!=NULL)arg_count++; char **argv1=VMEM_USER_ENV; if(argv!=NULL)copy_args(argv,argv1); else argv1=NULL; char **env1=VMEM_USER_ENV+1024*2; if(env!=NULL)copy_args(env,env1); else env1=NULL; uint32_t alloc; uint32_t entry_global=load_elf(name,&alloc); if(!entry_global){ set_errno(ENOENT); return -1; } uint32_t *stack=VMEM_USER_STACK_TOP-4*32; *--stack=argv1; *--stack=arg_count; *--stack=env1; task_reset(pid,entry_global,stack,alloc); task_set_name(pid,name); return 0; } int syscall_open(char *name, int flags, int mode,uint32_t pid) { klog("open %s",name); if(!strcmp("/dev/tty",name))return tty[pid]; uint32_t fdn=nextfd(pid); fds[pid][fdn]=mount_file_open(name); if(*(uint32_t *)fds[pid][fdn].data==0)return -1; return fdn; } // pid_t fork(void); uint32_t syscall_fork(int none1, int none2, int none3, int pid) { uint32_t newpid=task_fork(pid); for(int i=0;imax_addy)kpanic("can not set sbrk . TODO: dynamic allocation!"); fixme("fake syscall_sbrk(0x%08X) return %08X",incr,oldalloc); return oldalloc; } // stat, fstat, lstat int syscall_stat(const char *path, struct stat *st,int none,uint32_t pid) { st->st_mode = S_IFCHR; return 0; } uint32_t syscall_pipe(uint32_t *addr,int none1, int none2, uint32_t pid) { fd pipfds[2]; int ret=fds_from_pipe(pipfds); int fd1=nextfd(pid); int fd2=nextfd(pid); klog("new pipe read=%d, write=%d",fd1,fd2 ); fds[pid][fd1]=pipfds[0] ; *addr=fd1; addr++; fds[pid][fd2]=pipfds[1] ; *addr=fd2; return ret; } uint32_t syscall_dup2(uint32_t oldfd,int newfd, int none2, uint32_t pid) { if(newfd==0xffffffff)kpanic("dup mode not supported yet !!!"); fds[pid][newfd]=fd_dupl(&fds[pid][oldfd]); return newfd; } /// testing TODO: struct termios tty1; bool termios_init=false; uint32_t syscall_tcgetattr(int fd, struct termios *termios_p, uint32_t none, uint32_t pid) { if(!termios_init) { tty1.c_cc[VMIN]=1; // reading from terminal returns after each byte termios_init=true; } klog("pid %d calls tcgetattr on %d",pid,fd); *termios_p=tty1; return 0; } uint32_t syscall_tcsetattr(int fd, struct termios *termios_p, uint32_t none, uint32_t pid) { klog("pid %d calls tcsetattr on %d",pid,fd); klog("c_iflag=%08X",termios_p->c_iflag); klog("c_oflag=%08X",termios_p->c_oflag); klog("c_cflag=%08X",termios_p->c_cflag); klog("c_lflag=%08X",termios_p->c_lflag); for(int i=0;ic_cc[i]!=0) { klog("set c_cc[%d]=%d",i,termios_p->c_cc[i]); } } tty1=*termios_p; return 0; } uint32_t syscall_gui_rect(uint32_t p1, uint32_t p2, uint32_t p3, uint32_t pid) { compositor_wake(); return 1; } uint32_t syscall_gui_win(uint32_t p1, uint32_t p2, uint32_t p3, uint32_t pid) { uint32_t fdn=nextfd(pid); fds[pid][fdn]=fd_from_ringbuffer(); tty[pid]=fdn; task_add_win(pid); return 1; } /** Generics */ uint32_t syscall_generic_prep(uint32_t nr,uint32_t p1, uint32_t p2, uint32_t p3, uint32_t pid) { struct timeval *tv=p2; switch(nr){ case SYSCALL_SELECT : // change to absolute time for easier timout if(tv!=NULL&&(tv->tv_sec!=0||tv->tv_usec!=0)) { uint64_t t=timer_get_ms(); // current time in milliseconds (10^-3) t+=tv->tv_sec*1000; // seconds * 10^3 t+=tv->tv_usec/1000; // microseconds * 10^-3 tv->tv_sec=t/1000; tv->tv_usec=(t%1000)*1000; } break; } return 1; } /** Generics */ uint32_t syscall_generic_test(uint32_t nr,uint32_t p1, uint32_t p2, uint32_t p3, uint32_t pid) { switch(nr){ case SYSCALL_WAIT : return !task_runs(p1); case SYSCALL_READ : return fd_has(&fds[pid][p1])||fd_eof(&fds[pid][p1]); case SYSCALL_WRITE : return fd_can_write(&fds[pid][p1]); case SYSCALL_SELECT : return syscall_select(p1,p2,p3,pid,true); } return 1;//other syscalls never block for now. } /** Generics */ uint32_t syscall_generic(uint32_t nr,uint32_t p1, uint32_t p2, uint32_t p3, uint32_t pid) { #ifdef LOG_SYSCALLS klog("processing syscall [%s] for pid:%d",syscall_get_name(nr),pid); #endif switch(nr){ case SYSCALL_EXIT : return syscall_exit(p1,p2,p3,pid); case SYSCALL_CLOSE : return syscall_close(p1,p2,p3,pid); case SYSCALL_EXECVE : return syscall_execve(p1,p2,p3,pid); case SYSCALL_FORK : return syscall_fork(p1,p2,p3,pid); case SYSCALL_CLONE : return syscall_clone(p1,p2,p3,pid); case SYSCALL_GETPID : // return syscall_getpid(p1,p2,p3); return -1; case SYSCALL_ISATTY : return syscall_isatty(p1,p2,p3,pid); case SYSCALL_LINK : // return syscall_link(p1,p2,p3); return -1; case SYSCALL_LSEEK : return syscall_lseek(p1,p2,p3,pid); case SYSCALL_OPEN : return syscall_open(p1,p2,p3,pid); case SYSCALL_READ : return syscall_read(p1,p2,p3,pid); case SYSCALL_SBRK : return syscall_sbrk(p1,p2,p3,pid); case SYSCALL_STAT : return syscall_stat(p1,p2,p3,pid); case SYSCALL_FSTAT : return syscall_stat(p1,p2,p3,pid); case SYSCALL_LSTAT : return syscall_stat(p1,p2,p3,pid); case SYSCALL_TIMES : // return syscall_times(p1,p2,p3); return -1; case SYSCALL_UNLINK : // return syscall_unlink(p1,p2,p3); return -1; case SYSCALL_WAIT : return syscall_wait(p1,p2,p3,pid); case SYSCALL_WRITE : return syscall_write(p1,p2,p3,pid); case SYSCALL_GETTIMEOFDAY: return syscall_gettimeofday(p1,p2,p3,pid); case SYSCALL_READDIR : return syscall_readdir(p1,p2,p3,pid); case SYSCALL_OPENDIR : return syscall_opendir(p1,p2,p3,pid); case SYSCALL_KILL : // return task_kill(p1,p2,p3); return -1; case SYSCALL_PIPE : return syscall_pipe(p1,p2,p3,pid); case SYSCALL_DUP2 : return syscall_dup2(p1,p2,p3,pid); case SYSCALL_SELECT : return syscall_select(p1,p2,p3,pid,false); case SYSCALL_GUI_RECT : return syscall_gui_rect(p1,p2,p3,pid); case SYSCALL_GUI_WIN : return syscall_gui_win(p1,p2,p3,pid); case SYSCALL_TCGETATTR: return syscall_tcgetattr(p1,p2,p3,pid); case SYSCALL_TCSETATTR: return syscall_tcsetattr(p1,p2,p3,pid); case SYSCALL_UNIMPLEMENTED: if(!strcmp(p1,"fcntl")){ klog("todo: quickfix hack for fcntl"); } } klog("unknown syscall %s / %d we just return 0",p1,nr); return 0; }