📄 mem.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 + -