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 +