[BACK]Return to kern_mem.c CVS log [TXT][DIR] Up to [local] / funnyos / kern

File: [local] / funnyos / kern / kern_mem.c (download)

Revision 1.8, Fri Nov 9 16:22:16 2007 UTC (16 years, 5 months ago) by init
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +6 -2 lines

ugly hardcode brkaddr if we are sam7s64

/*
 * $Id: kern_mem.c,v 1.8 2007/11/09 16:22:16 init Exp $
 */
#include <sys/types.h>
#include <sys/mem.h>
#include <libkern/printf.h>

/* #define KMEM_DEBUG */

#ifdef KMEM_DEBUG
#define DPRINTF(x...) 	do { printf(x); } while (0)
#else
#define DPRINTF(x...) 	{ }
#endif
 	
/*
 * Kernel memory.
 *
 * Our memory map looks like that (at least for testarm with 32MB):
 * (0MB)      0x00000000 | interrupt vectors (actually kernel text)
 *            ...
 *            0x00000020 | kernel text (continue)
 *            ...
 *            0x000fffff | END of kernel text
 *
 * (1MB)      0x00100000 | kernel data
 *            ... (1MB of kernel data)
 *            0x001fffff | END of kernel data
 *
 * (2MB)      0x00200000 | heap start (grows downwards)
 *            ... (28MB of heap)
 *
 * (30MB)     0x01e00000 <---- brk address
 * 
 *            ... (2MB of stack)
 * (32MB)     0x01ffffff | stack pointer (grows upwards)
 *
 * XXX very-very tiny memory model for my at91sam7s64
 */

/* config.c exports us ammount of available physical memory. */
extern uint32_t	 physmem;

/* break address */
//uint32_t 	brkaddr = (KMEM_HEAPBEGIN + (physmem - KMEM_HEAPBEGIN) / 2) 
//						+ (physmem - KMEM_HEAPBEGIN)
uint32_t 	brkaddr;

/* from where to allocate memory in kmalloc() */
uint32_t 	allocbase;

/* stack pointer */
uint32_t 	sp;

/* memory bit map pointer and its length */
uint8_t 	*membmap;
uint32_t 	membmaplen;

/* pages statistics */
uint32_t 	totalpages;
uint32_t 	freepages;


void
kmem_init(void)
{
	/*
	 * Initialize kernel memory (de)allocation subsystem.
	 * This allocates bit map, each BIT of it represents one kmem page.
	 * kmem page is KMEM_PAGESIZE bytes length and may be 0 (free) or 1 (not free) in membmap.
	 */
	int32_t 	n;
	uint8_t 	*bytep;

#ifdef ARCH_SAM7S64
	/* XXX UGLY HACK */
	brkaddr = 0x00203800;
#else
	/* set break address */
 	brkaddr = physmem - (physmem / 16); /* XXX top 2MB in testarm */
#endif
	/* bytes needed to hold bitmap */
	membmaplen = ((brkaddr - KMEM_HEAPBEGIN) / KMEM_PAGESIZE) / 8;

	/* total pages that will be available to kernel */
	totalpages = (brkaddr - (KMEM_HEAPBEGIN + membmaplen)) / KMEM_PAGESIZE; /* XXX what about potential modulo? */
	freepages = totalpages;

	/* allocate space for membmap in the beginning of KMEM_HEAPBEGIN */
	bytep = (uint8_t *) KMEM_HEAPBEGIN;
	n = membmaplen;

	while(n) {
		/* XXX what about errors? */
		*bytep = 0;
		bytep++;

		n--;
	}
 
	membmap = (uint8_t *)KMEM_HEAPBEGIN;

	/* skip our map; all allocations will be done starting from this */
	allocbase = KMEM_HEAPBEGIN + membmaplen;

	printf("kmem_init: membmap @0x%x size=%d pagesize=%d; %d total pages available starting from 0x%x\n", 
				membmap, membmaplen, KMEM_PAGESIZE, totalpages, allocbase);
}


