/* * Copyright 2010 Stefan Lankes, Chair for Operating Systems, * RWTH Aachen University * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * This file is part of MetalSVM. */ #include #include #include #include #include #include #include #include #include #if defined(CONFIG_LWIP) && LWIP_SOCKET #include #include #include #include #include #include #include #include #include #include #include #endif static int get_fildes(){ int fd; for (fd = 0; fd < NR_OPEN; fd++) { if (per_core(current_task)->fildes_table[fd].node == NULL) { return fd; } } /* can't get any free fd */ return -EMFILE; } static int sys_open(const char* name, int flags, int mode) { int fd, check; fildes_t* file = NULL; fd = get_fildes(); /* validate the fd */ if (fd < 0) return fd; file = &(per_core(current_task)->fildes_table[fd]); file->offset = 0; file->mode = mode; file->flags = flags; check = open_fs(file, (char*) name); if (check < 0) { /* file doesn't exist! */ file->node = NULL; return check; } return fd; } #if defined(CONFIG_LWIP) && LWIP_SOCKET static int sys_socket(int domain, int type, int protocol) { int fd; fildes_t* file = NULL; fd = get_fildes(); /* validate the fd */ if (fd < 0) return fd; file = &(per_core(current_task)->fildes_table[fd]); file->offset = lwip_socket(domain, type, protocol); file->mode = 0; file->flags = 0; file->node = findnode_fs("/dev/socket"); return fd; } static int sys_accept(int s, struct sockaddr* addr, socklen_t* addrlen) { int fd; fildes_t* file = NULL; fd = get_fildes(); /* validate the fd */ if (fd < 0) return fd; file = &(per_core(current_task)->fildes_table[fd]); file->offset = lwip_accept(s, addr, addrlen); file->mode = 0; file->flags = 0; file->node = findnode_fs("/dev/socket"); return fd; } #endif static int sys_close(int fd) { fildes_t* file = &(per_core(current_task)->fildes_table[fd]); close_fs(file); file->node = NULL; file->offset = 0; file->mode = 0; file->flags = 0; return 0; } static int sys_lseek(int fd, off_t pos, int origin) { int ret = -EINVAL; fildes_t* file = &(per_core(current_task)->fildes_table[fd]); if (BUILTIN_EXPECT(!((file->node->type == FS_FILE) || (file->node->type == FS_CHARDEVICE)), 0)) return -EINVAL; switch(origin) { case SEEK_SET: { /* set file offset to offset */ file->offset = pos; ret = 0; break; } case SEEK_CUR: { /* set file offset to current plus offset */ ret = pos + file->offset; break; } case SEEK_END: { /* set file offset to EOF plus offset */ file->offset = pos + file->node->block_size; ret = 0; break; } default: ret = -EINVAL; break; } return ret; } static int sys_sbrk(int incr) { task_t* task = per_core(current_task); vma_t* tmp = NULL; int ret; spinlock_lock(&task->vma_lock); tmp = task->vma_list; while(tmp && !((task->end_heap >= tmp->start) && (task->end_heap <= tmp->end))) tmp = tmp->next; ret = (int) task->end_heap; task->end_heap += incr; if (task->end_heap < task->start_heap) task->end_heap = task->start_heap; // resize virtual memory area if (tmp && (tmp->end <= task->end_heap)) tmp->end = task->end_heap; spinlock_unlock(&task->vma_lock); return ret; } int syscall_handler(uint32_t sys_nr, ...) { int ret = -EINVAL; va_list vl; check_workqueues(); va_start(vl, sys_nr); switch(sys_nr) { case __NR_exit: sys_exit(va_arg(vl, uint32_t)); ret = 0; break; case __NR_write: { int fd = va_arg(vl, int); const char* buf = va_arg(vl, const char*); size_t len = va_arg(vl, size_t); if (fd >= 0) ret = write_fs(&(per_core(current_task)->fildes_table[fd]), (uint8_t*)buf, len); break; } case __NR_open: { const char* name = va_arg(vl, const char*); int flags = va_arg(vl, int); int mode = va_arg(vl, int); ret = sys_open(name, flags, mode); break; } case __NR_close: { int fd = va_arg(vl, int); if (fd >= 0) ret = sys_close(fd); break; } case __NR_read: { int fd = va_arg(vl, int); const char* buf = va_arg(vl, const char*); size_t len = va_arg(vl, size_t); if (fd >= 0) ret = read_fs(&(per_core(current_task)->fildes_table[fd]), (uint8_t*)buf, len); break; } case __NR_lseek: { int fd = va_arg(vl, int); off_t pos = va_arg(vl, off_t); int origin = va_arg(vl, int); if (fd >= 0) ret = sys_lseek(fd, pos, origin); break; } case __NR_sbrk: { int incr = va_arg(vl, int); ret = sys_sbrk(incr); break; } case __NR_getpid: ret = per_core(current_task)->id; break; case __NR_fork: ret = sys_fork(); break; case __NR_wait: { int32_t* status = va_arg(vl, int32_t*); ret = wait(status); break; } case __NR_execve: { const char* name = va_arg(vl, const char*); char** argv = va_arg(vl, char**); char** env = va_arg(vl, char**); ret = sys_execve(name, argv, env); break; } case __NR_times: { struct tms* buffer = va_arg(vl, struct tms*); clock_t* clock = va_arg(vl, clock_t*); ret = sys_times(buffer, clock); break; } #if defined(CONFIG_LWIP) && LWIP_SOCKET case __NR_closesocket: { int fd = va_arg(vl, int); if (fd < 0) { ret = -ENOTSOCK; break; } //ret = lwip_close(per_core(current_task)->fildes_table[fd].offset); if (ret < 0) ret = -errno; break; } case __NR_socket: { int domain = va_arg(vl, int); int type = va_arg(vl, int); int protocol = va_arg(vl, int); ret = sys_socket(domain, type, protocol); break; } case __NR_connect: { int fd = va_arg(vl, int); const struct sockaddr* name = va_arg(vl, const struct sockaddr*); socklen_t namelen = va_arg(vl, socklen_t); if (per_core(current_task)->fildes_table[fd].offset < 0) { ret = -ENOTSOCK; break; } //kprintf("lwip_connect: %p with lenght %i and Socket %i", name, namelen, per_core(current_task)->fildes_table[fd].offset); ret = lwip_connect(per_core(current_task)->fildes_table[fd].offset, name, namelen); if (ret < 0) ret = -errno; break; } case __NR_bind: { int fd = va_arg(vl, int); const struct sockaddr* name = va_arg(vl, const struct sockaddr*); socklen_t namelen = va_arg(vl, socklen_t); if (per_core(current_task)->fildes_table[fd].offset < 0) { ret = -ENOTSOCK; break; } ret = lwip_bind(per_core(current_task)->fildes_table[fd].offset, name, namelen); if (ret < 0) ret = -errno; break; } case __NR_listen: { int fd = va_arg(vl, int); int backlog = va_arg(vl, int); if (per_core(current_task)->fildes_table[fd].offset < 0) { ret = -ENOTSOCK; break; } ret = lwip_listen(per_core(current_task)->fildes_table[fd].offset, backlog); if (ret < 0) ret = -errno; break; } case __NR_accept: { int fd = va_arg(vl, int); struct sockaddr* addr = va_arg(vl, struct sockaddr*); socklen_t* addrlen = va_arg(vl, socklen_t*); if (per_core(current_task)->fildes_table[fd].offset < 0) { ret = -ENOTSOCK; break; } ret = sys_accept(per_core(current_task)->fildes_table[fd].offset, addr, addrlen); if (ret < 0) ret = -errno; break; } #endif default: kputs("invalid system call\n"); ret = -ENOSYS; break; }; va_end(vl); return ret; }