Added demand paging support
[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 <ros/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->env_procinfo, e->env_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->env_procinfo = get_cont_pages(LOG2_UP(PROCINFO_NUM_PAGES), 0)))
84                 goto env_setup_vm_error_i;
85         if (!(e->env_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->env_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->env_procdata + i *
94                                 PGSIZE), (void*SNT)(UDATA + i*PGSIZE), PTE_USER_RW) < 0)
95                         goto env_setup_vm_error;
96         }
97         memset(e->env_procinfo, 0, sizeof(procinfo_t));
98         memset(e->env_procdata, 0, sizeof(procdata_t));
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->env_procdata, LOG2_UP(PROCDATA_NUM_PAGES));
122 env_setup_vm_error_d:
123         free_cont_pages(e->env_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 // Allocate len bytes of physical memory for environment env,
132 // and map it at virtual address va in the environment's address space.
133 // Pages are zeroed by upage_alloc.
134 // Pages should be writable by user and kernel.
135 // Panic if any allocation attempt fails.
136 //
137 void
138 env_segment_alloc(env_t *e, void *SNT va, size_t len)
139 {
140         void *SNT start, *SNT end;
141         size_t num_pages;
142         int i, r;
143         page_t *page;
144         pte_t *pte;
145
146         start = ROUNDDOWN(va, PGSIZE);
147         end = ROUNDUP(va + len, PGSIZE);
148         if (start >= end)
149                 panic("Wrap-around in memory allocation addresses!");
150         if ((uintptr_t)end > UTOP)
151                 panic("Attempting to map above UTOP!");
152         num_pages = LA2PPN(end - start);
153
154         for (i = 0; i < num_pages; i++, start += PGSIZE) {
155                 // skip if a page is already mapped.  yes, page_insert will page_remove
156                 // whatever page was already there, but if we are seg allocing adjacent
157                 // regions, we don't want to destroy that old mapping/page
158                 // though later on we are told we can ignore this...
159                 pte = pgdir_walk(e->env_pgdir, start, 0);
160                 if (pte && *pte & PTE_P)
161                         continue;
162                 if ((r = upage_alloc(e, &page, 1)) < 0)
163                         panic("env_segment_alloc: %e", r);
164                 page_insert(e->env_pgdir, page, start, PTE_USER_RW);
165         }
166 }
167
168 void
169 env_segment_free(env_t *e, void *SNT va, size_t len)
170 {
171         void *SNT start, *SNT end;
172         size_t num_pages;
173         page_t *page;
174         pte_t *pte;
175
176         // Round this up this time so we don't free the page that va is actually on
177         start = ROUNDUP(va, PGSIZE);
178         end = ROUNDUP(va + len, PGSIZE);
179         if (start >= end)
180                 panic("Wrap-around in memory free addresses!");
181         if ((uintptr_t)end > UTOP)
182                 panic("Attempting to unmap above UTOP!");
183         // page_insert/pgdir_walk alloc a page and read/write to it via its address
184         // starting from pgdir (e's), so we need to be using e's pgdir
185         assert(e->env_cr3 == rcr3());
186         num_pages = LA2PPN(end - start);
187
188         env_user_mem_free(e,start,(char*)end-(char*)start);
189 }
190
191 // this helper function handles all cases of copying to/from user/kernel
192 // or between two users.
193 static error_t load_icode_memcpy(struct proc *dest_p, struct proc *src_p,
194                                  void* dest, const void* src, size_t len)
195 {
196         if(src < (void*)UTOP)
197         {
198                 if(src_p == NULL)
199                         return -EFAULT;
200
201                 if(dest_p == NULL)
202                         return memcpy_from_user(src_p, dest, src, len);
203                 else
204                 {
205                         // TODO: do something more elegant & faster here.
206                         // e.g. a memcpy_from_user_to_user
207                         uint8_t kbuf[1024];
208                         while(len > 0)
209                         {
210                                 size_t thislen = MIN(len,sizeof(kbuf));
211                                 if (memcpy_from_user(src_p, kbuf, src, thislen))
212                                         return -EFAULT;
213                                 if (memcpy_to_user(dest_p, dest, kbuf, thislen))
214                                         panic("destination env isn't mapped!");
215                                 len -= thislen;
216                                 src += thislen;
217                                 dest += thislen;
218                         }
219                         return ESUCCESS;
220                 }
221
222         }
223         else
224         {
225                 if(src_p != NULL)
226                         return -EFAULT;
227
228                 if(dest_p == NULL)
229                         memcpy(dest, src, len);
230                 else if(memcpy_to_user(dest_p, dest, src, len))
231                         panic("destination env isn't mapped!");
232
233                 return ESUCCESS;
234         }
235 }
236
237 //
238 // Set up the initial program binary, stack, and processor flags
239 // for a user process.
240 //
241 // This function loads all loadable segments from the ELF binary image
242 // into the environment's user memory, starting at the appropriate
243 // virtual addresses indicated in the ELF program header.
244 // At the same time it clears to zero any portions of these segments
245 // that are marked in the program header as being mapped
246 // but not actually present in the ELF file - i.e., the program's bss section.
247 //
248 // Finally, this function maps one page for the program's initial stack.
249 static void* load_icode(env_t *SAFE e, env_t* binary_env,
250                         uint8_t *COUNT(size) binary, size_t size)
251 {
252         // asw: copy the headers because they might not be aligned.
253         elf_t elfhdr;
254         proghdr_t phdr;
255         void* _end = 0;
256
257         assert(load_icode_memcpy(NULL,binary_env,&elfhdr, binary,
258                                  sizeof(elfhdr)) == ESUCCESS);
259
260         int i, r;
261
262         // is this an elf?
263         assert(elfhdr.e_magic == ELF_MAGIC);
264         // make sure we have proghdrs to load
265         assert(elfhdr.e_phnum);
266
267         // TODO: how do we do a runtime COUNT?
268         {TRUSTEDBLOCK // zra: TRUSTEDBLOCK until validation is done.
269         for (i = 0; i < elfhdr.e_phnum; i++) {
270                 // copy phdr to kernel mem
271                 assert(load_icode_memcpy(NULL,binary_env,&phdr, binary + elfhdr.e_phoff + i*sizeof(phdr), sizeof(phdr)) == ESUCCESS);
272
273                 if (phdr.p_type != ELF_PROG_LOAD)
274                         continue;
275                 // TODO: validate elf header fields!
276                 // seg alloc creates PTE_U|PTE_W pages.  if you ever want to change
277                 // this, there will be issues with overlapping sections
278                 _end = MAX(_end, (void*)(phdr.p_va + phdr.p_memsz));
279                 env_segment_alloc(e, (void*SNT)phdr.p_va, phdr.p_memsz);
280
281                 // copy section to user mem
282                 assert(load_icode_memcpy(e,binary_env,(void*)phdr.p_va, binary + phdr.p_offset, phdr.p_filesz) == ESUCCESS);
283
284                 //no need to memclr the remaining p_memsz-p_filesz bytes
285                 //because upage_alloc'd pages are zeroed
286         }}
287
288         proc_init_trapframe(&e->env_tf, 0, elfhdr.e_entry, USTACKTOP);
289         e->env_entry = elfhdr.e_entry;
290
291         // Now map USTACK_NUM_PAGES pages for the program's initial stack
292         // starting at virtual address USTACKTOP - USTACK_NUM_PAGES*PGSIZE.
293         env_segment_alloc(e, (void*SNT)(USTACKTOP - USTACK_NUM_PAGES*PGSIZE), 
294                           USTACK_NUM_PAGES*PGSIZE);
295         
296         return _end;
297 }
298
299 void env_load_icode(env_t* e, env_t* binary_env, uint8_t* binary, size_t size)
300 {
301         /* Load the binary and set the current locations of the elf segments.
302          * All end-of-segment pointers are page aligned (invariant) */
303         e->heap_bottom = load_icode(e, binary_env, binary, size);
304         e->heap_top = e->heap_bottom;
305 }
306
307 #define PER_CPU_THING(type,name)\
308 type SLOCKED(name##_lock) * RWPROTECT name;\
309 type SLOCKED(name##_lock) *\
310 (get_per_cpu_##name)()\
311 {\
312         { R_PERMITTED(global(name))\
313                 return &name[core_id()];\
314         }\
315 }
316
317 /* This is the top-half of an interrupt handler, where the bottom half is
318  * proc_run (which never returns).  Just add it to the delayed work queue,
319  * which (incidentally) can only hold one item at this point.
320  *
321  * Note this is rather old, and meant to run a RUNNABLE_S on a worker core.
322  */
323 #ifdef __IVY__
324 void run_env_handler(trapframe_t *tf, env_t * data)
325 #else
326 void run_env_handler(trapframe_t *tf, void * data)
327 #endif
328 {
329         assert(data);
330         struct work TP(env_t *) job;
331         struct workqueue TP(env_t *) *CT(1) workqueue =
332             TC(&per_cpu_info[core_id()].workqueue);
333         // this doesn't work, and making it a TP(env_t) is wrong
334         // zra: When you want to use other types, let me know, and I can help
335     // make something that Ivy is happy with. 
336 #ifdef __IVY__
337         job.func = proc_run;
338 #else
339         job.func = (func_t)proc_run;
340 #endif
341         job.data = data;
342         if (enqueue_work(workqueue, &job))
343                 panic("Failed to enqueue work!");
344 }
345
346 /* Frees (decrefs) all memory mapped in the given range */
347 void env_user_mem_free(env_t* e, void* start, size_t len)
348 {
349         assert((uintptr_t)start + len <= UVPT); //since this keeps fucking happening
350         int user_page_free(env_t* e, pte_t* pte, void* va, void* arg)
351         {
352                 if(PAGE_PRESENT(*pte))
353                 {
354                         page_t* page = ppn2page(PTE2PPN(*pte));
355                         *pte = 0;
356                         page_decref(page);
357                 }
358                 else // PAGE_PAGED_OUT(*pte)
359                 {
360                         pfault_info_free(PTE2PFAULT_INFO(*pte));
361                         *pte = 0;
362                 }
363                 return 0;
364         }
365
366         env_user_mem_walk(e,start,len,&user_page_free,NULL);
367         tlbflush();
368 }
369