Sped up fork/exec significantly
[akaros.git] / kern / src / mm.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  *
6  */
7
8 #include <ros/common.h>
9 #include <ros/mman.h>
10 #include <pmap.h>
11 #include <mm.h>
12 #include <process.h>
13 #include <stdio.h>
14
15 /* mmap2() semantics on the offset (num pages, not bytes) */
16 void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags,
17            int fd, size_t offset)
18 {
19         if (fd || offset) {
20                 printk("[kernel] mmap() does not support files yet.\n");
21                 return (void*SAFE)TC(-1);
22         }
23         /* TODO: make this work, instead of a ghetto hack
24          * Find a valid range, make sure it doesn't run into the kernel
25          * make sure there's enough memory (not exceeding quotas)
26          * allocate and map the pages, update appropriate structures (vm_region)
27          * return appropriate pointer
28          * Right now, all we can do is give them the range they ask for.
29          */
30         //void *tmp = get_free_va_range(p->env_pgdir, addr, len);
31         //printk("tmp = 0x%08x\n", tmp);
32         if (!addr) {
33                 printk("[kernel] mmap() requires an address, since it's ghetto\n");
34                 return (void*SAFE)TC(-1);
35         }
36         // brief sanity check.  must be page aligned and not reaching too high
37         if (PGOFF(addr)) {
38                 printk("[kernel] mmap() page align your addr.\n");
39                 return (void*SAFE)TC(-1);
40         }
41         int num_pages = ROUNDUP(len, PGSIZE) / PGSIZE;
42         pte_t *a_pte;
43         // TODO: grab the appropriate mm_lock
44         spin_lock_irqsave(&p->proc_lock);
45         // make sure all pages are available, and in a reasonable range
46         // TODO: can probably do this better with vm_regions.
47         // can also consider not mapping to 0x00000000
48         for (int i = 0; i < num_pages; i++) {
49                 a_pte = pgdir_walk(p->env_pgdir, (void*SNT)addr, 0);
50                 if (a_pte && *a_pte & PTE_P)
51                         goto mmap_abort;
52                 if (addr + i*PGSIZE >= USTACKBOT)
53                         goto mmap_abort;
54         }
55         page_t *a_page;
56         for (int i = 0; i < num_pages; i++) {
57                 if (upage_alloc(p, &a_page, 1))
58                         goto mmap_abort;
59                 // TODO: give them the permissions they actually want
60                 if (page_insert(p->env_pgdir, a_page, (void*SNT)addr + i*PGSIZE,
61                                 PTE_USER_RW)) {
62                         page_free(a_page);
63                         goto mmap_abort;
64                 }
65         }
66         // TODO: release the appropriate mm_lock
67         spin_unlock_irqsave(&p->proc_lock);
68         return (void*SAFE)TC(addr);
69
70         // TODO: if there's a failure, we should go back through the addr+len range
71         // and dealloc everything.  or at least define what we want to do if we run
72         // out of memory.
73         mmap_abort:
74                 // TODO: release the appropriate mm_lock
75                 spin_unlock_irqsave(&p->proc_lock);
76                 // not a kernel problem, like if they ask to mmap a mapped location.
77                 printd("[kernel] mmap() aborted!\n");
78                 // mmap's semantics.  we need a better error propagation system
79                 return (void*SAFE)TC(-1); // this is also ridiculous
80 }