Added dumb implementation of get_free_va_range.
[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         if (!addr)
31                 addr = (uintptr_t)get_free_va_range(p->env_pgdir,UMMAP_START,len);
32         // brief sanity check.  must be page aligned and not reaching too high
33         if (PGOFF(addr)) {
34                 printk("[kernel] mmap() page align your addr.\n");
35                 return (void*SAFE)TC(-1);
36         }
37         int num_pages = ROUNDUP(len, PGSIZE) / PGSIZE;
38         pte_t *a_pte;
39         // TODO: grab the appropriate mm_lock
40         spin_lock_irqsave(&p->proc_lock);
41         // make sure all pages are available, and in a reasonable range
42         // TODO: can probably do this better with vm_regions.
43         // can also consider not mapping to 0x00000000
44         for (int i = 0; i < num_pages; i++) {
45                 a_pte = pgdir_walk(p->env_pgdir, (void*SNT)addr, 0);
46                 if (a_pte && *a_pte & PTE_P)
47                         goto mmap_abort;
48                 if (addr + i*PGSIZE >= USTACKBOT)
49                         goto mmap_abort;
50         }
51         page_t *a_page;
52         for (int i = 0; i < num_pages; i++) {
53                 if (upage_alloc(p, &a_page, 1))
54                         goto mmap_abort;
55                 // TODO: give them the permissions they actually want
56                 if (page_insert(p->env_pgdir, a_page, (void*SNT)addr + i*PGSIZE,
57                                 PTE_USER_RW)) {
58                         page_free(a_page);
59                         goto mmap_abort;
60                 }
61         }
62         // TODO: release the appropriate mm_lock
63         spin_unlock_irqsave(&p->proc_lock);
64         return (void*SAFE)TC(addr);
65
66         // TODO: if there's a failure, we should go back through the addr+len range
67         // and dealloc everything.  or at least define what we want to do if we run
68         // out of memory.
69         mmap_abort:
70                 // TODO: release the appropriate mm_lock
71                 spin_unlock_irqsave(&p->proc_lock);
72                 // not a kernel problem, like if they ask to mmap a mapped location.
73                 printd("[kernel] mmap() aborted!\n");
74                 // mmap's semantics.  we need a better error propagation system
75                 return (void*SAFE)TC(-1); // this is also ridiculous
76 }