kern

changeset 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 096807345aa2
children 369adbbd4bdd
files src/main.c src/mem.c src/mem.h src/vm.c
diffstat 4 files changed, 172 insertions(+), 45 deletions(-) [+]
line diff
     1.1 --- a/src/main.c	Sun Mar 27 06:28:26 2011 +0300
     1.2 +++ b/src/main.c	Wed Mar 30 22:42:16 2011 +0300
     1.3 @@ -53,11 +53,13 @@
     1.4  
     1.5  	init_segm();
     1.6  	init_intr();
     1.7 -	init_vm(mbinf);
     1.8  
     1.9  	/* silence the blasted timer interrupt */
    1.10  	interrupt(32, do_nothing);
    1.11  
    1.12 +	init_vm(mbinf);
    1.13 +
    1.14 +
    1.15  	for(;;) {
    1.16  		char c, keypress;
    1.17  		do {
     2.1 --- a/src/mem.c	Sun Mar 27 06:28:26 2011 +0300
     2.2 +++ b/src/mem.c	Wed Mar 30 22:42:16 2011 +0300
     2.3 @@ -1,40 +1,181 @@
     2.4  #include <stdio.h>
     2.5 +#include <string.h>
     2.6  #include "mem.h"
     2.7  #include "panic.h"
     2.8  #include "vm.h"
     2.9  
    2.10 +#define FREE		0
    2.11 +#define USED		1
    2.12 +
    2.13 +#define BM_IDX(pg)	((pg) / 32)
    2.14 +#define BM_BIT(pg)	((pg) & 0x1f)
    2.15 +
    2.16 +#define IS_FREE(pg) ((bitmap[BM_IDX(pg)] & (1 << BM_BIT(pg))) == 0)
    2.17 +
    2.18 +static void mark_page(int pg, int free);
    2.19 +static void add_memory(uint32_t start, size_t size);
    2.20 +
    2.21  /* end of kernel image */
    2.22  extern int _end;
    2.23  
    2.24 -static uint32_t brk;
    2.25 +static uint32_t *bitmap;
    2.26 +static int bmsize, last_alloc_idx;
    2.27  
    2.28  void init_mem(struct mboot_info *mb)
    2.29  {
    2.30 -	/* start the physical allocated break at the end of
    2.31 -	 * the kernel image
    2.32 -	 */
    2.33 -	brk = (uint32_t)&_end;
    2.34 +	int i, num_pages, max_pg = 0;
    2.35 +	uint32_t used_end;
    2.36 +
    2.37 +	num_pages = 0;
    2.38 +	last_alloc_idx = 0;
    2.39 +
    2.40 +	bitmap = (uint32_t*)&_end;
    2.41 +
    2.42 +	/* start by marking all posible pages as used */
    2.43 +	memset(bitmap, 0xff, 1024 * 1024 / 8);
    2.44 +
    2.45 +	/* build the memory map */
    2.46 +	if(mb->flags & MB_MMAP) {
    2.47 +		struct mboot_mmap *mem, *mmap_end;
    2.48 +
    2.49 +		mem = mb->mmap;
    2.50 +		mmap_end = (struct mboot_mmap*)((char*)mb->mmap + mb->mmap_len);
    2.51 +
    2.52 +		printf("memory map:\n");
    2.53 +		while(mem < mmap_end) {
    2.54 +			char *type;
    2.55 +			unsigned int end = mem->base_low + mem->length_low;
    2.56 +
    2.57 +			if(mem->type == MB_MEM_VALID) {
    2.58 +				type = "free:";
    2.59 +				add_memory(mem->base_low, mem->length_low);
    2.60 +
    2.61 +				num_pages = ADDR_TO_PAGE(mem->base_low + mem->length_low);
    2.62 +				if(max_pg < num_pages) {
    2.63 +					max_pg = num_pages;
    2.64 +				}
    2.65 +			} else {
    2.66 +				type = "hole:";
    2.67 +			}
    2.68 +
    2.69 +			printf("  %s %x - %x (%u bytes)\n", type, mem->base_low, end, mem->length_low);
    2.70 +			mem = (struct mboot_mmap*)((char*)mem + mem->skip + sizeof mem->skip);
    2.71 +		}
    2.72 +	} else if(mb->flags & MB_MEM) {
    2.73 +		add_memory(0, mb->mem_lower);
    2.74 +		add_memory(0x100000, mb->mem_upper * 1024);
    2.75 +		max_pg = mb->mem_upper / 4;
    2.76 +
    2.77 +		printf("lower memory: %ukb, upper mem: %ukb\n", mb->mem_lower, mb->mem_upper);
    2.78 +	} else {
    2.79 +		panic("didn't get any memory info from the boot loader, I give up\n");
    2.80 +	}
    2.81 +
    2.82 +	bmsize = max_pg / 8;	/* size of the bitmap in bytes */
    2.83 +
    2.84 +	/* mark all the used pages as ... well ... used */
    2.85 +	used_end = ((uint32_t)bitmap + bmsize - 1);
    2.86 +
    2.87 +	printf("marking pages up to %x ", used_end);
    2.88 +	used_end = ADDR_TO_PAGE(used_end);
    2.89 +	printf("(page: %d) inclusive as used\n", used_end);
    2.90 +
    2.91 +	for(i=0; i<=used_end; i++) {
    2.92 +		mark_page(i, USED);
    2.93 +	}
    2.94 +
    2.95 +	/*for(i=0; i<bmsize / 4; i++) {
    2.96 +		printf("%3d [%x]\n", i, bitmap[i]);
    2.97 +		asm("hlt");
    2.98 +	}
    2.99 +	putchar('\n');*/
   2.100  }
   2.101  
   2.102  uint32_t alloc_phys_page(void)
   2.103  {
   2.104 -	uint32_t addr, dbg_prev_brk;
   2.105 +	int i, idx, max;
   2.106  
   2.107 -	if(ADDR_TO_PGOFFS(brk)) {
   2.108 -		/* brk is not aligned, find the next page-aligned address */
   2.109 -		addr = (brk + PGSIZE) & ~PGOFFS_MASK;
   2.110 -	} else {
   2.111 -		/* brk is aligned, so we can use that address directly */
   2.112 -		addr = brk;
   2.113 +	idx = last_alloc_idx;
   2.114 +	max = bmsize / 4;
   2.115 +
   2.116 +	while(idx <= max) {
   2.117 +		/* if at least one bit is 0 then we have at least
   2.118 +		 * one free page. find it and allocate it.
   2.119 +		 */
   2.120 +		if(bitmap[idx] != 0xffffffff) {
   2.121 +			for(i=0; i<32; i++) {
   2.122 +				int pg = idx * 32 + i;
   2.123 +
   2.124 +				if(IS_FREE(pg)) {
   2.125 +					mark_page(pg, USED);
   2.126 +
   2.127 +					last_alloc_idx = idx;
   2.128 +
   2.129 +					printf("alloc_phys_page() -> %x (page: %d)\n", PAGE_TO_ADDR(pg), pg);
   2.130 +					return PAGE_TO_ADDR(pg);
   2.131 +				}
   2.132 +			}
   2.133 +			panic("can't happen: alloc_phys_page (mem.c)\n");
   2.134 +		}
   2.135 +		idx++;
   2.136  	}
   2.137  
   2.138 -	if(addr >= MAX_BRK) {
   2.139 -		panic("alloc_phys_page() out of early alloc space");
   2.140 +	panic("alloc_phys_page(): out of memory\n");
   2.141 +	return 0;
   2.142 +}
   2.143 +
   2.144 +void free_phys_page(uint32_t addr)
   2.145 +{
   2.146 +	int pg = ADDR_TO_PAGE(addr);
   2.147 +	int bmidx = BM_IDX(pg);
   2.148 +
   2.149 +	if(!IS_FREE(pg)) {
   2.150 +		panic("free_phys_page(%d): I thought that was already free!\n", pg);
   2.151  	}
   2.152  
   2.153 -	dbg_prev_brk = brk;
   2.154 -	brk = addr + PGSIZE;	/* move the break to the end of the page */
   2.155 +	mark_page(pg, FREE);
   2.156 +	if(bmidx < last_alloc_idx) {
   2.157 +		last_alloc_idx = bmidx;
   2.158 +	}
   2.159 +}
   2.160  
   2.161 -	printf("DBG: alloc_phys_page(): %x  (brk %x -> %x)\n", addr, dbg_prev_brk, brk);
   2.162 -	return addr;
   2.163 +void get_kernel_mem_range(uint32_t *start, uint32_t *end)
   2.164 +{
   2.165 +	if(start) {
   2.166 +		*start = 0x100000;
   2.167 +	}
   2.168 +	if(end) {
   2.169 +		uint32_t e = (uint32_t)bitmap + bmsize;
   2.170 +
   2.171 +		if(e & PGOFFS_MASK) {
   2.172 +			*end = (e + 4096) & PGOFFS_MASK;
   2.173 +		} else {
   2.174 +			*end = e;
   2.175 +		}
   2.176 +	}
   2.177  }
   2.178 +
   2.179 +static void add_memory(uint32_t start, size_t sz)
   2.180 +{
   2.181 +	int i, szpg, pg;
   2.182 +
   2.183 +	szpg = ADDR_TO_PAGE(sz);
   2.184 +	pg = ADDR_TO_PAGE(start);
   2.185 +
   2.186 +	for(i=0; i<szpg; i++) {
   2.187 +		mark_page(pg++, FREE);
   2.188 +	}
   2.189 +}
   2.190 +
   2.191 +static void mark_page(int pg, int used)
   2.192 +{
   2.193 +	int idx = BM_IDX(pg);
   2.194 +	int bit = BM_BIT(pg);
   2.195 +
   2.196 +	if(used) {
   2.197 +		bitmap[idx] |= 1 << bit;
   2.198 +	} else {
   2.199 +		bitmap[idx] &= ~(1 << bit);
   2.200 +	}
   2.201 +}
   2.202 +
     3.1 --- a/src/mem.h	Sun Mar 27 06:28:26 2011 +0300
     3.2 +++ b/src/mem.h	Wed Mar 30 22:42:16 2011 +0300
     3.3 @@ -3,10 +3,11 @@
     3.4  
     3.5  #include "mboot.h"
     3.6  
     3.7 -/* maximum break for the early allocator */
     3.8 -#define MAX_BRK		0x400000
     3.9 +void init_mem(struct mboot_info *mb);
    3.10  
    3.11 -void init_mem(struct mboot_info *mb);
    3.12  uint32_t alloc_phys_page(void);
    3.13 +void free_phys_page(uint32_t addr);
    3.14 +
    3.15 +void get_kernel_mem_range(uint32_t *start, uint32_t *end);
    3.16  
    3.17  #endif	/* MEM_H_ */
     4.1 --- a/src/vm.c	Sun Mar 27 06:28:26 2011 +0300
     4.2 +++ b/src/vm.c	Wed Mar 30 22:42:16 2011 +0300
     4.3 @@ -29,13 +29,16 @@
     4.4  
     4.5  void init_vm(struct mboot_info *mb)
     4.6  {
     4.7 +	uint32_t idmap_end;
     4.8 +
     4.9  	init_mem(mb);
    4.10  
    4.11  	pgdir = (uint32_t*)alloc_phys_page();
    4.12  	memset(pgdir, 0, sizeof pgdir);
    4.13  
    4.14  	/* map the video memory and kernel code 1-1 */
    4.15 -	map_mem_range(IDMAP_START, MAX_BRK - IDMAP_START, IDMAP_START, 0);
    4.16 +	get_kernel_mem_range(0, &idmap_end);
    4.17 +	map_mem_range(IDMAP_START, idmap_end - IDMAP_START, IDMAP_START, 0);
    4.18  
    4.19  	interrupt(PAGEFAULT, pgfault);
    4.20  
    4.21 @@ -109,28 +112,6 @@
    4.22  	map_page_range(vpg_start, num_pages, ppg_start, attr);
    4.23  }
    4.24  
    4.25 -
    4.26 -/*	if(mb->flags & MB_MMAP) {
    4.27 -		struct mboot_mmap *mem, *mmap_end;
    4.28 -
    4.29 -		mem = mb->mmap;
    4.30 -		mmap_end = (struct mboot_mmap*)((char*)mb->mmap + mb->mmap_len);
    4.31 -
    4.32 -		printf("memory map:\n");
    4.33 -		while(mem < mmap_end) {
    4.34 -			unsigned int end = mem->base_low + mem->length_low;
    4.35 -			char *type = mem->type == MB_MEM_VALID ? "free:" : "hole:";
    4.36 -
    4.37 -			printf("  %s %x - %x (%u bytes)\n", type, mem->base_low, end, mem->length_low);
    4.38 -			mem = (struct mboot_mmap*)((char*)mem + mem->skip + sizeof mem->skip);
    4.39 -		}
    4.40 -	}
    4.41 -
    4.42 -	if(mb->flags & MB_MEM) {
    4.43 -		printf("lower memory: %ukb, upper mem: %ukb\n", mb->mem_lower, mb->mem_upper);
    4.44 -	}
    4.45 -*/
    4.46 -
    4.47  uint32_t virt_to_phys(uint32_t vaddr)
    4.48  {
    4.49  	uint32_t pgaddr, *pgtbl;
    4.50 @@ -166,4 +147,6 @@
    4.51  	} else {
    4.52  		printf("page not present\n");
    4.53  	}
    4.54 +
    4.55 +	panic("unhandled page fault\n");
    4.56  }