| #ifdef __SHARC__ |
| #pragma nosharc |
| #endif |
| |
| #ifdef __DEPUTY__ |
| #pragma nodeputy |
| #endif |
| |
| #include <atomic.h> |
| #include <process.h> |
| #include <kmalloc.h> |
| #include <pmap.h> |
| #include <frontend.h> |
| #include <syscall.h> |
| #include <smp.h> |
| #include <slab.h> |
| #include <arch/arch.h> |
| |
| volatile int magic_mem[10]; |
| |
| void |
| frontend_proc_init(struct proc *SAFE p) |
| { |
| #ifdef CONFIG_APPSERVER |
| pid_t parent_id = p->ppid, id = p->pid; |
| int32_t errno; |
| if(frontend_syscall(parent_id,APPSERVER_SYSCALL_proc_init,id,0,0,0,&errno)) |
| panic("Front-end server couldn't initialize new process!"); |
| #endif |
| } |
| |
| void |
| frontend_proc_free(struct proc *SAFE p) |
| { |
| #ifdef CONFIG_APPSERVER |
| int32_t errno; |
| if(frontend_syscall(0,APPSERVER_SYSCALL_proc_free,p->pid,0,0,0,&errno)) |
| panic("Front-end server couldn't free process!"); |
| #endif |
| } |
| |
| struct kmem_cache* struct_file_cache; |
| void file_init() |
| { |
| struct_file_cache = kmem_cache_create("struct_file", |
| sizeof(struct file), 8, 0, 0, 0); |
| } |
| |
| /* will zero anything in the page after the EOF */ |
| error_t file_read_page(struct file* f, physaddr_t pa, size_t pgoff) |
| { |
| int ret = frontend_syscall(0,APPSERVER_SYSCALL_pread,f->fd,pa,PGSIZE, |
| pgoff*PGSIZE,NULL); |
| if(ret >= 0) |
| memset(KADDR(pa)+ret,0,PGSIZE-ret); |
| return ret; |
| } |
| |
| struct file* file_open_from_fd(struct proc* p, int fd) |
| { |
| struct file* f = NULL; |
| if(!(f = kmem_cache_alloc(struct_file_cache,0))) |
| goto out; |
| |
| f->fd = frontend_syscall(p->pid,APPSERVER_SYSCALL_kdup,fd,0,0,0,NULL); |
| if(f->fd == -1) |
| { |
| kmem_cache_free(struct_file_cache,f); |
| f = NULL; |
| goto out; |
| } |
| spinlock_init(&f->lock); |
| f->refcnt = 1; |
| |
| out: |
| return f; |
| } |
| |
| struct file* file_open(const char* path, int oflag, int mode) |
| { |
| struct file* f = NULL; |
| // although path is a kernel pointer, it may be below KERNBASE. |
| // fix that if so. |
| char* malloced = NULL; |
| if((uintptr_t)path < KERNBASE) |
| { |
| size_t len = strlen(path)+1; |
| malloced = kmalloc(len,0); |
| if(!malloced) |
| goto out; |
| path = memcpy(malloced,path,len); |
| } |
| |
| if(!(f = kmem_cache_alloc(struct_file_cache,0))) |
| goto out; |
| |
| f->fd = frontend_syscall(0,APPSERVER_SYSCALL_open,PADDR(path), |
| oflag,mode,0,NULL); |
| if(f->fd == -1) |
| { |
| kmem_cache_free(struct_file_cache,f); |
| f = NULL; |
| goto out; |
| } |
| spinlock_init(&f->lock); |
| f->refcnt = 1; |
| |
| out: |
| if(malloced) |
| kfree(malloced); |
| return f; |
| } |
| |
| void file_incref(struct file* f) |
| { |
| spin_lock(&f->lock); |
| f->refcnt++; |
| spin_unlock(&f->lock); |
| } |
| |
| void file_decref(struct file* f) |
| { |
| // if you decref too many times, you'll clobber memory :( |
| spin_lock(&f->lock); |
| if(--f->refcnt == 0) |
| { |
| int ret = frontend_syscall(0,APPSERVER_SYSCALL_close,f->fd,0,0,0,NULL); |
| assert(ret == 0); |
| kmem_cache_free(struct_file_cache,f); |
| } |
| else |
| spin_unlock(&f->lock); |
| } |
| |
| int frontend_syscall_errno(struct proc* p, int n, int a0, int a1, int a2, int a3) |
| { |
| int errno, ret = frontend_syscall(p->pid,n,a0,a1,a2,a3,&errno); |
| if(errno && p) |
| set_errno(errno); |
| return ret; |
| } |
| |
| int32_t frontend_syscall(pid_t pid, int32_t syscall_num, |
| uint32_t arg0, uint32_t arg1, |
| uint32_t arg2, uint32_t arg3, int32_t* errno) |
| { |
| #ifndef CONFIG_APPSERVER |
| warn("No appserver support, requested syscall %d for proc %d", syscall_num, |
| pid); |
| if(errno) |
| *errno = ENOSYS; |
| return -1; |
| #endif |
| |
| #ifdef CONFIG_X86 |
| if (!irq_is_enabled()) |
| warn("IRQ is disabled in frontend_syscall %d for proc %d\n", syscall_num, pid); |
| #endif |
| |
| static spinlock_t lock = SPINLOCK_INITIALIZER; |
| int32_t ret; |
| |
| // only one frontend request at a time. |
| // interrupts could try to do frontend requests, |
| // which would deadlock, so disable them |
| spin_lock(&lock); |
| |
| // write syscall into magic memory |
| magic_mem[7] = 0; |
| magic_mem[1] = syscall_num; |
| magic_mem[2] = arg0; |
| magic_mem[3] = arg1; |
| magic_mem[4] = arg2; |
| magic_mem[5] = arg3; |
| magic_mem[6] = pid; |
| magic_mem[0] = 0x80; |
| |
| // wait for front-end response |
| while(magic_mem[7] == 0) |
| ; |
| |
| ret = magic_mem[1]; |
| if(errno) |
| *errno = magic_mem[2]; |
| |
| spin_unlock(&lock); |
| |
| return ret; |
| } |
| |
| void __diediedie(uint32_t srcid, uint32_t code, uint32_t a1, uint32_t a2) |
| { |
| int32_t errno; |
| frontend_syscall(0,APPSERVER_SYSCALL_exit,(int)code,0,0,0,&errno); |
| while(1); |
| } |
| |
| void appserver_die(uintptr_t code) |
| { |
| int i; |
| for(i = 0; i < num_cpus; i++) |
| if(i != core_id()) |
| while(send_kernel_message(i, (amr_t)&__diediedie, code, 0, 0, |
| KMSG_IMMEDIATE)); |
| |
| // just in case. |
| __diediedie(0, code, 0, 0); |
| } |