⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mem.c

📁 nucleus 源码包括具体的内核适合研究 nucleus
💻 C
字号:
/*
* Memory Management									*
* v0.01, 24.12.2003 TDS (X-Mas)						*
*		- basic routines like kmalloc, kfree, etc.	*
* v0.02, 30.03.2004 TDS								*
*		- fixed some bugs							*
* v0.03, 12.04.2004 TDS								*
*		- free, malloc, mem_walk are working :-)	*
* v0.03b, 13.05.2004 TDS							*
*		- fixed bug in malloc						*
* v0.04, 26.05.2004 TDS								*
*		- fixed bugs with large memory				*
*		- fixed bug in mem walk algorithms			*
* v0.05, 29.08.2004 Doug Gale                       *
*       - Rewrote memory size detection             *
*       - Integrated support for page tables        *
*       - Adapts to large memory (1GB+)             *
*		- Added functions to allocate single pages	*
*		- Added word and dword memset variants		*
*/

#include <drivers/mem/mem.h>
#include <nucleus.h>
#include <support.h>
#include <stdio.h>
#include <string.h>
#include <pagetbl.h>

//#define DEBUG_MEM

#define PAGE_SIZE 			4096u
#define PAGE_SHIFT 			12

#if (1<<PAGE_SHIFT) != PAGE_SIZE
#error Incorrect constant. PAGE_SIZE != (1<<PAGE_SHIFT)
#endif

unsigned *kernel_buffer;		// around (2MB / PAGE_SIZE)
								// 1MB for memory paging
char mm_initialized = 0;		// only do something if set

#define MM_ERROR_NOT_INITIALIZED	-1
#define MM_ERROR_PAGE_COUNT			-2
#define MM_ERROR_PAGE_NOT_ALLOCATED	-3
#define MM_ERROR_PAGE_NOT_USED		-4
#define MM_ERROR_PAGE_NOT_AVAILABLE	-5

#define MM_FREE			0x00
#define MM_USED			0x01
#define MM_KERNEL		0x02
#define MM_MOVEABLE		0x04
#define MM_CHANGED		0x08
#define MM_SWAP			0x10

#define size_t dword

struct
{
	size_t free, used, size;	
	size_t kernel_pages, kernel_start;	// kernel
	size_t kernel_pages_free, kernel_pages_used;
	size_t user_pages, user_start;		// user
	size_t user_pages_free, user_pages_used;
	int mm_error;
} mm_stat;

void mm_write_last_error(int write_if_none);

void memset(void *dest, int c, dword count)
{
#if 1
	__asm__ __volatile__ (
		"cld\n"
		"rep\n"
		"stosb\n"
		: "=D" (dest), "=c" (count)
		: "0" (dest), "1" (count), "a" (c)
		: "cc"
	);
#else
	dword size32	= count >> 2;
	dword fill		= (c & 0xFF) * 0x01010101;
	dword *dest32	= (dword*)dest;

	switch(count & 3)
	{
	case 3: ((byte*)dest)[count - 3] = c;
	case 2: ((byte*)dest)[count - 2] = c;
	case 1: ((byte*)dest)[count - 1] = c;
	}
	while( size32-- > 0 )
		*(dest32++) = fill;
#endif
}  

// =========================================================================
// Standard C memory functions
// =========================================================================

// Fill 16-bit values. Count * 2 bytes are filled.
void memsetw(void *dest, int c, dword count)
{
#if 1
	__asm__ __volatile__ (
		"cld\n"
		"rep\n"
		"stosw\n"
		: "=D" (dest), "=c" (count)
		: "0" (dest), "1" (count), "a" (c)
		: "cc"
	);
#else
	word *dest16 = dest;
	while (count--)
		*dest16++ = c;
#endif
}

