#include "mem.h" #include "kernel.h" #include "klibc.h" #include "list.h" #include "types.h" static struct mem_desc *page_desc = (struct mem_desc *)&__ld_kernel_end; static struct mem_desc *free_page; static struct mem_desc *used_page; static unsigned long bottom_mem; static unsigned long top_mem; static unsigned long allocatedPage = 0; int memSetup(paddr_t upperMem, paddr_t *lastUsedOut) { // Align upper mem (in kB) on page size even if it does loose a page upperMem = ALIGN_DOWN(upperMem, PAGE_SIZE / 1024); printf("Available Mem from 0x%x to 0x%x: %dMB \n", &__ld_kernel_end, upperMem * 1024, (upperMem * 1024 - (uint32_t)&__ld_kernel_end) / (1024 * 1024)); // Memory description is stored after the kernel. We need some place to store it unsigned long memdesc_end = (unsigned long)page_desc + ((upperMem) / (PAGE_SIZE / 1024)) * sizeof(struct mem_desc); uint lastUsed = (memdesc_end >> PAGE_SHIFT) + 1; list_init(free_page); list_init(used_page); bottom_mem = lastUsed; *lastUsedOut = memdesc_end; top_mem = upperMem * 1024; for (uint i = 0; i < (upperMem / (PAGE_SIZE / 1024)); i++) { struct mem_desc *mem = &page_desc[i]; if (i < lastUsed) { mem->ref = 1; list_add_tail(used_page, mem); } else { mem->ref = 0; list_add_tail(free_page, mem); } mem->phy_addr = i * PAGE_SIZE; } return 0; } struct mem_desc *addr2memDesc(paddr_t addr) { if (addr > top_mem || addr < bottom_mem) return NULL; int idx = addr >> PAGE_SHIFT; return page_desc + idx; } struct mem_desc *memFindConsecutiveFreePage(uint nbPage) { struct mem_desc *mem, *head; uint memIdx, count; if (list_is_empty(free_page)) { return NULL; } count = 1; memIdx = 0; head = free_page; mem = free_page; while (count < nbPage && (!memIdx || mem != free_page)) { 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 mem_desc *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(free_page, mem); mem->ref = 1; list_add_tail(used_page, mem); mem = next; next = mem->next; } allocatedPage += nbPage; return head->phy_addr; } int unrefPhyPage(paddr_t addr) { struct mem_desc *mem = addr2memDesc(addr); if (!mem) { return -1; } mem->ref--; if (mem->ref == 0) { allocatedPage--; list_delete(used_page, mem); list_add_tail(free_page, mem); // TODO find the right place to keep free_page sorted; } return mem->ref; } int refPhyPage(paddr_t addr) { struct mem_desc *mem = addr2memDesc(addr); if (!mem) { return -1; } mem->ref++; if (mem->ref == 1) { allocatedPage++; list_add_tail(used_page, mem); list_delete(free_page, mem); } return 0; } unsigned long getNbAllocatedPage(void) { return allocatedPage; }