memory.c (7619B)
1 /* Copyright 1998-1999, Brian J. Swetland. All rights reserved. 2 ** Distributed under the terms of the OpenBLT License 3 */ 4 5 #include "kernel.h" 6 #include "memory.h" 7 8 static unsigned char size_map[513] = { 9 KM16, 10 11 KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16, 12 KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16, 13 14 KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32, 15 KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32, 16 17 KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64, 18 KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64, 19 KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64, 20 KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64, 21 22 KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96, 23 KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96, 24 KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96, 25 KM96, KM96, KM96, KM96, KM96, KM96, KM96, KM96, 26 27 KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128, 28 KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128, 29 KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128, 30 KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128, 31 32 KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, 33 KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, 34 KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, 35 KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, 36 KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, 37 KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, 38 KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, 39 KM192, KM192, KM192, KM192, KM192, KM192, KM192, KM192, 40 41 KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, 42 KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, 43 KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, 44 KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, 45 KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, 46 KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, 47 KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, 48 KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256, 49 }; 50 51 52 void *kmallocB(int size) 53 { 54 if(size < 256) return kmallocP(size_map[size]); 55 panic("invalid kmallocB"); 56 } 57 58 void kfreeB(int size, void *block) 59 { 60 if(size < 256) return kfreeP(size_map[size],block); 61 panic("invalid kmallocB"); 62 } 63 64 65 66 struct km_mnode 67 { 68 struct km_mnode *next; 69 }; 70 71 static struct _km_map 72 { 73 int size; 74 int used_count; 75 int fresh_count; 76 int free_count; 77 struct km_mnode *free_chain; 78 void *fresh_chain; 79 } km_map[KMMAX] = { 80 { 16, 0, 256, 0, NULL, NULL }, 81 { 32, 0, 128, 0, NULL, NULL }, 82 { 64, 0, 64, 0, NULL, NULL }, 83 { 96, 0, 42, 0, NULL, NULL }, 84 { 128, 0, 32, 0, NULL, NULL }, 85 { 192, 0, 21, 0, NULL, NULL }, 86 { 256, 0, 16, 0, NULL, NULL } 87 }; 88 89 extern uint32 memsize; 90 extern uint32 memtotal; 91 92 static uint32 total_pages; 93 static uint32 used_pages; 94 95 void memory_status(void) 96 { 97 int i; 98 int inuse = 0, allocated = 0; 99 100 kprintf(""); 101 kprintf("size used free fresh"); 102 for(i=0;i<KMMAX;i++){ 103 kprintf("%U %U %U %U", km_map[i].size, km_map[i].used_count, 104 km_map[i].free_count, km_map[i].fresh_count); 105 inuse += km_map[i].size * km_map[i].used_count; 106 allocated += km_map[i].size * 107 (km_map[i].free_count+km_map[i].used_count+km_map[i].fresh_count); 108 109 } 110 inuse /= 1024; 111 allocated /= 1024; 112 kprintf(""); 113 kprintf("%dkb allocated, %dkb in use",allocated,inuse); 114 kprintf("%d (of %d) pages in use",used_pages, total_pages); 115 116 } 117 118 119 /* kernel 'heap' is allocated top down ... top three pages used by the bootstrap */ 120 static uint32 nextmem = 0x80400000 - 4*4096; 121 static node_t *freevpagelist = NULL; 122 123 static uint32 *pagelist = NULL; 124 static uint32 freepage = 0; 125 126 extern aspace_t *flat; 127 128 void putpage(uint32 number) 129 { 130 // kprintf("- %d",number); 131 132 pagelist[number] = freepage; 133 freepage = number; 134 used_pages--; 135 } 136 137 uint32 getpage(void) 138 { 139 uint32 n = freepage; 140 141 // kprintf("+ %d",n); 142 143 if(n){ 144 freepage = pagelist[n]; 145 } else { 146 panic("Out of physical memory"); 147 } 148 used_pages++; 149 return n; 150 } 151 152 void kfreepage(void *vaddr) 153 { 154 node_t *n; 155 int pageno; 156 int vpage = (((uint32)vaddr)/0x1000) & 0x3ff; 157 158 if(!flat->high[vpage]){ 159 kprintf("vpage %d / %x unmapped already?!",vpage,vaddr); 160 DEBUGGER(); 161 } 162 163 /* release the underlying page */ 164 pageno = flat->high[vpage] / 0x1000; 165 // kprintf("kfreepage(%x) high[%d] = %d",vaddr,vpage,pageno); 166 putpage( pageno ); 167 168 flat->high[vpage] = 0; 169 local_flush_pte(vaddr); 170 171 /* stick it on the virtual page freelist */ 172 n = kmalloc(node_t); 173 n->next = freevpagelist; 174 n->data = vaddr; 175 freevpagelist = n; 176 } 177 178 void *kgetpage(uint32 *phys) 179 { 180 uint32 pg = getpage(); 181 *phys = pg * 0x1000; 182 183 if(nextmem < 0x80050000) panic("kernel vspace exhausted"); 184 185 if(freevpagelist){ 186 node_t *n = freevpagelist; 187 void *page = n->data; 188 freevpagelist = n->next; 189 kfree(node_t, n); 190 if(flat->high[(((uint32)page)/0x1000) & 0x3ff]){ 191 kprintf("page collision @ %x",page); 192 DEBUGGER(); 193 } 194 aspace_maphi(flat, pg, (((uint32)page)/0x1000) , 1, 3); 195 return page; 196 } else { 197 nextmem -= 4096; 198 aspace_maphi(flat, pg, nextmem/0x1000, 1, 3); 199 return (void *) nextmem; 200 } 201 } 202 203 void *kgetpages(int count) 204 { 205 if(count == 1){ 206 uint32 phys; 207 return kgetpage(&phys); 208 } else { 209 int i,n; 210 nextmem -= 4096*count; 211 for(n=nextmem/0x1000,i=0;i<count;n++,i++){ 212 aspace_maphi(flat, getpage(), n, 1, 3); 213 } 214 return (void *) nextmem; 215 } 216 } 217 218 /* map specific physical pages into kernel space, return virtaddr */ 219 void *kmappages(int phys, int count, int flags) 220 { 221 nextmem -= 4096*count; 222 aspace_maphi(flat, phys, nextmem/0x1000, count, flags); 223 return (void *) nextmem; 224 } 225 226 void memory_init(uint32 bottom_page, uint32 top_page) 227 { 228 int i,count; 229 230 /* we can track 1024 pages for every 4K of pagelist */ 231 count = ((top_page - bottom_page) / 1024) + 1; 232 233 /* allocate the pagelist */ 234 top_page -= count; 235 total_pages = 0; 236 used_pages = 0; 237 238 nextmem -= 4096*count; 239 pagelist = (uint32 *) nextmem; 240 aspace_maphi(flat, top_page, nextmem/0x1000, count, 3); 241 242 /* setup the pagelist */ 243 freepage = 0; 244 for(i=top_page;i>=bottom_page;i--){ 245 total_pages++; 246 pagelist[i] = freepage; 247 freepage = i; 248 } 249 250 /* setup the memory pools */ 251 for(i=0;i<KMMAX;i++){ 252 km_map[i].fresh_chain = kgetpages(1); 253 } 254 } 255 256 257 void *kmallocP(int size) 258 { 259 struct _km_map *km; 260 void *block; 261 if(size >= KMMAX) panic("illegal size in kmalloc()"); 262 km = &km_map[size]; 263 264 km->used_count++; 265 266 if(km->free_chain) { 267 /* recycle free'd blocks if available */ 268 km->free_count--; 269 block = (void *) km->free_chain; 270 km->free_chain = km->free_chain->next; 271 } else { 272 /* shave a new block off of the fresh page if 273 we can't recycle */ 274 km->fresh_count--; 275 block = km->fresh_chain; 276 277 if(km->fresh_count){ 278 /* still some left, just bump us to the next chunk */ 279 km->fresh_chain = (void *) 280 (((char *) km->fresh_chain) + km->size); 281 } else { 282 /* gotta grab a new page */ 283 km->fresh_count = 4096 / km->size; 284 km->fresh_chain = kgetpages(1); 285 } 286 } 287 288 return block; 289 } 290 291 void kfreeP(int size, void *block) 292 { 293 struct _km_map *km; 294 if(size > KMMAX) panic("illegal size in kmalloc()"); 295 km = &km_map[size]; 296 297 km->free_count++; 298 km->used_count--; 299 ((struct km_mnode *) block)->next = km->free_chain; 300 km->free_chain = (struct km_mnode *) block; 301 } 302