Merge branch 'master' into net-dev (with code changes listed below besides normal...
[akaros.git] / kern / src / kmalloc.c
1 /* Copyright (c) 2009 The Regents of the University of California. 
2  * See the COPYRIGHT files at the top of this source tree for full 
3  * license information.
4  * 
5  * Kevin Klues <klueska@cs.berkeley.edu>    
6  */
7
8 #include <arch/types.h>
9 #include <ros/error.h>
10 #include <pmap.h>
11 #include <kmalloc.h>
12 #include <stdio.h>
13
14 #define kmallocdebug(args...)  //printk(args)
15
16 char*BND(end, maxaddrpa_ptr + IVY_KERNBASE) boot_freemem;
17 static page_list_t pages_list;  //List of physical pages used by kmalloc
18
19 /*
20  * Allocate n bytes of physical memory aligned on an 
21  * align-byte boundary.  Align must be a power of two.
22  * Return kernel virtual address.  Returned memory is uninitialized.
23  *
24  * If we're out of memory, boot_alloc should panic.
25  * This function may ONLY be used during initialization,
26  * before the page_free_list has been set up.
27  */
28 void* boot_alloc(uint32_t n, uint32_t align)
29 {
30         extern char (SNT end)[];
31         void *v;
32
33         // Initialize boot_freemem if this is the first time.
34         // 'end' is a magic symbol automatically generated by the linker,
35         // which points to the end of the kernel's bss segment -
36         // i.e., the first virtual address that the linker
37         // did _not_ assign to any kernel code or global variables.
38         if (boot_freemem == 0) {
39                 boot_freemem = TC(end);
40         }
41
42         //      Step 1: round boot_freemem up to be aligned properly
43         boot_freemem = PTRROUNDUP(boot_freemem, align);
44
45         //      Step 2: save current value of boot_freemem as allocated chunk
46         v = boot_freemem;
47         //  Step 2.5: check if we can alloc
48         if (PADDR(boot_freemem + n) > maxaddrpa)
49                 panic("Out of memory in boot alloc, you fool!\n");
50         //      Step 3: increase boot_freemem to record allocation
51         boot_freemem += n;      
52         //      Step 4: return allocated chunk
53         return v;
54 }
55
56 void* boot_calloc(uint32_t _n, size_t sz, uint32_t align)
57 {
58         extern char (SNT end)[];
59         uint32_t n = _n *sz;
60         void *v;
61
62         // Initialize boot_freemem if this is the first time.
63         // 'end' is a magic symbol automatically generated by the linker,
64         // which points to the end of the kernel's bss segment -
65         // i.e., the first virtual address that the linker
66         // did _not_ assign to any kernel code or global variables.
67         if (boot_freemem == 0)
68                 boot_freemem = TC(end);
69
70         //      Step 1: round boot_freemem up to be aligned properly
71         boot_freemem = PTRROUNDUP(boot_freemem, align);
72
73         //      Step 2: save current value of boot_freemem as allocated chunk
74         v = boot_freemem;
75         //  Step 2.5: check if we can alloc
76         if (PADDR(boot_freemem + n) > maxaddrpa)
77                 panic("Out of memory in boot alloc, you fool!\n");
78         //      Step 3: increase boot_freemem to record allocation
79         boot_freemem += n;
80         //  Step 4: zero allocated chunk
81         memset(v,0,n);
82         //      Step 5: return allocated chunk
83         return v;
84 }
85
86 void kmalloc_init() 
87 {
88         LIST_INIT(&pages_list);
89 }
90
91 void* kmalloc(size_t size, int flags) 
92 {
93         // ****** NEXT CONDITION MUST BE MERGED INTO MASTER!!! -PAUL *******
94         if (size == 0)
95                 return NULL;
96
97         int npages = ROUNDUP(size, PGSIZE) / PGSIZE;
98         
99         // Find 'npages' free consecutive pages
100         int first = -1;
101         kmallocdebug("naddrpages: %u\n", naddrpages);
102         kmallocdebug("npages: %u\n", npages);
103         for(int i=(naddrpages-1); i>=(npages-1); i--) {
104                 int j;
105                 for(j=i; j>=(i-(npages-1)); j--) {
106                         if( !page_is_free(j) )
107                                 break;
108                 }
109                 if( j == (i-(npages-1)-1)) {
110                         first = j+1;
111                         break;
112                 }
113         }
114         //If we couldn't find them, return NULL
115         if( first == -1 )
116                 return NULL;
117                 
118         //Otherwise go ahead and allocate them to ourselves now
119         for(int i=0; i<npages; i++) {
120                 page_t* page;
121                 page_alloc_specific(&page, first+i);
122                 // NEXT LINE MUST BE MERGED INTO MASTER (Also, Kevin doesn't like.)
123                 page_incref(page); 
124                 page->num_cons_links = npages-i;
125                 LIST_INSERT_HEAD(&pages_list, page, global_link);
126                 kmallocdebug("mallocing page: %u\n", first+i);
127                 kmallocdebug("at addr: %p\n", ppn2kva(first+i));
128         }
129         //And return the address of the first one
130         return ppn2kva(first);
131 }
132
133 void kfree(void *addr)
134 {
135         kmallocdebug("incoming address: %p\n", addr);
136         page_t* page = kva2page(addr);
137         int num_links = page->num_cons_links;
138         kmallocdebug("getting page: %u\n", page2ppn(page));
139         for(int i=0; i<num_links; i++) {
140                 page_t* p = ppn2page((page2ppn(page) + i));
141                 LIST_REMOVE(p, global_link);
142                 page_free(p);
143                 kmallocdebug("freeing page: %d\n", page2ppn(p));
144         }
145 }
146