// Fill 32-bit values. Count * 4 bytes are filled.
void memsetd(void *dest, int c, dword count)
{
#if 1
	__asm__ __volatile__ (
		"cld\n"
		"rep\n"
		"stosl\n"
		: "=D" (dest), "=c" (count)
		: "0" (dest), "1" (count), "a" (c)
		: "cc"
	);
#else
	dword *dest32 = dest;
	while (count--)
		*dest32++ = (dword)c;
#endif
}

void memcpy(void * dest, const void * src, dword count)
{
	dword size32	= count >> 2;
	dword *dest32	= (dword*)dest;
	dword *src32	= (dword*)src;

	switch( (count-(size32<<2)) )
	{
		case 3:((byte*)dest)[count-3] = ((byte*)src)[count-3];
		case 2:((byte*)dest)[count-2] = ((byte*)src)[count-2];
		case 1:((byte*)dest)[count-1] = ((byte*)src)[count-1];
	}
	while( size32-- > 0 )
		*(dest32++) = *(src32++);
}

void memmove(void *dest, const void *src, dword count)
{
	dword size32	= count>>2,i;
	dword *dest32	= (dword*)dest;
	byte  *dest8;
	dword *src32	= (dword*)src;
	byte  *src8;

	if( dest > src )
	{
		dest8 = (byte*)dest;
		src8 = (byte*)src;
		switch( (count-(size32<<2)) )
		{
		case 3:
			dest8[count-1] = src8[count-1];
			dest8[count-2] = src8[count-2];
			dest8[count-3] = src8[count-3];
			break;
		case 2:
			dest8[count-1] = src8[count-1];
			dest8[count-2] = src8[count-2];
			break;
		case 1:
			dest8[count-1] = src8[count-1];
			break;
		}
		while( size32-- )
			dest32[size32] = src32[size32];
	}
	else
	{
		for(i=0;i<size32;i++)
			*(dest32++) = *(src32++);

		dest8 = (byte*)dest32;
		src8 = (byte*)src32;
		switch( (count-(size32<<2)) )
		{
		case 3:*dest8++ = *src8++;
		case 2:*dest8++ = *src8++;
		case 1:*dest8++ = *src8++;
		}
	}
}

// =========================================================================
// Kernel page allocation functions
// =========================================================================

static unsigned int BLOCK(dword x)
{
	return (dword)(x-mm_stat.kernel_start) / PAGE_SIZE;
}

static dword ADDR(unsigned int x)
{	
	return (dword)(x*PAGE_SIZE) + mm_stat.kernel_start;
}

static int mm_get_page(int count, int * block)
{
	unsigned int i, j;	
	
	if (!mm_initialized) return MM_ERROR_NOT_INITIALIZED;
	if (count < 1) return MM_ERROR_PAGE_COUNT;
	for (i=0; i < mm_stat.kernel_pages; i++)
	{
		if (kernel_buffer[i] & MM_USED) continue;	// check for used bit
		for (j=0; j < count; j++)
		{
			if (kernel_buffer[i+j] & MM_USED)		// are there enough pages
				break;
		}
		if (j == count)
		{
			for (j=0; j < count; j++)
				kernel_buffer[i+j] |= MM_USED;				// set used bit
			mm_stat.kernel_pages_free -= count;
			mm_stat.kernel_pages_used += count;
			*block = i;
			return count;
		}
	}
	return MM_ERROR_PAGE_NOT_ALLOCATED;
}

static int mm_free_page(int page)
{
	if (page >= 0 && page < mm_stat.kernel_pages)
	{
		if (kernel_buffer[page] & 1)
		{
				kernel_buffer[page] &= ~1;	// set free bit
				mm_stat.kernel_pages_free++;
				mm_stat.kernel_pages_used--;
				return 0;
		}
		else	
		{
			return MM_ERROR_PAGE_NOT_USED;
		}
	}
	else	
	{
		return MM_ERROR_PAGE_NOT_AVAILABLE;
	}
}

