Physical memory init uses multiboot info
[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  * Barret Rhoden <brho@cs.berkeley.edu>
6  * Kevin Klues <klueska@cs.berkeley.edu>    
7  */
8
9 #ifdef __SHARC__
10 #pragma nosharc
11 #define SINIT(x) x
12 #endif
13
14 #ifdef __DEPUTY__
15 #pragma nodeputy
16 #endif
17
18 #include <ros/common.h>
19 #include <error.h>
20 #include <pmap.h>
21 #include <kmalloc.h>
22 #include <stdio.h>
23 #include <slab.h>
24 #include <assert.h>
25
26 #define kmallocdebug(args...)  //printk(args)
27
28 //List of physical pages used by kmalloc
29 static spinlock_t pages_list_lock = SPINLOCK_INITIALIZER;
30 static page_list_t LCKD(&pages_list_lock)pages_list;
31
32 struct kmem_cache *kmalloc_caches[NUM_KMALLOC_CACHES];
33 void kmalloc_init(void)
34 {
35         // i want to know if we ever make the tag bigger (should be below 16 bytes)
36         static_assert(sizeof(struct kmalloc_tag) <= KMALLOC_ALIGNMENT);
37         // build caches of common sizes
38         size_t ksize = KMALLOC_SMALLEST;
39         for (int i = 0; i < NUM_KMALLOC_CACHES; i++) {
40                 kmalloc_caches[i] = kmem_cache_create("kmalloc_cache", ksize,
41                                                       KMALLOC_ALIGNMENT, 0, 0, 0);
42                 ksize <<= 1;
43         }
44 }
45
46 void *kmalloc(size_t size, int flags) 
47 {
48         // reserve space for bookkeeping and preserve alignment
49         size_t ksize = size + KMALLOC_OFFSET;
50         void *buf;
51         int cache_id;
52         // determine cache to pull from
53         if (ksize <= KMALLOC_SMALLEST)
54                 cache_id = 0;
55         else
56                 cache_id = LOG2_UP(ksize) - LOG2_UP(KMALLOC_SMALLEST);
57         // if we don't have a cache to handle it, alloc cont pages
58         if (cache_id >= NUM_KMALLOC_CACHES) {
59                 size_t num_pgs = ROUNDUP(size + sizeof(struct kmalloc_tag), PGSIZE) /
60                                            PGSIZE;
61                 buf = get_cont_pages(LOG2_UP(num_pgs), flags);
62                 if (!buf)
63                         panic("Kmalloc failed!  Handle me!");
64                 // fill in the kmalloc tag
65                 struct kmalloc_tag *tag = buf;
66                 tag->flags = KMALLOC_TAG_PAGES;
67                 tag->num_pages = num_pgs;
68                 tag->canary = KMALLOC_CANARY;
69                 return buf + KMALLOC_OFFSET;
70         }
71         // else, alloc from the appropriate cache
72         buf = kmem_cache_alloc(kmalloc_caches[cache_id], flags);
73         if (!buf)
74                 panic("Kmalloc failed!  Handle me!");
75         // store a pointer to the buffers kmem_cache in it's bookkeeping space
76         struct kmalloc_tag *tag = buf;
77         tag->flags = KMALLOC_TAG_CACHE;
78         tag->my_cache = kmalloc_caches[cache_id];
79         tag->canary = KMALLOC_CANARY;
80         return buf + KMALLOC_OFFSET;
81 }
82
83 void *krealloc(void* buf, size_t size, int flags) {
84         struct kmalloc_tag *tag = (struct kmalloc_tag*)(buf - KMALLOC_OFFSET);
85         if (tag->my_cache->obj_size >= size)
86                 return buf;
87         kfree(buf);
88         return kmalloc(size, flags);
89 }
90
91 void kfree(void *addr)
92 {
93         if(addr == NULL)
94                 return;
95         struct kmalloc_tag *tag = (struct kmalloc_tag*)(addr - KMALLOC_OFFSET);
96         assert(tag->canary == KMALLOC_CANARY);
97         if (tag->flags & KMALLOC_TAG_CACHE)
98                 kmem_cache_free(tag->my_cache, addr - KMALLOC_OFFSET);
99         else if (tag->flags & KMALLOC_TAG_PAGES) {
100                 free_cont_pages(addr - KMALLOC_OFFSET, LOG2_UP(tag->num_pages));
101         } else 
102                 panic("[Italian Accent]: Che Cazzo! BO! Flag in kmalloc!!!");
103 }
104