akaros/kern/src/env.c
<<
>>
Prefs
   1/* See COPYRIGHT for copyright information. */
   2
   3#include <arch/arch.h>
   4#include <arch/mmu.h>
   5#include <bitmask.h>
   6#include <elf.h>
   7#include <smp.h>
   8#include <atomic.h>
   9#include <string.h>
  10#include <assert.h>
  11#include <process.h>
  12#include <pmap.h>
  13#include <trap.h>
  14#include <monitor.h>
  15#include <manager.h>
  16#include <stdio.h>
  17#include <schedule.h>
  18#include <kmalloc.h>
  19#include <mm.h>
  20
  21#include <ros/syscall.h>
  22#include <error.h>
  23
  24atomic_t num_envs;
  25
  26// Initialize the kernel virtual memory layout for environment e.
  27// Allocate a page directory, set e->env_pgdir and e->env_cr3 accordingly,
  28// and initialize the kernel portion of the new environment's address space.
  29// Do NOT (yet) map anything into the user portion
  30// of the environment's virtual address space.
  31//
  32// Returns 0 on success, < 0 on error.  Errors include:
  33//      -ENOMEM if page directory or table could not be allocated.
  34//
  35int env_setup_vm(env_t *e)
  36{
  37        int i, ret;
  38        static page_t *shared_page = 0;
  39
  40        if ((ret = arch_pgdir_setup(boot_pgdir, &e->env_pgdir)))
  41                return ret;
  42        e->env_cr3 = arch_pgdir_get_cr3(e->env_pgdir);
  43
  44        /* These need to be contiguous, so the kernel can alias them.  Note the
  45         * pages return with a refcnt, but it's okay to insert them since we
  46         * free them manually when the process is cleaned up. */
  47        if (!(e->procinfo = kpages_alloc(PROCINFO_NUM_PAGES * PGSIZE,
  48                                         MEM_WAIT)))
  49                goto env_setup_vm_error_i;
  50        if (!(e->procdata = kpages_alloc(PROCDATA_NUM_PAGES * PGSIZE,
  51                                         MEM_WAIT)))
  52                goto env_setup_vm_error_d;
  53        /* Normally we would 0 the pages here.  We handle it in proc_init_proc*.
  54         * Do not start the process without calling those. */
  55        for (int i = 0; i < PROCINFO_NUM_PAGES; i++) {
  56                if (page_insert(e->env_pgdir,
  57                                kva2page((void*)e->procinfo + i * PGSIZE),
  58                                (void*)(UINFO + i * PGSIZE), PTE_USER_RO) < 0)
  59                        goto env_setup_vm_error;
  60        }
  61        for (int i = 0; i < PROCDATA_NUM_PAGES; i++) {
  62                if (page_insert(e->env_pgdir,
  63                                kva2page((void*)e->procdata + i * PGSIZE),
  64                                (void*)(UDATA + i * PGSIZE), PTE_USER_RW) < 0)
  65                        goto env_setup_vm_error;
  66        }
  67        for (int i = 0; i < PROCGINFO_NUM_PAGES; i++) {
  68                if (page_insert(e->env_pgdir,
  69                                kva2page((void*)&__proc_global_info
  70                                         + i * PGSIZE),
  71                                (void*)(UGINFO + i * PGSIZE), PTE_USER_RO) < 0)
  72                        goto env_setup_vm_error;
  73        }
  74        /* Finally, set up the Global Shared Data page for all processes.  Can't
  75         * be trusted, but still very useful at this stage for us.  Consider
  76         * removing when we have real processes (TODO).
  77         *
  78         * Note the page is alloced only the first time through, and its ref is
  79         * stored in shared_page. */
  80        if (!shared_page) {
  81                if (upage_alloc(e, &shared_page, 1) < 0)
  82                        goto env_setup_vm_error;
  83        }
  84        if (page_insert(e->env_pgdir, shared_page, (void*)UGDATA, PTE_USER_RW)
  85            < 0)
  86                goto env_setup_vm_error;
  87
  88        return 0;
  89
  90env_setup_vm_error:
  91        kpages_free(e->procdata, PROCDATA_NUM_PAGES * PGSIZE);
  92env_setup_vm_error_d:
  93        kpages_free(e->procinfo, PROCINFO_NUM_PAGES * PGSIZE);
  94env_setup_vm_error_i:
  95        env_user_mem_free(e, 0, UVPT);
  96        env_pagetable_free(e);
  97        return -ENOMEM;
  98}
  99
 100/* Frees (decrefs) all memory mapped in the given range */
 101void env_user_mem_free(env_t* e, void* start, size_t len)
 102{
 103        assert((uintptr_t)start + len <= UVPT);
 104        int user_page_free(env_t* e, pte_t pte, void* va, void* arg)
 105        {
 106                if (!pte_is_mapped(pte))
 107                        return 0;
 108                page_t *page = pa2page(pte_get_paddr(pte));
 109                pte_clear(pte);
 110                page_decref(page);
 111                /* TODO: consider other states here (like !P, yet still tracking
 112                 * a page, for VM tricks, page map stuff, etc.  Should be okay:
 113                 * once we're freeing, everything else about this proc is dead.
 114                 * */
 115                return 0;
 116        }
 117
 118        env_user_mem_walk(e,start,len,&user_page_free,NULL);
 119        tlbflush();
 120}
 121
 122void set_username(struct username *u, char *name)
 123{
 124        ERRSTACK(1);
 125
 126        spin_lock(&u->name_lock);
 127
 128        if (waserror()) {
 129                spin_unlock(&u->name_lock);
 130                nexterror();
 131        }
 132
 133        __set_username(u, name);
 134
 135        poperror();
 136        spin_unlock(&u->name_lock);
 137}
 138
 139/*
 140 * This function exists so that you can do your own locking - do not use it
 141 * without locking the username's spinlock yourself.
 142 */
 143void __set_username(struct username *u, char *name)
 144{
 145        if (!name)
 146                error(EINVAL, "New username is NULL");
 147
 148        if (strlen(name) > sizeof(u->name) - 1)
 149                error(EINVAL,
 150                      "New username for process more than %d chars long",
 151                      sizeof(u->name) - 1);
 152
 153        // 'backward' copy since reads aren't protected
 154        u->name[0] = 0;
 155        wmb(); // ensure user.name="" before writing the rest of the new name
 156        strlcpy(&u->name[1], &name[1], sizeof(u->name));
 157        wmb(); // ensure new name is written before writing first byte
 158        u->name[0] = name[0];
 159}
 160