| 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 atomicssize_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);}*/
 |