Example #1
0
void procfs_rmentry(pid_t pid)
{
    vnode_t * pdir;
    char name[PROCFS_NAMELEN_MAX];
    struct procfs_file ** file;

    if (!vn_procfs)
        return; /* Not yet initialized. */

    uitoa32(name, pid);

    KERROR_DBG("%s(pid = %s)\n", __func__, name);

    vref(vn_procfs);

    if (vn_procfs->vnode_ops->lookup(vn_procfs, name, &pdir)) {
        KERROR_DBG("pid dir doesn't exist\n");
        goto out;
    }

    SET_FOREACH(file, procfs_files) {
        if ((*file)->filetype < PROCFS_KERNEL_SEPARATOR) {
            pdir->vnode_ops->unlink(pdir, (*file)->filename);
        }
    }


    vrele(pdir);
    if (vn_procfs->vnode_ops->rmdir(vn_procfs, name)) {
        KERROR_DBG("Can't rmdir(%s)\n", name);
    }

out:
    vrele(vn_procfs);
}
Example #2
0
struct buf * geteblk_special(size_t size, uint32_t control)
{
    struct proc_info * proc = proc_ref(0);
    const uintptr_t kvaddr = get_ksect_addr(size);
    struct buf * buf;
    int err;

    KASSERT(proc, "Can't get the PCB of pid 0");
    proc_unref(proc);

    if (kvaddr == 0) {
        KERROR_DBG("Returned kvaddr is NULL\n");
        return NULL;
    }

    buf = vm_newsect(kvaddr, size, VM_PROT_READ | VM_PROT_WRITE);
    if (!buf) {
        KERROR_DBG("vm_newsect() failed\n");
        return NULL;
    }

    buf->b_mmu.control = control;

    err = vm_insert_region(proc, buf, VM_INSOP_MAP_REG);
    if (err < 0) {
        panic("Mapping a kernel special buffer failed");
    }

    buf->b_data = buf->b_mmu.vaddr; /* Should be same as kvaddr */

    return buf;
}
Example #3
0
static pid_t proc_get_next_pid(void)
{
    const pid_t pid_reset = (configMAXPROC < 20) ? 2 :
                            (configMAXPROC < 200) ? configMAXPROC / 2 : 100;
    pid_t newpid = (proc_lastpid >= configMAXPROC) ? pid_reset :
                                                     proc_lastpid + 1;

    KERROR_DBG("%s()\n", __func__);

    PROC_LOCK();

    while (proc_exists_locked(newpid)) {
        newpid++;
        if (newpid > configMAXPROC) {
            newpid = pid_reset;
        }
    }
    proc_lastpid = newpid;

    PROC_UNLOCK();

    KERROR_DBG("%s done\n", __func__);

    return newpid;
}
Example #4
0
pid_t proc_get_random_pid(void)
{

    pid_t last_maxproc, newpid;
    int count = 0, iterations = 0;

    KERROR_DBG("%s()\n", __func__);

    PROC_LOCK();
    last_maxproc = configMAXPROC;
    newpid = last_maxproc;

    /*
     * The new PID will be "randomly" selected between proc_lastpid and
     * maxproc.
     */
    do {
        long d = last_maxproc - proc_lastpid - 1;

        if (d <= 1 || count == 20) {
            proc_lastpid = 2;
            count = 0;
            continue;
        }
        if (newpid + 1 > last_maxproc)
            newpid = proc_lastpid + kunirand(d);
        newpid++;
        count++;

        if (iterations++ > 10000) { /* Just try to find any sufficient PID. */
            iterations = 0;

            for (pid_t pid = 2; pid <= configMAXPROC; pid++) {
                if (!proc_exists_locked(newpid)) {
                    newpid = pid;
                    break;
                }
            }
        }
    } while (proc_exists_locked(newpid));

    proc_lastpid = newpid;

    PROC_UNLOCK();

    KERROR_DBG("%s done\n", __func__);

    return newpid;
}
Example #5
0
int procfs_mkentry(const struct proc_info * proc)
{
    char name[PROCFS_NAMELEN_MAX];
    vnode_t * pdir = NULL;
    struct procfs_file ** file;
    int err;

    if (!vn_procfs)
        return 0; /* Not yet initialized. */

    uitoa32(name, proc->pid);

    KERROR_DBG("%s(pid = %s)\n", __func__, name);

    err = vn_procfs->vnode_ops->mkdir(vn_procfs, name, PROCFS_PERMS);
    if (err == -EEXIST) {
        return 0;
    } else if (err) {
        goto fail;
    }

    err = vn_procfs->vnode_ops->lookup(vn_procfs, name, &pdir);
    if (err) {
        pdir = NULL;
        goto fail;
    }

    SET_FOREACH(file, procfs_files) {
        const enum procfs_filetype filetype = (*file)->filetype;

        if (filetype < PROCFS_KERNEL_SEPARATOR) {
            const char * filename = (*file)->filename;

            err = create_proc_file(pdir, proc->pid, filename, filetype);
            if (err)
                goto fail;
        }
    }

fail:
    if (pdir)
        vrele(pdir);
    if (err)
        KERROR_DBG("Failed to create a procfs entry\n");
    return err;
}
Example #6
0
static void set_proc_inher(struct proc_info * old_proc,
                           struct proc_info * new_proc)
{
    KERROR_DBG("Updating inheriance attributes of new_proc\n");

