kern
diff src/mem.c @ 19:8be069e6bb05
I think I'm done with the physical memory page allocator
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 30 Mar 2011 22:42:16 +0300 |
parents | 098b1cb5eeaa |
children | 369adbbd4bdd |
line diff
1.1 --- a/src/mem.c Sun Mar 27 06:28:26 2011 +0300 1.2 +++ b/src/mem.c Wed Mar 30 22:42:16 2011 +0300 1.3 @@ -1,40 +1,181 @@ 1.4 #include <stdio.h> 1.5 +#include <string.h> 1.6 #include "mem.h" 1.7 #include "panic.h" 1.8 #include "vm.h" 1.9 1.10 +#define FREE 0 1.11 +#define USED 1 1.12 + 1.13 +#define BM_IDX(pg) ((pg) / 32) 1.14 +#define BM_BIT(pg) ((pg) & 0x1f) 1.15 + 1.16 +#define IS_FREE(pg) ((bitmap[BM_IDX(pg)] & (1 << BM_BIT(pg))) == 0) 1.17 + 1.18 +static void mark_page(int pg, int free); 1.19 +static void add_memory(uint32_t start, size_t size); 1.20 + 1.21 /* end of kernel image */ 1.22 extern int _end; 1.23 1.24 -static uint32_t brk; 1.25 +static uint32_t *bitmap; 1.26 +static int bmsize, last_alloc_idx; 1.27 1.28 void init_mem(struct mboot_info *mb) 1.29 { 1.30 - /* start the physical allocated break at the end of 1.31 - * the kernel image 1.32 - */ 1.33 - brk = (uint32_t)&_end; 1.34 + int i, num_pages, max_pg = 0; 1.35 + uint32_t used_end; 1.36 + 1.37 + num_pages = 0; 1.38 + last_alloc_idx = 0; 1.39 + 1.40 + bitmap = (uint32_t*)&_end; 1.41 + 1.42 + /* start by marking all posible pages as used */ 1.43 + memset(bitmap, 0xff, 1024 * 1024 / 8); 1.44 + 1.45 + /* build the memory map */ 1.46 + if(mb->flags & MB_MMAP) { 1.47 + struct mboot_mmap *mem, *mmap_end; 1.48 + 1.49 + mem = mb->mmap; 1.50 + mmap_end = (struct mboot_mmap*)((char*)mb->mmap + mb->mmap_len); 1.51 + 1.52 + printf("memory map:\n"); 1.53 + while(mem < mmap_end) { 1.54 + char *type; 1.55 + unsigned int end = mem->base_low + mem->length_low; 1.56 + 1.57 + if(mem->type == MB_MEM_VALID) { 1.58 + type = "free:"; 1.59 + add_memory(mem->base_low, mem->length_low); 1.60 + 1.61 + num_pages = ADDR_TO_PAGE(mem->base_low + mem->length_low); 1.62 + if(max_pg < num_pages) { 1.63 + max_pg = num_pages; 1.64 + } 1.65 + } else { 1.66 + type = "hole:"; 1.67 + } 1.68 + 1.69 + printf(" %s %x - %x (%u bytes)\n", type, mem->base_low, end, mem->length_low); 1.70 + mem = (struct mboot_mmap*)((char*)mem + mem->skip + sizeof mem->skip); 1.71 + } 1.72 + } else if(mb->flags & MB_MEM) { 1.73 + add_memory(0, mb->mem_lower); 1.74 + add_memory(0x100000, mb->mem_upper * 1024); 1.75 + max_pg = mb->mem_upper / 4; 1.76 + 1.77 + printf("lower memory: %ukb, upper mem: %ukb\n", mb->mem_lower, mb->mem_upper); 1.78 + } else { 1.79 + panic("didn't get any memory info from the boot loader, I give up\n"); 1.80 + } 1.81 + 1.82 + bmsize = max_pg / 8; /* size of the bitmap in bytes */ 1.83 + 1.84 + /* mark all the used pages as ... well ... used */ 1.85 + used_end = ((uint32_t)bitmap + bmsize - 1); 1.86 + 1.87 + printf("marking pages up to %x ", used_end); 1.88 + used_end = ADDR_TO_PAGE(used_end); 1.89 + printf("(page: %d) inclusive as used\n", used_end); 1.90 + 1.91 + for(i=0; i<=used_end; i++) { 1.92 + mark_page(i, USED); 1.93 + } 1.94 + 1.95 + /*for(i=0; i<bmsize / 4; i++) { 1.96 + printf("%3d [%x]\n", i, bitmap[i]); 1.97 + asm("hlt"); 1.98 + } 1.99 + putchar('\n');*/ 1.100 } 1.101 1.102 uint32_t alloc_phys_page(void) 1.103 { 1.104 - uint32_t addr, dbg_prev_brk; 1.105 + int i, idx, max; 1.106 1.107 - if(ADDR_TO_PGOFFS(brk)) { 1.108 - /* brk is not aligned, find the next page-aligned address */ 1.109 - addr = (brk + PGSIZE) & ~PGOFFS_MASK; 1.110 - } else { 1.111 - /* brk is aligned, so we can use that address directly */ 1.112 - addr = brk; 1.113 + idx = last_alloc_idx; 1.114 + max = bmsize / 4; 1.115 + 1.116 + while(idx <= max) { 1.117 + /* if at least one bit is 0 then we have at least 1.118 + * one free page. find it and allocate it. 1.119 + */ 1.120 + if(bitmap[idx] != 0xffffffff) { 1.121 + for(i=0; i<32; i++) { 1.122 + int pg = idx * 32 + i; 1.123 + 1.124 + if(IS_FREE(pg)) { 1.125 + mark_page(pg, USED); 1.126 + 1.127 + last_alloc_idx = idx; 1.128 + 1.129 + printf("alloc_phys_page() -> %x (page: %d)\n", PAGE_TO_ADDR(pg), pg); 1.130 + return PAGE_TO_ADDR(pg); 1.131 + } 1.132 + } 1.133 + panic("can't happen: alloc_phys_page (mem.c)\n"); 1.134 + } 1.135 + idx++; 1.136 } 1.137 1.138 - if(addr >= MAX_BRK) { 1.139 - panic("alloc_phys_page() out of early alloc space"); 1.140 + panic("alloc_phys_page(): out of memory\n"); 1.141 + return 0; 1.142 +} 1.143 + 1.144 +void free_phys_page(uint32_t addr) 1.145 +{ 1.146 + int pg = ADDR_TO_PAGE(addr); 1.147 + int bmidx = BM_IDX(pg); 1.148 + 1.149 + if(!IS_FREE(pg)) { 1.150 + panic("free_phys_page(%d): I thought that was already free!\n", pg); 1.151 } 1.152 1.153 - dbg_prev_brk = brk; 1.154 - brk = addr + PGSIZE; /* move the break to the end of the page */ 1.155 + mark_page(pg, FREE); 1.156 + if(bmidx < last_alloc_idx) { 1.157 + last_alloc_idx = bmidx; 1.158 + } 1.159 +} 1.160 1.161 - printf("DBG: alloc_phys_page(): %x (brk %x -> %x)\n", addr, dbg_prev_brk, brk); 1.162 - return addr; 1.163 +void get_kernel_mem_range(uint32_t *start, uint32_t *end) 1.164 +{ 1.165 + if(start) { 1.166 + *start = 0x100000; 1.167 + } 1.168 + if(end) { 1.169 + uint32_t e = (uint32_t)bitmap + bmsize; 1.170 + 1.171 + if(e & PGOFFS_MASK) { 1.172 + *end = (e + 4096) & PGOFFS_MASK; 1.173 + } else { 1.174 + *end = e; 1.175 + } 1.176 + } 1.177 } 1.178 + 1.179 +static void add_memory(uint32_t start, size_t sz) 1.180 +{ 1.181 + int i, szpg, pg; 1.182 + 1.183 + szpg = ADDR_TO_PAGE(sz); 1.184 + pg = ADDR_TO_PAGE(start); 1.185 + 1.186 + for(i=0; i<szpg; i++) { 1.187 + mark_page(pg++, FREE); 1.188 + } 1.189 +} 1.190 + 1.191 +static void mark_page(int pg, int used) 1.192 +{ 1.193 + int idx = BM_IDX(pg); 1.194 + int bit = BM_BIT(pg); 1.195 + 1.196 + if(used) { 1.197 + bitmap[idx] |= 1 << bit; 1.198 + } else { 1.199 + bitmap[idx] &= ~(1 << bit); 1.200 + } 1.201 +} 1.202 +