123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- #include <asm/port_io.h>
- #include <asm/sys.h>
- #include <assert.h>
- #include <kernel/errno.h>
- #include <kernel/interrupt.h>
- #include <kernel/log.hpp>
- #include <kernel/mem.h>
- #include <kernel/mm.hpp>
- #include <kernel/process.hpp>
- #include <kernel/syscall.hpp>
- #include <kernel/tty.hpp>
- #include <kernel/vfs.hpp>
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include <types/allocator.hpp>
- #include <types/elf.hpp>
- #include <types/status.h>
- #define SYSCALL_HANDLERS_SIZE (16)
- syscall_handler syscall_handlers[SYSCALL_HANDLERS_SIZE];
- extern "C" void _syscall_stub_fork_return(void);
- int _syscall_fork(interrupt_stack* data)
- {
- auto* newproc = &procs->emplace(*current_process)->value;
- auto* newthd = &newproc->thds.Emplace(*current_thread, newproc);
- readythds->push(newthd);
- // create fake interrupt stack
- push_stack(&newthd->esp, data->ss);
- push_stack(&newthd->esp, data->esp);
- push_stack(&newthd->esp, data->eflags);
- push_stack(&newthd->esp, data->cs);
- push_stack(&newthd->esp, (uint32_t)data->v_eip);
- // eax
- push_stack(&newthd->esp, 0);
- push_stack(&newthd->esp, data->s_regs.ecx);
- // edx
- push_stack(&newthd->esp, 0);
- push_stack(&newthd->esp, data->s_regs.ebx);
- push_stack(&newthd->esp, data->s_regs.esp);
- push_stack(&newthd->esp, data->s_regs.ebp);
- push_stack(&newthd->esp, data->s_regs.esi);
- push_stack(&newthd->esp, data->s_regs.edi);
- // ctx_switch stack
- // return address
- push_stack(&newthd->esp, (uint32_t)_syscall_stub_fork_return);
- // ebx
- push_stack(&newthd->esp, 0);
- // edi
- push_stack(&newthd->esp, 0);
- // esi
- push_stack(&newthd->esp, 0);
- // ebp
- push_stack(&newthd->esp, 0);
- // eflags
- push_stack(&newthd->esp, 0);
- return newproc->pid;
- }
- int _syscall_write(interrupt_stack* data)
- {
- int fd = data->s_regs.edi;
- const char* buf = reinterpret_cast<const char*>(data->s_regs.esi);
- size_t n = data->s_regs.edx;
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- if (file->type == fs::file::types::directory)
- return -EBADF;
- int n_wrote = fs::vfs_write(file->ind, buf, file->cursor, n);
- file->cursor += n_wrote;
- return n_wrote;
- }
- int _syscall_read(interrupt_stack* data)
- {
- int fd = data->s_regs.edi;
- char* buf = reinterpret_cast<char*>(data->s_regs.esi);
- size_t n = data->s_regs.edx;
- auto* file = current_process->files[fd];
- if (!file)
- return -EBADF;
- if (file->type == fs::file::types::directory)
- return -EBADF;
- // TODO: copy to user function !IMPORTANT
- int n_wrote = fs::vfs_read(file->ind, buf, n, file->cursor, n);
- if (n_wrote >= 0)
- file->cursor += n_wrote;
- return n_wrote;
- }
- int _syscall_sleep(interrupt_stack* data)
- {
- current_thread->attr.ready = 0;
- current_thread->attr.wait = 1;
- schedule();
- return 0;
- }
- int _syscall_chdir(interrupt_stack* data)
- {
- const char* path = reinterpret_cast<const char*>(data->s_regs.edi);
- auto* dir = fs::vfs_open(path);
- if (!dir)
- return -ENOENT;
- if (!dir->ind->flags.in.directory)
- return -ENOTDIR;
- current_process->pwd = path;
- return 0;
- }
- // syscall_exec(const char* exec, const char** argv)
- // @param exec: the path of program to execute
- // @param argv: arguments end with nullptr
- // @param envp: environment variables end with nullptr
- int _syscall_exec(interrupt_stack* data)
- {
- const char* exec = reinterpret_cast<const char*>(data->s_regs.edi);
- char* const* argv = reinterpret_cast<char* const*>(data->s_regs.esi);
- char* const* envp = reinterpret_cast<char* const*>(data->s_regs.edx);
- types::elf::elf32_load_data d;
- d.argv = argv;
- d.envp = envp;
- d.exec = exec;
- d.system = false;
- int ret = types::elf::elf32_load(&d);
- if (ret != GB_OK)
- return -d.errcode;
- data->v_eip = d.eip;
- data->esp = (uint32_t)d.sp;
- return 0;
- }
- // @param exit_code
- int _syscall_exit(interrupt_stack* data)
- {
- uint32_t exit_code = data->s_regs.edi;
- // TODO: terminating a thread only
- if (current_thread->owner->thds.size() != 1) {
- assert(false);
- }
- // terminating a whole process:
- procs->kill(current_process->pid, exit_code);
- // switch to new process and continue
- schedule();
- // we should not return to here
- assert(false);
- return -1;
- }
- // @param address of exit code: int*
- // @return pid of the exited process
- int _syscall_wait(interrupt_stack* data)
- {
- auto* arg1 = reinterpret_cast<int*>(data->s_regs.edi);
- auto& waitlst = current_process->wait_lst;
- if (waitlst.empty() && !procs->has_child(current_process->pid))
- return -ECHILD;
- while (waitlst.empty()) {
- current_thread->attr.ready = 0;
- current_thread->attr.wait = 1;
- waitlst.subscribe(current_thread);
- schedule();
- if (!waitlst.empty()) {
- waitlst.unsubscribe(current_thread);
- break;
- }
- }
- auto evt = waitlst.front();
- pid_t pid = (pid_t)evt.data1;
- // TODO: copy_to_user check privilege
- *arg1 = (int)evt.data2;
- procs->remove(pid);
- return pid;
- }
- int _syscall_getdents(interrupt_stack* data)
- {
- int fd = data->s_regs.edi;
- auto* buf = (char*)(data->s_regs.esi);
- size_t cnt = data->s_regs.edx;
- auto* dir = current_process->files[fd];
- if (dir->type != fs::file::types::directory)
- return -ENOTDIR;
- size_t orig_cnt = cnt;
- int nread = dir->ind->fs->inode_readdir(dir->ind, dir->cursor,
- [&buf, &cnt](const char* fn, size_t len, fs::ino_t ino, uint8_t type) -> int {
- if (!len)
- len = strlen(fn);
- size_t reclen = sizeof(fs::user_dirent) + 1 + len;
- if (cnt < reclen)
- return GB_FAILED;
- auto* dirp = (fs::user_dirent*)buf;
- dirp->d_ino = ino;
- dirp->d_reclen = reclen;
- // TODO: show offset
- // dirp->d_off = 0;
- // TODO: use copy_to_user
- memcpy(dirp->d_name, fn, len);
- buf[reclen - 2] = 0;
- buf[reclen - 1] = type;
- buf += reclen;
- cnt -= reclen;
- return GB_OK;
- });
- if (nread > 0)
- dir->cursor += nread;
- return orig_cnt - cnt;
- }
- int _syscall_open(interrupt_stack* data)
- {
- auto* path = (const char*)data->s_regs.edi;
- uint32_t flags = data->s_regs.esi;
- return current_process->files.open(path, flags);
- }
- int _syscall_getcwd(interrupt_stack* data)
- {
- char* buf = reinterpret_cast<char*>(data->s_regs.edi);
- size_t bufsize = reinterpret_cast<size_t>(data->s_regs.esi);
- // TODO: use copy_to_user
- strncpy(buf, current_process->pwd.c_str(), bufsize);
- buf[bufsize - 1] = 0;
- return (uint32_t)buf;
- }
- int _syscall_setsid(interrupt_stack* data)
- {
- if (current_process->pid == current_process->pgid)
- return -EPERM;
- current_process->sid = current_process->pid;
- current_process->pgid = current_process->pid;
- // TODO: get tty* from fd or block device id
- procs->set_ctrl_tty(current_process->pid, console);
- return current_process->pid;
- }
- int _syscall_getsid(interrupt_stack* data)
- {
- pid_t pid = data->s_regs.edi;
- auto* proc = procs->find(pid);
- if (!proc)
- return -ESRCH;
- if (proc->sid != current_process->sid)
- return -EPERM;
- return proc->sid;
- }
- int _syscall_close(interrupt_stack* data)
- {
- int fd = data->s_regs.edi;
- current_process->files.close(fd);
- return 0;
- }
- extern "C" void syscall_entry(interrupt_stack* data)
- {
- int ret = syscall_handlers[data->s_regs.eax](data);
- data->s_regs.eax = ret;
- check_signal();
- }
- SECTION(".text.kinit")
- void init_syscall(void)
- {
- syscall_handlers[0] = _syscall_fork;
- syscall_handlers[1] = _syscall_write;
- syscall_handlers[2] = _syscall_sleep;
- syscall_handlers[3] = _syscall_chdir;
- syscall_handlers[4] = _syscall_exec;
- syscall_handlers[5] = _syscall_exit;
- syscall_handlers[6] = _syscall_wait;
- syscall_handlers[7] = _syscall_read;
- syscall_handlers[8] = _syscall_getdents;
- syscall_handlers[9] = _syscall_open;
- syscall_handlers[10] = _syscall_getcwd;
- syscall_handlers[11] = _syscall_setsid;
- syscall_handlers[12] = _syscall_getsid;
- syscall_handlers[13] = _syscall_close;
- }
|