New vcoremap in procinfo
[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 <arch/bitmask.h>
10 #include <elf.h>
11 #include <smp.h>
12
13 #include <atomic.h>
14 #include <string.h>
15 #include <assert.h>
16 #include <process.h>
17 #include <pmap.h>
18 #include <trap.h>
19 #include <monitor.h>
20 #include <manager.h>
21 #include <stdio.h>
22 #include <schedule.h>
23 #include <kmalloc.h>
24 #include <mm.h>
25
26 #include <ros/syscall.h>
27 #include <error.h>
28
29 atomic_t num_envs;
30
31 // Initialize the kernel virtual memory layout for environment e.
32 // Allocate a page directory, set e->env_pgdir and e->env_cr3 accordingly,
33 // and initialize the kernel portion of the new environment's address space.
34 // Do NOT (yet) map anything into the user portion
35 // of the environment's virtual address space.
36 //
37 // Returns 0 on success, < 0 on error.  Errors include:
38 //      -ENOMEM if page directory or table could not be allocated.
39 //
40 int env_setup_vm(env_t *e)
41 WRITES(e->env_pgdir, e->env_cr3, e->procinfo, e->procdata)
42 {
43         int i, r;
44         page_t *pgdir = NULL;
45         static page_t * RO shared_page = 0;
46
47         /*
48          * First, allocate a page for the pgdir of this process and up
49          * its reference count since this will never be done elsewhere
50          */
51         r = kpage_alloc(&pgdir);
52         if(r < 0) return r;
53
54         /*
55          * Next, set up the e->env_pgdir and e->env_cr3 pointers to point
56          * to this newly allocated page and clear its contents
57          */
58         memset(page2kva(pgdir), 0, PGSIZE);
59         e->env_pgdir = (pde_t *COUNT(NPDENTRIES)) TC(page2kva(pgdir));
60         e->env_cr3 =   (physaddr_t) TC(page2pa(pgdir));
61
62         /*
63          * Now start filling in the pgdir with mappings required by all newly
64          * created address spaces
65          */
66
67         // Map in the kernel to the top of every address space
68         // should be able to do this so long as boot_pgdir never has
69         // anything put below UTOP
70         // TODO check on this!  had a nasty bug because of it
71         // this is a bit wonky, since if it's not PGSIZE, lots of other things are
72         // screwed up...
73         memcpy(e->env_pgdir, boot_pgdir, NPDENTRIES*sizeof(pde_t));
74
75         // VPT and UVPT map the env's own page table, with
76         // different permissions.
77         e->env_pgdir[PDX(VPT)]  = PTE(LA2PPN(e->env_cr3), PTE_P | PTE_KERN_RW);
78         e->env_pgdir[PDX(UVPT)] = PTE(LA2PPN(e->env_cr3), PTE_P | PTE_USER_RO);
79
80         /* These need to be contiguous, so the kernel can alias them.  Note the
81          * pages return with a refcnt, but it's okay to insert them since we free
82          * them manually when the process is cleaned up. */
83         if (!(e->procinfo = get_cont_pages(LOG2_UP(PROCINFO_NUM_PAGES), 0)))
84                 goto env_setup_vm_error_i;
85         if (!(e->procdata = get_cont_pages(LOG2_UP(PROCDATA_NUM_PAGES), 0)))
86                 goto env_setup_vm_error_d;
87         for (int i = 0; i < PROCINFO_NUM_PAGES; i++) {
88                 if (page_insert(e->env_pgdir, kva2page((void*)e->procinfo + i *
89                                 PGSIZE), (void*SNT)(UINFO + i*PGSIZE), PTE_USER_RO) < 0)
90                         goto env_setup_vm_error;
91         }
92         for (int i = 0; i < PROCDATA_NUM_PAGES; i++) {
93                 if (page_insert(e->env_pgdir, kva2page((void*)e->procdata + i *
94                                 PGSIZE), (void*SNT)(UDATA + i*PGSIZE), PTE_USER_RW) < 0)
95                         goto env_setup_vm_error;
96         }
97         memset(e->procinfo, 0, sizeof(struct procinfo));
98         memset(e->procdata, 0, sizeof(struct procdata));
99
100         /* Finally, set up the Global Shared Data page for all processes.
101          * Can't be trusted, but still very useful at this stage for us.
102          * Consider removing when we have real processes.
103          * (TODO).  Note the page is alloced only the first time through
104          */
105         if (!shared_page) {
106                 if(upage_alloc(e, &shared_page,1) < 0)
107                         goto env_setup_vm_error;
108                 // Up it, so it never goes away.  One per user, plus one from page_alloc
109                 // This is necessary, since it's in the per-process range of memory that
110                 // gets freed during page_free.
111                 page_incref(shared_page);
112         }
113
114         // Inserted into every process's address space at UGDATA
115         if(page_insert(e->env_pgdir, shared_page, (void*SNT)UGDATA, PTE_USER_RW) < 0)
116                 goto env_setup_vm_error;
117
118         return 0;
119
120 env_setup_vm_error:
121         free_cont_pages(e->procdata, LOG2_UP(PROCDATA_NUM_PAGES));
122 env_setup_vm_error_d:
123         free_cont_pages(e->procinfo, LOG2_UP(PROCINFO_NUM_PAGES));
124 env_setup_vm_error_i:
125         page_decref(shared_page);
126         env_user_mem_free(e, 0, UVPT);
127         env_pagetable_free(e);
128         return -ENOMEM;
129 }
130
131 // this helper function handles all cases of copying to/from user/kernel
132 // or between two users.
133 static error_t load_icode_memcpy(struct proc *dest_p, struct proc *src_p,
134                                  void* dest, const void* src, size_t len)
135 {
136         if(src < (void*)UTOP)
137         {
138                 if(src_p == NULL)
139                         return -EFAULT;
140
141                 if(dest_p == NULL)
142                         return memcpy_from_user(src_p, dest, src, len);
143                 else
144                 {
145                         // TODO: do something more elegant & faster here.
146                         // e.g. a memcpy_from_user_to_user
147                         uint8_t kbuf[1024];
148                         while(len > 0)
149                         {
150                                 size_t thislen = MIN(len,sizeof(kbuf));
151                                 if (memcpy_from_user(src_p, kbuf, src, thislen))
152                                         return -EFAULT;
153                                 if (memcpy_to_user(dest_p, dest, kbuf, thislen))
154                                         panic("destination env isn't mapped!");
155                                 len -= thislen;
156                                 src += thislen;
157                                 dest += thislen;
158                         }
159                         return ESUCCESS;
160                 }
161
162         }
163         else
164         {
165                 if(src_p != NULL)
166                         return -EFAULT;
167
168                 if(dest_p == NULL)
169                         memcpy(dest, src, len);
170                 else if(memcpy_to_user(dest_p, dest, src, len))
171                         panic("destination env isn't mapped!");
172
173                 return ESUCCESS;
174         }
175 }
176
177 //
178 // Set up the initial program binary, stack, and processor flags
179 // for a user process.
180 //
181 // This function loads all loadable segments from the ELF binary image
182 // into the environment's user memory, starting at the appropriate
183 // virtual addresses indicated in the ELF program header.
184 // At the same time it clears to zero any portions of these segments
185 // that are marked in the program header as being mapped
186 // but not actually present in the ELF file - i.e., the program's bss section.
187 //
188 // Finally, this function maps one page for the program's initial stack.
189 static void* load_icode(env_t *SAFE e, env_t* binary_env,
190                         uint8_t *COUNT(size) binary, size_t size)
191 {
192         // asw: copy the headers because they might not be aligned.
193         elf_t elfhdr;
194         proghdr_t phdr;
195         void* _end = 0;
196
197         assert(load_icode_memcpy(NULL,binary_env,&elfhdr, binary,
198                                  sizeof(elfhdr)) == ESUCCESS);
199
200         int i, r;
201
202         // is this an elf?
203         assert(elfhdr.e_magic == ELF_MAGIC);
204         // make sure we have proghdrs to load
205         assert(elfhdr.e_phnum);
206
207         // TODO: how do we do a runtime COUNT?
208         {TRUSTEDBLOCK // zra: TRUSTEDBLOCK until validation is done.
209         for (i = 0; i < elfhdr.e_phnum; i++) {
210                 // copy phdr to kernel mem
211                 assert(load_icode_memcpy(NULL,binary_env,&phdr, binary + elfhdr.e_phoff + i*sizeof(phdr), sizeof(phdr)) == ESUCCESS);
212
213                 if (phdr.p_type != ELF_PROG_LOAD)
214                         continue;
215                 // TODO: validate elf header fields!
216                 // seg alloc creates PTE_U|PTE_W pages.  if you ever want to change
217                 // this, there will be issues with overlapping sections
218                 _end = MAX(_end, (void*)(phdr.p_va + phdr.p_memsz));
219
220                 // use mmap to allocate memory.  don't clobber other sections.
221                 // this is ugly but will go away once we stop using load_icode
222                 uintptr_t pgstart = ROUNDDOWN((uintptr_t)phdr.p_va,PGSIZE);
223                 uintptr_t pgend = ROUNDUP((uintptr_t)phdr.p_va+phdr.p_memsz,PGSIZE);
224                 for(uintptr_t addr = pgstart; addr < pgend; addr += PGSIZE)
225                 {
226                         pte_t* pte = pgdir_walk(e->env_pgdir, (void*)addr, 0);
227                         if(!pte || PAGE_UNMAPPED(*pte))
228                                 assert(do_mmap(e,addr,PGSIZE,PROT_READ|PROT_WRITE|PROT_EXEC,
229                                            MAP_ANONYMOUS|MAP_FIXED,NULL,0) != MAP_FAILED);
230                 }
231
232                 // copy section to user mem
233                 assert(load_icode_memcpy(e,binary_env,(void*)phdr.p_va, binary + phdr.p_offset, phdr.p_filesz) == ESUCCESS);
234
235                 //no need to memclr the remaining p_memsz-p_filesz bytes
236                 //because upage_alloc'd pages are zeroed
237         }}
238
239         proc_init_trapframe(&e->env_tf, 0, elfhdr.e_entry, USTACKTOP);
240         e->env_entry = elfhdr.e_entry;
241
242         // Now map USTACK_NUM_PAGES pages for the program's initial stack
243         // starting at virtual address USTACKTOP - USTACK_NUM_PAGES*PGSIZE.
244         uintptr_t stacksz = USTACK_NUM_PAGES*PGSIZE;
245         assert(do_mmap(e, USTACKTOP-stacksz, stacksz, PROT_READ | PROT_WRITE,
246                        MAP_FIXED | MAP_ANONYMOUS | MAP_POPULATE, NULL, 0)
247                != MAP_FAILED);
248         
249         return _end;
250 }
251
252 void env_load_icode(env_t* e, env_t* binary_env, uint8_t* binary, size_t size)
253 {
254         /* Load the binary and set the current locations of the elf segments.
255          * All end-of-segment pointers are page aligned (invariant) */
256         e->heap_top = load_icode(e, binary_env, binary, size);
257         e->procinfo->heap_bottom = e->heap_top;
258 }
259
260 #define PER_CPU_THING(type,name)\
261 type SLOCKED(name##_lock) * RWPROTECT name;\
262 type SLOCKED(name##_lock) *\
263 (get_per_cpu_##name)()\
264 {\
265         { R_PERMITTED(global(name))\
266                 return &name[core_id()];\
267         }\
268 }
269
270 /* This is the top-half of an interrupt handler, where the bottom half is
271  * proc_run (which never returns).  Just add it to the delayed work queue,
272  * which (incidentally) can only hold one item at this point.
273  *
274  * Note this is rather old, and meant to run a RUNNABLE_S on a worker core.
275  */
276 #ifdef __IVY__
277 void run_env_handler(trapframe_t *tf, env_t * data)
278 #else
279 void run_env_handler(trapframe_t *tf, void * data)
280 #endif
281 {
282         assert(data);
283         struct work TP(env_t *) job;
284         struct workqueue TP(env_t *) *CT(1) workqueue =
285             TC(&per_cpu_info[core_id()].workqueue);
286         // this doesn't work, and making it a TP(env_t) is wrong
287         // zra: When you want to use other types, let me know, and I can help
288     // make something that Ivy is happy with. 
289 #ifdef __IVY__
290         job.func = proc_run;
291 #else
292         job.func = (func_t)proc_run;
293 #endif
294         job.data = data;
295         if (enqueue_work(workqueue, &job))
296                 panic("Failed to enqueue work!");
297 }
298
299 /* Frees (decrefs) all memory mapped in the given range */
300 void env_user_mem_free(env_t* e, void* start, size_t len)
301 {
302         assert((uintptr_t)start + len <= UVPT); //since this keeps fucking happening
303         int user_page_free(env_t* e, pte_t* pte, void* va, void* arg)
304         {
305                 if(PAGE_PRESENT(*pte))
306                 {
307                         page_t* page = ppn2page(PTE2PPN(*pte));
308                         *pte = 0;
309                         page_decref(page);
310                 }
311                 else // PAGE_PAGED_OUT(*pte)
312                 {
313                         pfault_info_free(PTE2PFAULT_INFO(*pte));
314                         *pte = 0;
315                 }
316                 return 0;
317         }
318
319         env_user_mem_walk(e,start,len,&user_page_free,NULL);
320         tlbflush();
321 }
322