void
*kmalloc(uint32_t nbytes)
{
	/*
	 * Allocate nbytes bytes of memory
	 */
	uint32_t 	pagesfound, npages, nmbmbytes, firstmbmbit;
	uint8_t 	*mbmbyte, mask, nmbmbits, i, offbits;
	uint32_t 	*firstpageptr, *lastpageptr, mbmbit, offbytes;


	/* kmalloc(0) should return NULL */
	if (! nbytes)
		return(NULL);

	/* pages needed to hold requested bytes */
	npages = nbytes / KMEM_PAGESIZE + (nbytes % KMEM_PAGESIZE != 0 ? 1 : 0);

	DPRINTF("kmalloc: requested %d bytes (%d pages) of %d free pages; ", nbytes, npages, freepages);

	/* check if we have enough free pages */
	if (npages > freepages) {
		DPRINTF("not enough free pages\n");
		return(NULL);
	}

	pagesfound = 0;
	nmbmbytes = 0;
	/* look for contiguously available pages in memory bit map */
	for (mbmbyte = membmap; nmbmbytes < membmaplen; nmbmbytes++) {

		mask = 0x01;
		nmbmbits = 0; /* counts "free page" bits inside mbmbyte */

		/* check all 8 bits in mbmbyte */
		while(mask != 0) {

//			printf("0x%x @ 0x%x & %x\n", *mbmbyte, mbmbyte, mask);
			if ((mbmbyte[nmbmbytes] & mask) == 0) {
				/* page is free */
				pagesfound++;

				/* see if we need not to search more */
				if (pagesfound == npages) {
					/*
					 * Requested amount of pages have been found.
					 */

					/* calculate pointer to this (last) page */
					lastpageptr = (uint32_t *)((allocbase + (8 * nmbmbytes * KMEM_PAGESIZE)) + (KMEM_PAGESIZE * nmbmbits)); 

					/* rewind pointer to the first byte */
					firstpageptr = lastpageptr - ((npages - 1));

					/* fill this (npages pages) region with zeroes */
					while(firstpageptr <= lastpageptr) {

						/* TODO invalidate page in membmap */
						offbytes = ((uint32_t)firstpageptr - (uint32_t)allocbase) / (KMEM_PAGESIZE * 8);
						offbits = ((uint32_t)firstpageptr - (uint32_t)allocbase) / (KMEM_PAGESIZE);

						if (offbits > 7)
							offbits -= 8 * (offbits / 8);

//						printf("membmap[%d] |= 1 << %d\n", offbytes, offbits);
						membmap[offbytes] |= 1 << offbits;

						/* zerofy page */
						for (i = 0; i < KMEM_PAGESIZE; i++) {
							*(uint8_t *)firstpageptr = KMEM_FILLBYTE;
							((uint8_t *)firstpageptr)++;
						}
						/* TODO rework offbits calculation */
						offbits++;
						if(offbits == 8)
							/* reset to the first bit */
							offbits = 0;
					}

					/* rewind pointer again */
					firstpageptr = lastpageptr - ((npages - 1));

					/* got it */
					DPRINTF("allocated, addr=0x%x len=%d [0x%x-0x%x]\n", firstpageptr, npages * KMEM_PAGESIZE, firstpageptr, lastpageptr);

					/* decrement system free pages */
					freepages -= npages;

					/* return pointer to the first byte of the allocated region */
					return(firstpageptr);
				}
			} else {
				/* encountered non-free page; reset pagesfound */
				pagesfound = 0;
			}

			/* shift to check next bit */
			mask <<= 1;
			nmbmbits++;
		}
			
	}

	/* free pages haven't been found */
	DPRINTF("not found contiguous region\n");

	return(NULL);
}


void
kfree(void *p, uint32_t nbytes)
{
	/*
	 * XXX Free nbytes bytes
	*/
}