// Allocate a single entire page
// Returns zero on error
void *mm_page_alloc(void)
{
	unsigned i;
	void *p;

	if (!mm_initialized)
		return 0;

	// Search for an available page
	for (i=0; i < mm_stat.kernel_pages; i++)
	{
		if (!(kernel_buffer[i] & MM_USED))
			break;
	}
	if (i >= mm_stat.kernel_pages)
		return 0;

	// Mark page as used
	kernel_buffer[i] |= MM_USED;

	// Calculate pointer to the page
	p = (void *)ADDR(i);

	// Fill the page with garbage
	memsetd(p, 0xcccccccc, PAGE_SIZE >> 2);

	mm_stat.kernel_pages_free--;
	mm_stat.kernel_pages_used++;

	// Return pointer to the page
	return p;
}

// Free a single entire page
void mm_page_free(void *page)
{
	unsigned i;

	if (!mm_initialized) return;

	i = BLOCK((dword)page);

	// Debug. Panic if page is already free.
	if (!(kernel_buffer[i] & MM_USED))
		panic();

	// Mark page as free
	kernel_buffer[i] &= ~MM_USED;

	// Fill the page with garbage
	memsetd(page, 0xcdcdcdcd, 1024);

	mm_stat.kernel_pages_free++;
	mm_stat.kernel_pages_used--;
}

unsigned long mm_get_memsize()
{
	return mm_stat.size;
}

static const unsigned int SIZE = 4;

void * kmalloc(dword size)
{
	unsigned int block, pages;
	dword addr;

	if (!mm_initialized) return 0;
	size += SIZE;
	pages = (size % PAGE_SIZE) ? 1 : 0;		// adjust one extra page
	pages += (size / PAGE_SIZE);			// calculate needed pages
	if ((mm_stat.mm_error = mm_get_page(pages, &block)) > 0)
	{
		addr = ADDR(block);
#ifdef DEBUG_MEM		
		dprintf("memory: Allocated %ld Bytes (%d pages) at 0x%lX\n", size-SIZE, pages, addr);
#endif		
		*(word *)addr = pages;
		return (void *)(addr + SIZE);
	}
	return 0;
}

void kfree(void * ptr)
{
	int i;
	
	if (!mm_initialized) return;
	
	dword addr = (dword)((ptr) - SIZE);
	unsigned int pages = *(unsigned int *)addr;
	unsigned int startpage = BLOCK(addr);
	
#ifdef DEBUG_MEM
	dprintf("memory: freeing memory (%d pages, 0x%lX)\n", pages, addr);
#endif
	for (i=startpage; i < startpage + pages; i++)
	{
		if (mm_free_page(i) != 0)
		{
			mm_write_last_error(0);
			ptr = NULL;	// wasted memory
			break;
		}
	}
	ptr = NULL;
}

void mm_write_last_error(int write_if_none)
{
	switch(mm_stat.mm_error)
	{
		case MM_ERROR_NOT_INITIALIZED:		
				dprintf("memory: error: Memory management not initialized!\n"); break;
		case MM_ERROR_PAGE_COUNT:			
				dprintf("memory: error: Wrong page count!\n"); break;
		case MM_ERROR_PAGE_NOT_ALLOCATED:	
				dprintf("memory: error: Couldn't allocate pages!\n"); break;
		case MM_ERROR_PAGE_NOT_USED:
				dprintf("memory: error: Page not used!\n"); break;
		case MM_ERROR_PAGE_NOT_AVAILABLE:
				dprintf("memory: error: Page not available!\n"); break;
		default: if (write_if_none) dprintf("memory: No error\n");
	}
}

// user stuff
// double linked list for easy use

typedef struct MEM_LIST
{
	char status;	// free, used, kernel (driver, etc.), moveable, changed, swap
	size_t size;
	struct MEM_LIST *next;
} MEM_LIST;	

static MEM_LIST *ml, *ml_start;

static int mem_create_user(size_t entries)
{
	MEM_LIST *tmp, *next;
	
	if (!mm_initialized) return MM_ERROR_NOT_INITIALIZED;
	// reserve kernel space, max. 320kb for allocating 32768 pages 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -