123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- #include <bits/ioctl.h>
- #include <errno.h>
- #include <poll.h>
- #include <sys/mman.h>
- #include <unistd.h>
- #include <types/path.hpp>
- #include <kernel/log.hpp>
- #include <kernel/mem/vm_area.hpp>
- #include <kernel/process.hpp>
- #include <kernel/syscall.hpp>
- #include <kernel/vfs.hpp>
- #define NOT_IMPLEMENTED not_implemented(__FILE__, __LINE__)
- static inline void not_implemented(const char* pos, int line) {
- kmsgf(
- "[kernel] the function at %s:%d is not implemented, killing the "
- "pid%d...",
- pos, line, current_process->pid);
- current_thread->send_signal(SIGSYS);
- }
- ssize_t kernel::syscall::do_write(int fd, const char __user* buf, size_t n) {
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- return file->write(buf, n);
- }
- ssize_t kernel::syscall::do_read(int fd, char __user* buf, size_t n) {
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- return file->read(buf, n);
- }
- int kernel::syscall::do_close(int fd) {
- current_process->files.close(fd);
- return 0;
- }
- int kernel::syscall::do_dup(int old_fd) {
- return current_process->files.dup(old_fd);
- }
- int kernel::syscall::do_dup2(int old_fd, int new_fd) {
- return current_process->files.dup(old_fd, new_fd, 0);
- }
- int kernel::syscall::do_pipe(int __user* pipefd) {
- // TODO: use copy_from_user and copy_to_user
- return current_process->files.pipe(*(int(*)[2])pipefd);
- }
- ssize_t kernel::syscall::do_getdents(int fd, char __user* buf, size_t cnt) {
- auto* dir = current_process->files[fd];
- if (!dir)
- return -EBADF;
- return dir->getdents(buf, cnt);
- }
- ssize_t kernel::syscall::do_getdents64(int fd, char __user* buf, size_t cnt) {
- auto* dir = current_process->files[fd];
- if (!dir)
- return -EBADF;
- return dir->getdents64(buf, cnt);
- }
- int kernel::syscall::do_open(const char __user* path, int flags, mode_t mode) {
- mode &= ~current_process->umask;
- // TODO: use copy_from_user
- return current_process->files.open(current_process->cwd.get(), path, flags,
- mode);
- }
- int kernel::syscall::do_symlink(const char __user* target,
- const char __user* linkpath) {
- // TODO: use copy_from_user
- auto [dent, status] = current_open(linkpath);
- if (!dent || status != -ENOENT)
- return status;
- return fs::symlink(dent.get(), target);
- }
- int kernel::syscall::do_readlink(const char __user* pathname, char __user* buf,
- size_t buf_size) {
- // TODO: use copy_from_user
- auto [dent, status] = current_open(pathname, false);
- if (!dent || status)
- return status;
- if (buf_size <= 0 || !S_ISLNK(dent->inode->mode))
- return -EINVAL;
- // TODO: use copy_to_user
- return fs::readlink(dent->inode, buf, buf_size);
- }
- int kernel::syscall::do_ioctl(int fd, unsigned long request, uintptr_t arg3) {
- // TODO: check fd type and get tty* from fd
- //
- // we use a trick for now, check whether
- // the file that fd points to is a pipe or
- // not. and we suppose that stdin will be
- // either a tty or a pipe.
- auto* file = current_process->files[fd];
- if (!file || !S_ISCHR(file->mode))
- return -ENOTTY;
- switch (request) {
- case TIOCGPGRP: {
- auto* pgid = (pid_t __user*)arg3;
- auto* ctrl_tty = current_process->control_tty;
- if (!ctrl_tty)
- return -ENOTTY;
- // TODO: copy_to_user
- *pgid = ctrl_tty->get_pgrp();
- break;
- }
- case TIOCSPGRP: {
- // TODO: copy_from_user
- auto pgid = *(const pid_t __user*)arg3;
- auto* ctrl_tty = current_process->control_tty;
- if (!ctrl_tty)
- return -ENOTTY;
- ctrl_tty->set_pgrp(pgid);
- break;
- }
- case TIOCGWINSZ: {
- auto* ws = (winsize __user*)arg3;
- // TODO: copy_to_user
- ws->ws_col = 80;
- ws->ws_row = 10;
- break;
- }
- case TCGETS: {
- auto* argp = (struct termios __user*)arg3;
- auto* ctrl_tty = current_process->control_tty;
- if (!ctrl_tty)
- return -EINVAL;
- // TODO: use copy_to_user
- memcpy(argp, &ctrl_tty->termio, sizeof(ctrl_tty->termio));
- break;
- }
- case TCSETS: {
- auto* argp = (const struct termios __user*)arg3;
- auto* ctrl_tty = current_process->control_tty;
- if (!ctrl_tty)
- return -EINVAL;
- // TODO: use copy_from_user
- memcpy(&ctrl_tty->termio, argp, sizeof(ctrl_tty->termio));
- break;
- }
- default:
- kmsgf("[error] the ioctl() function %x is not implemented",
- request);
- return -EINVAL;
- }
- return 0;
- }
- ssize_t kernel::syscall::do_readv(int fd, const iovec* iov, int iovcnt) {
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- // TODO: fix fake EOF
- ssize_t totn = 0;
- for (int i = 0; i < iovcnt; ++i) {
- ssize_t ret = file->read((char*)iov[i].iov_base, iov[i].iov_len);
- if (ret < 0)
- return ret;
- if (ret == 0)
- break;
- totn += ret;
- if ((size_t)ret != iov[i].iov_len)
- break;
- }
- return totn;
- }
- // TODO: this operation SHOULD be atomic
- ssize_t kernel::syscall::do_writev(int fd, const iovec* iov, int iovcnt) {
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- ssize_t totn = 0;
- for (int i = 0; i < iovcnt; ++i) {
- ssize_t ret = file->write((const char*)iov[i].iov_base, iov[i].iov_len);
- if (ret < 0)
- return ret;
- totn += ret;
- }
- return totn;
- }
- off_t kernel::syscall::do_lseek(int fd, off_t offset, int whence) {
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- return file->seek(offset, whence);
- }
- uintptr_t kernel::syscall::do_mmap_pgoff(uintptr_t addr, size_t len, int prot,
- int flags, int fd, off_t pgoffset) {
- if (addr & 0xfff)
- return -EINVAL;
- if (len == 0)
- return -EINVAL;
- len = (len + 0xfff) & ~0xfff;
- // TODO: shared mappings
- if (flags & MAP_SHARED)
- return -ENOMEM;
- if (flags & MAP_ANONYMOUS) {
- if (fd != -1)
- return -EINVAL;
- if (pgoffset != 0)
- return -EINVAL;
- // TODO: shared mappings
- if (!(flags & MAP_PRIVATE))
- return -EINVAL;
- auto& mms = current_process->mms;
- // do unmapping, equal to munmap, MAP_FIXED set
- if (prot == PROT_NONE) {
- if (int ret = mms.unmap(addr, len, true); ret != 0)
- return ret;
- } else {
- // TODO: add NULL check in mm_list
- if (!addr || !mms.is_avail(addr, len)) {
- if (flags & MAP_FIXED)
- return -ENOMEM;
- addr = mms.find_avail(addr, len);
- }
- // TODO: check current cs
- if (addr + len > 0x100000000ULL)
- return -ENOMEM;
- mem::mm_list::map_args args{};
- args.vaddr = addr;
- args.length = len;
- args.flags = mem::MM_ANONYMOUS;
- if (prot & PROT_WRITE)
- args.flags |= mem::MM_WRITE;
- if (prot & PROT_EXEC)
- args.flags |= mem::MM_EXECUTE;
- if (int ret = mms.mmap(args); ret != 0)
- return ret;
- }
- }
- return addr;
- }
- int kernel::syscall::do_munmap(uintptr_t addr, size_t len) {
- if (addr & 0xfff)
- return -EINVAL;
- return current_process->mms.unmap(addr, len, true);
- }
- ssize_t kernel::syscall::do_sendfile(int out_fd, int in_fd,
- off_t __user* offset, size_t count) {
- auto* out_file = current_process->files[out_fd];
- auto* in_file = current_process->files[in_fd];
- if (!out_file || !in_file)
- return -EBADF;
- // TODO: check whether in_fd supports mmapping
- if (!S_ISREG(in_file->mode) && !S_ISBLK(in_file->mode))
- return -EINVAL;
- if (offset) {
- NOT_IMPLEMENTED;
- return -EINVAL;
- }
- constexpr size_t bufsize = 4096;
- std::vector<char> buf(bufsize);
- size_t totn = 0;
- while (totn < count) {
- if (current_thread->signals.pending_signal() != 0)
- return (totn == 0) ? -EINTR : totn;
- size_t n = std::min(count - totn, bufsize);
- ssize_t ret = in_file->read(buf.data(), n);
- if (ret < 0)
- return ret;
- if (ret == 0)
- break;
- ret = out_file->write(buf.data(), ret);
- if (ret < 0)
- return ret;
- totn += ret;
- }
- return totn;
- }
- int kernel::syscall::do_statx(int dirfd, const char __user* path, int flags,
- unsigned int mask, statx __user* statxbuf) {
- // AT_STATX_SYNC_AS_STAT is the default value
- if ((flags & AT_STATX_SYNC_TYPE) != AT_STATX_SYNC_AS_STAT) {
- NOT_IMPLEMENTED;
- return -EINVAL;
- }
- if (dirfd != AT_FDCWD) {
- NOT_IMPLEMENTED;
- return -EINVAL;
- }
- auto [dent, status] = current_open(path, !(flags & AT_SYMLINK_NOFOLLOW));
- if (!dent || status)
- return status;
- // TODO: copy to user
- return fs::statx(dent->inode, statxbuf, mask);
- }
- int kernel::syscall::do_fcntl(int fd, int cmd, unsigned long arg) {
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- switch (cmd) {
- case F_SETFD:
- return current_process->files.set_flags(fd, arg);
- case F_DUPFD:
- case F_DUPFD_CLOEXEC: {
- return current_process->files.dupfd(fd, arg, FD_CLOEXEC);
- }
- default:
- NOT_IMPLEMENTED;
- return -EINVAL;
- }
- }
- int kernel::syscall::do_mkdir(const char __user* pathname, mode_t mode) {
- mode &= (~current_process->umask & 0777);
- // TODO: use copy_from_user
- auto [dent, status] = current_open(pathname);
- if (!dent || status != -ENOENT)
- return status;
- return fs::mkdir(dent.get(), mode);
- }
- int kernel::syscall::do_truncate(const char __user* pathname, long length) {
- auto [dent, status] = current_open(pathname);
- if (!dent || status)
- return status;
- if (S_ISDIR(dent->inode->mode))
- return -EISDIR;
- return fs::truncate(dent->inode, length);
- }
- int kernel::syscall::do_unlink(const char __user* pathname) {
- auto [dent, status] = current_open(pathname, false);
- if (!dent || status)
- return status;
- if (S_ISDIR(dent->inode->mode))
- return -EISDIR;
- return fs::unlink(dent.get());
- }
- int kernel::syscall::do_access(const char __user* pathname, int mode) {
- auto [dent, status] = current_open(pathname);
- if (!dent || status)
- return status;
- switch (mode) {
- case F_OK:
- return 0;
- case R_OK:
- case W_OK:
- case X_OK:
- // TODO: check privilege
- return 0;
- default:
- return -EINVAL;
- }
- }
- int kernel::syscall::do_mknod(const char __user* pathname, mode_t mode,
- dev_t dev) {
- mode &= S_IFMT | (~current_process->umask & 0777);
- auto [dent, status] = current_open(pathname);
- if (!dent || status != -ENOENT)
- return status;
- return fs::mknod(dent.get(), mode, dev);
- }
- int kernel::syscall::do_poll(pollfd __user* fds, nfds_t nfds, int timeout) {
- if (nfds == 0)
- return 0;
- if (nfds > 1) {
- NOT_IMPLEMENTED;
- return -EINVAL;
- }
- // TODO: handle timeout
- // if (timeout != -1) {
- // }
- (void)timeout;
- // for now, we will poll from console only
- int ret = tty::console->poll();
- if (ret < 0)
- return ret;
- fds[0].revents = POLLIN;
- return ret;
- // TODO: check address validity
- // TODO: poll multiple fds and other type of files
- // for (nfds_t i = 0; i < nfds; ++i) {
- // auto& pfd = fds[i];
- // auto* file = current_process->files[pfd.fd];
- // if (!file || !S_ISCHR(file->mode))
- // return -EINVAL;
- // // poll the fds
- // }
- //
- // return 0;
- }
- int kernel::syscall::do_socket(int domain, int type, int protocol) {
- return -EINVAL;
- }
- /* TODO: implement vfs_stat(stat*)
- int do_stat(const char __user* pathname, stat __user* buf)
- {
- auto* dent = fs::vfs_open(*current_process->root,
- types::make_path(pathname, current_process->pwd));
- if (!dent)
- return -ENOENT;
- return fs::vfs_stat(dent, buf);
- }
- */
- /* TODO: implement vfs_stat(stat*)
- int do_fstat(int fd, stat __user* buf)
- {
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- return fs::vfs_stat(file, buf);
- }
- */
|