169 lines
3.8 KiB
C
169 lines
3.8 KiB
C
#include "assert.h"
|
|
#include "mem.h"
|
|
#include "kernel.h"
|
|
#include "klibc.h"
|
|
#include "list.h"
|
|
#include "types.h"
|
|
|
|
static struct memDesc *pageDesc = (struct memDesc *)&__ld_kernel_end;
|
|
static struct memDesc *freePage;
|
|
static struct memDesc *usedPage;
|
|
paddr_t pageDescEnd;
|
|
paddr_t upperMem;
|
|
|
|
static unsigned long allocatedPage = 0;
|
|
|
|
int memSetup(paddr_t upperMemKB, paddr_t *lastMemUsedOut)
|
|
{
|
|
list_init(freePage);
|
|
list_init(usedPage);
|
|
|
|
// Align upper mem (in kB) on page size even if it does loose a page
|
|
upperMemKB = ALIGN_DOWN(upperMemKB, PAGE_SIZE / 1024);
|
|
unsigned long nbPage = ((upperMemKB) / (PAGE_SIZE / 1024));
|
|
|
|
printf("Available Mem from 0x%x to 0x%x: %dMB in %d Pages of %dB\n", &__ld_kernel_end,
|
|
upperMemKB * 1024, (upperMemKB * 1024 - (uint32_t)&__ld_kernel_end) / (1024 * 1024),
|
|
nbPage, PAGE_SIZE);
|
|
|
|
// Memory description is stored after the kernel. We need some place to store it
|
|
pageDescEnd = (unsigned long)pageDesc + nbPage * sizeof(struct memDesc);
|
|
*lastMemUsedOut = ALIGN(pageDescEnd, PAGE_SIZE);
|
|
upperMem = upperMemKB * 1024;
|
|
|
|
memAddBank(0, *lastMemUsedOut, 0);
|
|
return 0;
|
|
}
|
|
|
|
int memAddBank(paddr_t bottomMem, paddr_t topMem, int isFree)
|
|
{
|
|
topMem = min(topMem, upperMem);
|
|
for (uint i = (bottomMem >> PAGE_SHIFT); i < (topMem >> PAGE_SHIFT); i++) {
|
|
struct memDesc *mem = &pageDesc[i];
|
|
if (isFree) {
|
|
mem->ref = 0;
|
|
list_add_tail(freePage, mem);
|
|
} else {
|
|
mem->ref = 1;
|
|
list_add_tail(usedPage, mem);
|
|
}
|
|
mem->phy_addr = i * PAGE_SIZE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void memGetStat(uint *free, uint *used)
|
|
{
|
|
uint idx;
|
|
struct memDesc *mem;
|
|
list_foreach(freePage, mem, idx)
|
|
{
|
|
continue;
|
|
}
|
|
*free = idx;
|
|
list_foreach(usedPage, mem, idx)
|
|
{
|
|
continue;
|
|
}
|
|
*used = idx;
|
|
}
|
|
|
|
struct memDesc *addr2memDesc(paddr_t addr)
|
|
{
|
|
int idx = addr >> PAGE_SHIFT;
|
|
return pageDesc + idx;
|
|
}
|
|
|
|
struct memDesc *memFindConsecutiveFreePage(uint nbPage)
|
|
{
|
|
struct memDesc *mem, *head;
|
|
uint memIdx, count;
|
|
|
|
if (list_is_empty(freePage)) {
|
|
return NULL;
|
|
}
|
|
count = 1;
|
|
memIdx = 0;
|
|
head = freePage;
|
|
mem = freePage;
|
|
|
|
while (count < nbPage && (!memIdx || mem != freePage)) {
|
|
memIdx++;
|
|
mem = mem->next;
|
|
if (mem->phy_addr == head->phy_addr + count * PAGE_SIZE) {
|
|
count++;
|
|
} else {
|
|
count = 1;
|
|
head = mem;
|
|
}
|
|
}
|
|
|
|
if (count < nbPage) {
|
|
return NULL;
|
|
}
|
|
return head;
|
|
}
|
|
|
|
paddr_t allocPhyPage(uint nbPage)
|
|
{
|
|
struct memDesc *mem, *head, *next;
|
|
uint count;
|
|
|
|
head = memFindConsecutiveFreePage(nbPage);
|
|
|
|
if (head == NULL) {
|
|
pr_devel("Cannot find %d consecutive page\n", nbPage);
|
|
return (unsigned long)NULL;
|
|
}
|
|
|
|
mem = head;
|
|
next = head->next;
|
|
for (count = 0; count < nbPage; count++) {
|
|
list_delete(freePage, mem);
|
|
mem->ref = 1;
|
|
list_add_tail(usedPage, mem);
|
|
mem = next;
|
|
next = mem->next;
|
|
}
|
|
allocatedPage += nbPage;
|
|
return head->phy_addr;
|
|
}
|
|
|
|
int unrefPhyPage(paddr_t addr)
|
|
{
|
|
struct memDesc *mem = addr2memDesc(addr);
|
|
if (!mem) {
|
|
return -1;
|
|
}
|
|
mem->ref--;
|
|
if (mem->ref == 0) {
|
|
allocatedPage--;
|
|
list_delete(usedPage, mem);
|
|
list_add_tail(freePage, mem); // TODO find the right place to keep free_page sorted;
|
|
}
|
|
|
|
return mem->ref;
|
|
}
|
|
|
|
int refPhyPage(paddr_t addr)
|
|
{
|
|
struct memDesc *mem = addr2memDesc(addr);
|
|
if (!mem) {
|
|
return -1;
|
|
}
|
|
mem->ref++;
|
|
if (mem->ref == 1) {
|
|
allocatedPage++;
|
|
list_add_tail(usedPage, mem);
|
|
list_delete(freePage, mem);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned long getNbAllocatedPage(void)
|
|
{
|
|
return allocatedPage;
|
|
}
|