X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=bootcensus;a=blobdiff_plain;f=src%2Fmem.c;h=a01360777d7b5096a74b84406eb4f620a37835b9;hp=1d5db9e87b6efd653980188b2a68a810ff26dac8;hb=81c11bdd80190ec319a82b0402173cfb65fcbf72;hpb=79be435fcf61613617025a2c4ef5fddf00a09178 diff --git a/src/mem.c b/src/mem.c index 1d5db9e..a013607 100644 --- a/src/mem.c +++ b/src/mem.c @@ -16,21 +16,72 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include +#include +#include "config.h" #include "panic.h" #include "mem.h" +#include "intr.h" + +#define FREE 0 +#define USED 1 + +#define BM_IDX(pg) ((pg) / 32) +#define BM_BIT(pg) ((pg) & 0x1f) + +#define IS_FREE(pg) ((bitmap[BM_IDX(pg)] & (1 << BM_BIT(pg))) == 0) + +#define MEM_START ((uint32_t)&_mem_start) + struct mem_range { uint32_t start; uint32_t size; }; +void move_stack(uint32_t newaddr); /* defined in startup.s */ + +static void mark_page(int pg, int used); +static void add_memory(uint32_t start, size_t size); + #define MAX_MAP_SIZE 16 extern struct mem_range boot_mem_map[MAX_MAP_SIZE]; extern int boot_mem_map_size; +/* linker supplied symbol, points to the end of the kernel image */ +extern uint32_t _mem_start; + + +/* A bitmap is used to track which physical memory pages are used, and which + * are available for allocation by alloc_ppage. + * + * last_alloc_idx keeps track of the last 32bit element in the bitmap array + * where a free page was found. It's guaranteed that all the elements before + * this have no free pages, but it doesn't imply that there will be another + * free page there. So it's used as a starting point for the search. + */ +static uint32_t *bitmap; +static int bmsize, last_alloc_idx; + + + void init_mem(void) { - int i; + int i, pg, max_used_pg, end_pg = 0; + uint32_t used_end, start, end, sz, total = 0, rem; + const char *suffix[] = {"bytes", "KB", "MB", "GB"}; + + last_alloc_idx = 0; + + /* the allocation bitmap starts right at the end of the kernel image */ + bitmap = (uint32_t*)&_mem_start; + + /* start by marking all posible pages (2**20) as used. We do not "reserve" + * all this space. Pages beyond the end of the useful bitmap area + * ((char*)bitmap + bmsize), which will be determined after we traverse the + * memory map, are going to be marked as available for allocation. + */ + memset(bitmap, 0xff, 1024 * 1024 / 8); + if(boot_mem_map_size <= 0 || boot_mem_map_size > MAX_MAP_SIZE) { panic("invalid memory map size reported by the boot loader: %d\n", boot_mem_map_size); @@ -40,5 +91,224 @@ void init_mem(void) for(i=0; i 1024) { + rem = total & 0x3ff; + total >>= 10; + ++i; + } + printf("Total usable RAM: %u.%u %s\n", total, 100 * rem / 1024, suffix[i]); + + /* size of the useful part of the bitmap in bytes padded to 4-byte + * boundaries to allow 32bit at a time operations. + */ + bmsize = (end_pg / 32) * 4; + + /* mark all pages occupied by the bitmap as used */ + used_end = (uint32_t)bitmap + bmsize - 1; + + max_used_pg = ADDR_TO_PAGE(used_end); + printf("marking pages up to %x (page: %d) as used\n", used_end, max_used_pg); + for(i=0; i<=max_used_pg; i++) { + mark_page(i, USED); + } + +#ifdef MOVE_STACK_RAMTOP + /* allocate space for the stack at the top of RAM and move it there */ + if((pg = alloc_ppages(STACK_PAGES, MEM_STACK)) != -1) { + printf("moving stack-top to: %x (%d pages)\n", PAGE_TO_ADDR(end_pg) - 4, STACK_PAGES); + move_stack(PAGE_TO_ADDR(pg + STACK_PAGES) - 4); + } +#endif +} + +int alloc_ppage(int area) +{ + return alloc_ppages(1, area); +} + +/* free_ppage marks the physical page, free in the allocation bitmap. + * + * CAUTION: no checks are done that this page should actually be freed or not. + * If you call free_ppage with the address of some part of memory that was + * originally reserved due to it being in a memory hole or part of the kernel + * image or whatever, it will be subsequently allocatable by alloc_ppage. + */ +void free_ppage(int pg) +{ + int bmidx = BM_IDX(pg); + + int intr_state = get_intr_flag(); + disable_intr(); + + if(IS_FREE(pg)) { + panic("free_ppage(%d): I thought that was already free!\n", pg); + } + + mark_page(pg, FREE); + if(bmidx < last_alloc_idx) { + last_alloc_idx = bmidx; + } + + set_intr_flag(intr_state); +} + + +int alloc_ppages(int count, int area) +{ + int i, dir, pg, idx, max, intr_state, found_free = 0; + + intr_state = get_intr_flag(); + disable_intr(); + + if(area == MEM_STACK) { + idx = (bmsize - 1) / 4; + max = -1; + dir = -1; + } else { + idx = last_alloc_idx; + max = bmsize / 4; + dir = 1; + } + + while(idx != max) { + /* if at least one bit is 0 then we have at least + * one free page. find it and try to allocate a range starting from there + */ + if(bitmap[idx] != 0xffffffff) { + pg = idx * 32; + if(dir < 0) pg += 31; + + for(i=0; i<32; i++) { + if(IS_FREE(pg)) { + if(!found_free && dir > 0) { + last_alloc_idx = idx; + found_free = 1; + } + + if(alloc_ppage_range(pg, count) != -1) { + set_intr_flag(intr_state); + return pg; + } + } + pg += dir; + } + } + idx += dir; + } + + set_intr_flag(intr_state); + return -1; +} + +void free_ppages(int pg0, int count) +{ + int i; + + for(i=0; i