    mtx_init(&new_proc->inh.lock, PROC_INH_LOCK_TYPE, PROC_INH_LOCK_OPT);
    new_proc->inh.parent = old_proc;
    PROC_INH_INIT(new_proc);

    mtx_lock(&old_proc->inh.lock);
    PROC_INH_INSERT_HEAD(old_proc, new_proc);
    mtx_unlock(&old_proc->inh.lock);
}
Example #7
0
/**
 * Clone old process descriptor.
 */
static struct proc_info * clone_proc_info(struct proc_info * const old_proc)
{
    struct proc_info * new_proc;

    KERROR_DBG("clone proc info of pid %u\n", old_proc->pid);

    new_proc = kmalloc(sizeof(struct proc_info));
    if (!new_proc) {
        return NULL;
    }
    memcpy(new_proc, old_proc, sizeof(struct proc_info));

    return new_proc;
}
Example #8
0
static int clone_stack(struct proc_info * new_proc, struct proc_info * old_proc)
{
    struct buf * const old_region = (*old_proc->mm.regions)[MM_STACK_REGION];
    struct buf * new_region;
    int err;

    if (unlikely(!old_region)) {
        KERROR_DBG("No stack created\n");
        return 0;
    }

    err = clone2vr(old_region, &new_region);
    if (err)
        return err;

    err = vm_replace_region(new_proc, new_region, MM_STACK_REGION,
                            VM_INSOP_MAP_REG);
    return err;
}
Example #9
0
File: kinit.c Project: Zeke-OS/zeke
static pthread_t create_uinit_main(void * stack_addr)
{
    struct _sched_pthread_create_args init_ds = {
        .param.sched_policy = SCHED_OTHER,
        .param.sched_priority = NZERO,
        .stack_addr = stack_addr,
        .stack_size = configUSRINIT_SSIZE,
        .flags      = 0,
        .start      = uinit, /* We have to first get into user space to use exec
                              * and mount the rootfs.
                              */
        .arg1       = (uintptr_t)rootfs,
        .del_thread = (void (*)(void *))uinit_exit,
    };

    return thread_create(&init_ds, THREAD_MODE_PRIV);
}

/**
 * Map vmstack to proc.
 */
static void map_vmstack2proc(struct proc_info * proc, struct buf * vmstack)
{
    struct vm_pt * vpt;

    (*proc->mm.regions)[MM_STACK_REGION] = vmstack;
    vm_updateusr_ap(vmstack);

    vpt = ptlist_get_pt(&proc->mm, vmstack->b_mmu.vaddr,
                        MMU_PGSIZE_COARSE, VM_PT_CREAT);
    if (vpt == 0)
        panic("Couldn't get vpt for init stack");

    vmstack->b_mmu.pt = &(vpt->pt);
    vm_map_region(vmstack, vpt);
}

/**
 * Create init process.
 */
