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