#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; } assert(mem->ref >0); 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; }