int __kinit__ kinit(void)
{
    SUBSYS_DEP(sched_init);
    SUBSYS_DEP(proc_init);
    SUBSYS_DEP(ramfs_init);
    SUBSYS_DEP(sysctl_init);
    SUBSYS_INIT("kinit");

    char strbuf[80]; /* Buffer for panic messages. */
    struct buf * init_vmstack;
    pthread_t tid;
    pid_t pid;
    struct thread_info * init_thread;
    struct proc_info * init_proc;


    /*
     * FIXME Memory allocation, protection or manipulation bug!
     * There is a critical bug causing random crashes in userland. I suspect
     * something is overwriting user space allocation from the kernel space.
     * Allocating some memory before init is executed seems to fix this issue,
     * however naturally this is not the proper way to fix the bug.
     * Without the allocation here the issue is sometimes seen in init or
     * usually after couple of fork + exec + exit cycles. The usual symptom is
     * that the userland app first calls some 0:0 syscalls and then tries to
     * execute undefined instruction, which probably means that either some
     * jump table in the heap or some part of the executable code is modified
     * by a bad access in kernel mode just before this happens.
     */
    (void)geteblk(MMU_PGSIZE_COARSE * 10);


    mount_tmp_rootfs();

    /*
     * User stack for init
     */
    init_vmstack = create_vmstack();
    if (!init_vmstack)
        panic("Can't allocate a stack for init");

    /*
     * Create a thread for init
     */
    tid = create_uinit_main((void *)(init_vmstack->b_mmu.paddr));
    if (tid < 0) {
        ksprintf(strbuf, sizeof(strbuf), "Can't create a thread for init. %i",
                 tid);
        panic(strbuf);
    }

    /*
     * pid of init
     */
    pid = proc_fork();
    if (pid <= 0) {
        ksprintf(strbuf, sizeof(strbuf), "Can't fork a process for init. %i",
                 pid);
        panic(strbuf);
    }

    init_thread = thread_lookup(tid);
    if (!init_thread) {
        panic("Can't get thread descriptor of init_thread!");
    }

    init_proc = proc_ref(pid);
    if (!init_proc || (init_proc->state == PROC_STATE_INITIAL)) {
        panic("Failed to get proc struct or invalid struct");
    }

    init_thread->pid_owner = pid;
    init_thread->curr_mpt = &init_proc->mm.mpt;

    /*
     * Map the previously created user stack with init process page table.
     */
    map_vmstack2proc(init_proc, init_vmstack);

    /*
     * Map tkstack of init with vm_pagetable_system.
     */
    mmu_map_region(&init_thread->kstack_region->b_mmu);
    init_proc->main_thread = init_thread;

    KERROR_DBG("Init created with pid: %u, tid: %u, stack: %p\n",
               pid, tid, (void *)init_vmstack->b_mmu.vaddr);

    proc_unref(init_proc);

    return 0;
}
Example #10
0
pid_t proc_fork(void)
{
    /*
     * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html
     */

    KERROR_DBG("%s(%u)\n", __func__, curproc->pid);

    struct proc_info * const old_proc = curproc;
    struct proc_info * new_proc;
    pid_t retval = 0;

    /* Check that the old process is in valid state. */
    if (!old_proc || old_proc->state == PROC_STATE_INITIAL)
        return -EINVAL;

    new_proc = clone_proc_info(old_proc);
    if (!new_proc)
        return -ENOMEM;

    /* Clear some things required to be zeroed at this point */
    new_proc->state = PROC_STATE_INITIAL;
    new_proc->files = NULL;
    new_proc->pgrp = NULL; /* Must be NULL so we don't free the old ref. */
    memset(&new_proc->tms, 0, sizeof(new_proc->tms));
    /* ..and then start to fix things. */

    /*
     * Process group.
     */
    PROC_LOCK();
    proc_pgrp_insert(old_proc->pgrp, new_proc);
    PROC_UNLOCK();

    /*
     *  Initialize the mm struct.
     */
    retval = vm_mm_init(&new_proc->mm, old_proc->mm.nr_regions);
    if (retval)
        goto out;

    /*
     * Clone the master page table.
     * This is probably something we would like to get rid of but we are
     * stuck with because it's the easiest way to keep some static kernel
     * mappings valid between processes.
     */
    if (mmu_ptcpy(&new_proc->mm.mpt, &old_proc->mm.mpt)) {
        retval = -EAGAIN;
        goto out;
    }

    /*
     * Clone L2 page tables.
     */
    if (vm_ptlist_clone(&new_proc->mm.ptlist_head, &new_proc->mm.mpt,
                        &old_proc->mm.ptlist_head) < 0) {
        retval = -ENOMEM;
        goto out;
    }

    retval = clone_code_region(new_proc, old_proc);
    if (retval)
        goto out;

    /*
     * Clone stack region.
     */
    retval = clone_stack(new_proc, old_proc);
    if (retval) {
        KERROR_DBG("Cloning stack region failed.\n");
        goto out;
    }

    /*
     *  Clone other regions.
     */
    retval = clone_regions_from(new_proc, old_proc, MM_HEAP_REGION);
    if (retval)
        goto out;

    /*
     * Set break values.
     */
    new_proc->brk_start = (void *)(
            (*new_proc->mm.regions)[MM_HEAP_REGION]->b_mmu.vaddr +
            (*new_proc->mm.regions)[MM_HEAP_REGION]->b_bcount);
    new_proc->brk_stop = (void *)(
            (*new_proc->mm.regions)[MM_HEAP_REGION]->b_mmu.vaddr +
            (*new_proc->mm.regions)[MM_HEAP_REGION]->b_bufsize);

    /* fork() signals */
    ksignal_signals_fork_reinit(&new_proc->sigs);

    /*
     * Copy file descriptors.
     */
    KERROR_DBG("Copy file descriptors\n");
    int nofile_max = old_proc->rlim[RLIMIT_NOFILE].rlim_max;
    if (nofile_max < 0) {
#if configRLIMIT_NOFILE < 0
#error configRLIMIT_NOFILE can't be negative.
#endif
        nofile_max = configRLIMIT_NOFILE;
    }
    new_proc->files = fs_alloc_files(nofile_max, nofile_max);
    if (!new_proc->files) {
        KERROR_DBG(
               "\tENOMEM when tried to allocate memory for file descriptors\n");
        retval = -ENOMEM;
        goto out;
    }
    /* Copy and ref old file descriptors */
    for (int i = 0; i < old_proc->files->count; i++) {
        new_proc->files->fd[i] = old_proc->files->fd[i];
        fs_fildes_ref(new_proc->files, i, 1); /* null pointer safe */
    }
    KERROR_DBG("All file descriptors copied\n");

    /*
     * Select PID.
     */
    if (likely(nprocs != 1)) { /* Tecnically it would be good idea to have lock
                                * on nprocs before reading it but I think this
                                * should work fine... */
        new_proc->pid = proc_get_random_pid();
    } else { /* Proc is init */
        KERROR_DBG("Assuming this process to be init\n");
        new_proc->pid = 1;
    }

    if (new_proc->cwd) {
        KERROR_DBG("Increment refcount for the cwd\n");
        vref(new_proc->cwd); /* Increment refcount for the cwd */
    }

    /* Update inheritance attributes */
    set_proc_inher(old_proc, new_proc);

    /* Insert the new process into the process array */
    procarr_insert(new_proc);

    /*
     * A process shall be created with a single thread. If a multi-threaded
     * process calls fork(), the new process shall contain a replica of the
     * calling thread.
     * We left main_thread null if calling process has no main thread.
     */
    KERROR_DBG("Handle main_thread\n");
    if (old_proc->main_thread) {
        KERROR_DBG("Call thread_fork() to get a new main thread for the fork.\n");
        if (!(new_proc->main_thread = thread_fork(new_proc->pid))) {
            KERROR_DBG("\tthread_fork() failed\n");
            retval = -EAGAIN;
            goto out;
        }

        KERROR_DBG("\tthread_fork() fork OK\n");

        /*
         * We set new proc's mpt as the current mpt because the new main thread
         * is going to return directly to the user space.
         */
        new_proc->main_thread->curr_mpt = &new_proc->mm.mpt;
    } else {
        KERROR_DBG("No thread to fork.\n");
        new_proc->main_thread = NULL;
    }
    retval = new_proc->pid;

    new_proc->state = PROC_STATE_READY;

#ifdef configPROCFS
    procfs_mkentry(new_proc);
#endif

    if (new_proc->main_thread) {
        KERROR_DBG("Set the new main_thread (%d) ready\n",
                   new_proc->main_thread->id);
        thread_ready(new_proc->main_thread->id);
    }

    KERROR_DBG("Fork %d -> %d created.\n", old_proc->pid, new_proc->pid);

out:
    if (unlikely(retval < 0)) {
        _proc_free(new_proc);
    }
    return retval;
}