heap.c (3256B)
1 /* 2 * core/heap.c 3 * 4 * Copyright (C) 2009 stateless 5 */ 6 7 #include <heap.h> 8 #include <mm.h> 9 #include <common.h> 10 #include <x86.h> 11 #include <errno.h> 12 #include <list.h> 13 #include <tty.h> 14 15 /* for debugging purposes */ 16 #define DUMP_CHUNK(chunk) \ 17 ({ \ 18 printf("\tbase_addr = 0x%lx, end_addr = 0x%lx, size = 0x%x\n", \ 19 chunk->base_addr, \ 20 chunk->end_addr, chunk->size); \ 21 serial_dump("\tbase_addr = 0x%lx, end_addr = 0x%lx, size = 0x%x\n", \ 22 chunk->base_addr, \ 23 chunk->end_addr, chunk->size); \ 24 }) 25 26 struct chunk_t { 27 uint32_t base_addr; 28 uint32_t end_addr; 29 size_t size; 30 struct list_head list; 31 }; 32 33 static int is_init = 0; 34 static struct list_head freelist; 35 static struct list_head allolist; 36 37 void 38 walk_heap_lists(void) 39 { 40 uint32_t state; 41 struct list_head *iter; 42 struct chunk_t *tmp; 43 44 save_flags(&state); 45 cli(); 46 printf("Summary of free chunks\n"); 47 serial_dump("Summary of free chunks\n"); 48 list_for_each(iter, &freelist) { 49 tmp = list_entry(iter, struct chunk_t, list); 50 DUMP_CHUNK(tmp); 51 } 52 printf("Summary of allocated chunks\n"); 53 serial_dump("Summary of allocated chunks\n"); 54 list_for_each(iter, &allolist) { 55 tmp = list_entry(iter, struct chunk_t, list); 56 DUMP_CHUNK(tmp); 57 } 58 load_flags(state); 59 } 60 61 void 62 kfree(void *ptr) 63 { 64 struct chunk_t *tmp; 65 struct list_head *iter, *q; 66 uint32_t state; 67 68 if (!ptr) return; /* free-ing NULL pointers is good */ 69 if (!is_init) 70 panic("allocator is not initialized!"); 71 save_flags(&state); 72 cli(); 73 list_for_each_safe(iter, q, &allolist) { 74 tmp = list_entry(iter, struct chunk_t, list); 75 if (tmp->base_addr == (uint32_t)ptr) { 76 list_del(&tmp->list); 77 list_add_tail(&tmp->list, &freelist); 78 goto out; 79 } 80 } 81 panic("trying to free non-existent chunk at 0x%08lx!", ptr); 82 out: 83 load_flags(state); 84 } 85 86 void * 87 kmalloc_ext(size_t size, enum heap_cntl flag) 88 { 89 struct list_head *iter, *q; 90 struct chunk_t *tmp, *new; 91 uint32_t addr, state; 92 int ret; 93 94 if (!is_init) 95 panic("allocator is not initialized!"); 96 97 if (flag != DEFAULT) 98 return ERR_PTR(-ENOTSUP); 99 100 if (!size) 101 return ERR_PTR(-EINVAL); 102 save_flags(&state); 103 cli(); 104 size += sizeof(struct chunk_t); 105 do { 106 list_for_each_safe(iter, q, &freelist) { 107 tmp = list_entry(iter, struct chunk_t, list); 108 if (size > tmp->size) 109 continue; 110 new = (struct chunk_t *)(tmp->end_addr - size); 111 new->base_addr = tmp->end_addr - size + sizeof(*tmp); 112 new->size = size - sizeof(*tmp); 113 new->end_addr = tmp->end_addr; 114 tmp->size -= size; 115 tmp->end_addr -= size; 116 list_add_tail(&new->list, &allolist); 117 load_flags(state); 118 return (void *)new->base_addr; 119 } 120 addr = (uint32_t)sbrk(size); 121 if (IS_ERR((void *)addr)) { 122 ret = PTR_ERR((void *)addr); 123 break; 124 } 125 tmp = (struct chunk_t *)addr; 126 tmp->base_addr = addr + sizeof(*tmp); 127 tmp->size = size; 128 tmp->size = roundup_pagesize(tmp->size); 129 tmp->size -= sizeof(*tmp); 130 tmp->end_addr = tmp->base_addr + tmp->size; 131 list_add_tail(&tmp->list, &freelist); 132 } while (1); 133 load_flags(state); 134 return ERR_PTR(ret); 135 } 136 137 void * 138 kmalloc(size_t size) 139 { 140 return kmalloc_ext(size, DEFAULT); 141 } 142 143 void 144 init_heap(void) 145 { 146 uint32_t state; 147 148 save_flags(&state); 149 cli(); 150 INIT_LIST_HEAD(&freelist); 151 INIT_LIST_HEAD(&allolist); 152 is_init = 1; 153 load_flags(state); 154 } 155