matos/core/mem.c

145 lines
3.4 KiB
C

#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;
}