Changes pde_t* -> pgdir_t
[akaros.git] / kern / src / env.c
1 /* See COPYRIGHT for copyright information. */
2
3 #ifdef __SHARC__
4 #pragma nosharc
5 #endif
6
7 #include <arch/arch.h>
8 #include <arch/mmu.h>
9 #include <bitmask.h>
10 #include <elf.h>
11 #include <smp.h>
12 #include <atomic.h>
13 #include <string.h>
14 #include <assert.h>
15 #include <process.h>
16 #include <pmap.h>
17 #include <trap.h>
18 #include <monitor.h>
19 #include <manager.h>
20 #include <stdio.h>
21 #include <schedule.h>
22 #include <kmalloc.h>
23 #include <mm.h>
24
25 #include <ros/syscall.h>
26 #include <error.h>
27
28 atomic_t num_envs;
29
30 // Initialize the kernel virtual memory layout for environment e.
31 // Allocate a page directory, set e->env_pgdir and e->env_cr3 accordingly,
32 // and initialize the kernel portion of the new environment's address space.
33 // Do NOT (yet) map anything into the user portion
34 // of the environment's virtual address space.
35 //
36 // Returns 0 on success, < 0 on error.  Errors include:
37 //      -ENOMEM if page directory or table could not be allocated.
38 //
39 int env_setup_vm(env_t *e)
40 WRITES(e->env_pgdir, e->env_cr3, e->procinfo, e->procdata)
41 {
42         int i, ret;
43         static page_t * RO shared_page = 0;
44
45         if ((ret = arch_pgdir_setup(boot_pgdir, &e->env_pgdir)))
46                 return ret;
47         /* TODO: verify there is nothing below ULIM */
48         e->env_cr3 = arch_pgdir_get_cr3(e->env_pgdir);
49
50         /* These need to be contiguous, so the kernel can alias them.  Note the
51          * pages return with a refcnt, but it's okay to insert them since we free
52          * them manually when the process is cleaned up. */
53         if (!(e->procinfo = get_cont_pages(LOG2_UP(PROCINFO_NUM_PAGES), 0)))
54                 goto env_setup_vm_error_i;
55         if (!(e->procdata = get_cont_pages(LOG2_UP(PROCDATA_NUM_PAGES), 0)))
56                 goto env_setup_vm_error_d;
57         /* Normally we'd 0 the pages here.  We handle it in proc_init_proc*.  Don't
58          * start the process without calling those. */
59         for (int i = 0; i < PROCINFO_NUM_PAGES; i++) {
60                 if (page_insert(e->env_pgdir, kva2page((void*)e->procinfo + i *
61                                 PGSIZE), (void*SNT)(UINFO + i*PGSIZE), PTE_USER_RO) < 0)
62                         goto env_setup_vm_error;
63         }
64         for (int i = 0; i < PROCDATA_NUM_PAGES; i++) {
65                 if (page_insert(e->env_pgdir, kva2page((void*)e->procdata + i *
66                                 PGSIZE), (void*SNT)(UDATA + i*PGSIZE), PTE_USER_RW) < 0)
67                         goto env_setup_vm_error;
68         }
69         /* Finally, set up the Global Shared Data page for all processes.  Can't be
70          * trusted, but still very useful at this stage for us.  Consider removing
71          * when we have real processes (TODO). 
72          *
73          * Note the page is alloced only the first time through, and its ref is
74          * stored in shared_page. */
75         if (!shared_page) {
76                 if (upage_alloc(e, &shared_page, 1) < 0)
77                         goto env_setup_vm_error;
78         }
79         if (page_insert(e->env_pgdir, shared_page, (void*)UGDATA, PTE_USER_RW) < 0)
80                 goto env_setup_vm_error;
81
82         return 0;
83
84 env_setup_vm_error:
85         free_cont_pages(e->procdata, LOG2_UP(PROCDATA_NUM_PAGES));
86 env_setup_vm_error_d:
87         free_cont_pages(e->procinfo, LOG2_UP(PROCINFO_NUM_PAGES));
88 env_setup_vm_error_i:
89         page_decref(shared_page);
90         env_user_mem_free(e, 0, UVPT);
91         env_pagetable_free(e);
92         return -ENOMEM;
93 }
94
95 #define PER_CPU_THING(type,name)\
96 type SLOCKED(name##_lock) * RWPROTECT name;\
97 type SLOCKED(name##_lock) *\
98 (get_per_cpu_##name)()\
99 {\
100         { R_PERMITTED(global(name))\
101                 return &name[core_id()];\
102         }\
103 }
104
105 /* Frees (decrefs) all memory mapped in the given range */
106 void env_user_mem_free(env_t* e, void* start, size_t len)
107 {
108         assert((uintptr_t)start + len <= UVPT); //since this keeps fucking happening
109         int user_page_free(env_t* e, pte_t pte, void* va, void* arg)
110         {
111                 if (!pte_is_present(pte))
112                         return 0;
113                 page_t *page = pa2page(pte_get_paddr(pte));
114                 pte_clear(pte);
115                 page_decref(page);
116                 /* TODO: consider other states here (like !P, yet still tracking a page,
117                  * for VM tricks, page map stuff, etc.  Should be okay: once we're
118                  * freeing, everything else about this proc is dead. */
119                 return 0;
120         }
121
122         env_user_mem_walk(e,start,len,&user_page_free,NULL);
123         tlbflush();
124 }
125